Compare commits

...

8 Commits

Author SHA1 Message Date
2f1b784dc2 v0.0.219 implement error.Is(*) for exerr 2023-07-28 15:42:12 +02:00
190584e0e6 v0.0.218 bf 2023-07-27 17:16:30 +02:00
b7003b9ec9 v0.0.217 2023-07-27 17:12:41 +02:00
4f871271e8 v0.0.216 2023-07-27 17:00:53 +02:00
91f4793678 v0.0.215 Add (ee *ExErr) ToAPIJson 2023-07-27 14:37:11 +02:00
3b30bb049e v0.0.214 reassign innerctx 2023-07-27 09:58:10 +02:00
f0c5b36ea9 v0.0.213 inject gin key value pairs into context 2023-07-27 09:46:06 +02:00
647ec64c3b v0.0.212 2023-07-26 10:44:26 +02:00
11 changed files with 112 additions and 39 deletions

View File

@@ -31,13 +31,13 @@ type EnumDef struct {
Values []EnumDefVal
}
var rexPackage = rext.W(regexp.MustCompile("^package\\s+(?P<name>[A-Za-z0-9_]+)\\s*$"))
var rexPackage = rext.W(regexp.MustCompile(`^package\s+(?P<name>[A-Za-z0-9_]+)\s*$`))
var rexEnumDef = rext.W(regexp.MustCompile("^\\s*type\\s+(?P<name>[A-Za-z0-9_]+)\\s+(?P<type>[A-Za-z0-9_]+)\\s*//\\s*(@enum:type).*$"))
var rexEnumDef = rext.W(regexp.MustCompile(`^\s*type\s+(?P<name>[A-Za-z0-9_]+)\s+(?P<type>[A-Za-z0-9_]+)\s*//\s*(@enum:type).*$`))
var rexValueDef = rext.W(regexp.MustCompile("^\\s*(?P<name>[A-Za-z0-9_]+)\\s+(?P<type>[A-Za-z0-9_]+)\\s*=\\s*(?P<value>(\"[A-Za-z0-9_:]+\"|[0-9]+))\\s*(//(?P<descr>.*))?.*$"))
var rexValueDef = rext.W(regexp.MustCompile(`^\s*(?P<name>[A-Za-z0-9_]+)\s+(?P<type>[A-Za-z0-9_]+)\s*=\s*(?P<value>("[A-Za-z0-9_:]+"|[0-9]+))\s*(//(?P<descr>.*))?.*$`))
var rexChecksumConst = rext.W(regexp.MustCompile("const ChecksumGenerator = \"(?P<cs>[A-Za-z0-9_]*)\""))
var rexChecksumConst = rext.W(regexp.MustCompile(`const ChecksumGenerator = "(?P<cs>[A-Za-z0-9_]*)"`))
func GenerateEnumSpecs(sourceDir string, destFile string) error {

View File

@@ -22,7 +22,7 @@ type ExErr struct {
WrappedErrType string `json:"wrappedErrType"`
Caller string `json:"caller"`
OriginalError *ExErr
OriginalError *ExErr `json:"originalError"`
Meta MetaMap `json:"meta"`
}
@@ -31,10 +31,16 @@ func (ee *ExErr) Error() string {
return ee.Message
}
// Unwrap must be implemented so that some error.XXX methods work
func (ee *ExErr) Unwrap() error {
return ee.OriginalError
}
// Is must be implemented so that error.Is(x) works
func (ee *ExErr) Is(e error) bool {
return IsFrom(ee, e)
}
func (ee *ExErr) Log(evt *zerolog.Event) {
evt.Msg(ee.FormatLog(LogPrintFull))
}

View File

@@ -3,12 +3,13 @@ package exerr
import (
"github.com/gin-gonic/gin"
json "gogs.mikescher.com/BlackForestBytes/goext/gojson"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/http"
"time"
)
func (ee *ExErr) toJson(depth int) gin.H {
ginJson := gin.H{}
func (ee *ExErr) toJson(depth int, applyExtendListener bool) langext.H {
ginJson := langext.H{}
if ee.UniqueID != "" {
ginJson["id"] = ee.UniqueID
@@ -38,21 +39,51 @@ func (ee *ExErr) toJson(depth int) gin.H {
ginJson["wrappedErrType"] = ee.WrappedErrType
}
if ee.OriginalError != nil {
ginJson["original"] = ee.OriginalError.toJson(depth + 1)
ginJson["original"] = ee.OriginalError.toJson(depth+1, applyExtendListener)
}
if applyExtendListener {
pkgconfig.ExtendGinDataOutput(ee, depth, ginJson)
}
return ginJson
}
// ToAPIJson converts the ExError to a json object
// (the same object as used in the Output(gin) method)
//
// Parameters:
// - [applyExtendListener]: if false the pkgconfig.ExtendGinOutput / pkgconfig.ExtendGinDataOutput will not be applied
// - [includeWrappedErrors]: if false we do not include the recursive/wrapped errors in `__data`
func (ee *ExErr) ToAPIJson(applyExtendListener bool, includeWrappedErrors bool) langext.H {
apiOutput := langext.H{
"errorid": ee.UniqueID,
"message": ee.RecursiveMessage(),
"errorcode": ee.RecursiveType().Key,
"category": ee.RecursiveCategory().Category,
}
if includeWrappedErrors {
apiOutput["__data"] = ee.toJson(0, applyExtendListener)
}
if applyExtendListener {
pkgconfig.ExtendGinOutput(ee, apiOutput)
}
return apiOutput
}
func (ee *ExErr) Output(g *gin.Context) {
warnOnPkgConfigNotInitialized()
var statuscode = http.StatusInternalServerError
var baseCat = ee.RecursiveCategory()
var baseType = ee.RecursiveType()
var baseStatuscode = ee.RecursiveStatuscode()
var baseMessage = ee.RecursiveMessage()
if baseCat == CatUser {
statuscode = http.StatusBadRequest
@@ -66,20 +97,7 @@ func (ee *ExErr) Output(g *gin.Context) {
statuscode = *baseType.DefaultStatusCode
}
warnOnPkgConfigNotInitialized()
ginOutput := gin.H{
"errorid": ee.UniqueID,
"message": baseMessage,
"errorcode": baseType.Key,
"category": baseCat.Category,
}
if pkgconfig.ExtendedGinOutput {
ginOutput["__data"] = ee.toJson(0)
}
pkgconfig.ExtendGinOutput(ee, ginOutput)
ginOutput := ee.ToAPIJson(true, pkgconfig.ExtendedGinOutput)
g.Render(statuscode, json.GoJsonRender{Data: ginOutput, NilSafeSlices: true, NilSafeMaps: true})
}

View File

@@ -24,6 +24,8 @@ func IsFrom(e error, original error) bool {
if e == nil {
return false
}
//goland:noinspection GoDirectComparisonOfErrors
if e == original {
return true
}

View File

@@ -14,6 +14,9 @@ type AppContext struct {
}
func CreateAppContext(g *gin.Context, innerCtx context.Context, cancelFn context.CancelFunc) *AppContext {
for key, value := range g.Keys {
innerCtx = context.WithValue(innerCtx, key, value)
}
return &AppContext{
inner: innerCtx,
cancelFunc: cancelFn,
@@ -38,6 +41,10 @@ func (ac *AppContext) Value(key any) any {
return ac.inner.Value(key)
}
func (ac *AppContext) Set(key, value any) {
ac.inner = context.WithValue(ac.inner, key, value)
}
func (ac *AppContext) Cancel() {
ac.cancelled = true
ac.cancelFunc()

View File

@@ -162,7 +162,7 @@ func nameOfFunction(f any) string {
fname = fname[:len(fname)-len("-fm")]
}
suffix := rext.W(regexp.MustCompile("\\.func[0-9]+$"))
suffix := rext.W(regexp.MustCompile(`\.func[0-9]+(?:\.[0-9]+)*$`))
if match, ok := suffix.MatchFirst(fname); ok {
fname = fname[:len(fname)-match.FullMatch().Length()]

View File

@@ -1,5 +1,5 @@
package goext
const GoextVersion = "0.0.211"
const GoextVersion = "0.0.219"
const GoextVersionTimestamp = "2023-07-26T10:40:42+0200"
const GoextVersionTimestamp = "2023-07-28T15:42:12+0200"

View File

@@ -8,7 +8,7 @@ import (
func TestGroupByNameOrEmpty1(t *testing.T) {
regex1 := W(regexp.MustCompile("0(?P<group1>A+)B(?P<group2>C+)0"))
regex1 := W(regexp.MustCompile(`0(?P<group1>A+)B(?P<group2>C+)0`))
match1, ok1 := regex1.MatchFirst("Hello 0AAAABCCC0 Bye.")
@@ -26,7 +26,7 @@ func TestGroupByNameOrEmpty1(t *testing.T) {
func TestGroupByNameOrEmpty2(t *testing.T) {
regex1 := W(regexp.MustCompile("0(?P<group1>A+)B(?P<group2>C+)(?P<group3>C+)?0"))
regex1 := W(regexp.MustCompile(`0(?P<group1>A+)B(?P<group2>C+)(?P<group3>C+)?0`))
match1, ok1 := regex1.MatchFirst("Hello 0AAAABCCC0 Bye.")

View File

@@ -39,7 +39,7 @@ func HashSqliteSchema(ctx context.Context, schemaStr string) (string, error) {
return HashSqliteDatabase(ctx, db)
}
func HashSqliteDatabase(ctx context.Context, db DB) (string, error) {
func HashSqliteDatabase(ctx context.Context, db Queryable) (string, error) {
ss, err := CreateSqliteDatabaseSchemaString(ctx, db)
if err != nil {
return "", err
@@ -50,7 +50,7 @@ func HashSqliteDatabase(ctx context.Context, db DB) (string, error) {
return hex.EncodeToString(cs[:]), nil
}
func CreateSqliteDatabaseSchemaString(ctx context.Context, db DB) (string, error) {
func CreateSqliteDatabaseSchemaString(ctx context.Context, db Queryable) (string, error) {
type colInfo struct {
Name string `db:"name"`

View File

@@ -7,9 +7,19 @@ import (
"gogs.mikescher.com/BlackForestBytes/goext/langext"
)
type TxStatus string
const (
TxStatusInitial TxStatus = "INITIAL"
TxStatusActive TxStatus = "ACTIVE"
TxStatusComitted TxStatus = "COMMITTED"
TxStatusRollback TxStatus = "ROLLBACK"
)
type Tx interface {
Rollback() error
Commit() error
Status() TxStatus
Exec(ctx context.Context, sql string, prep PP) (sql.Result, error)
Query(ctx context.Context, sql string, prep PP) (*sqlx.Rows, error)
}
@@ -18,6 +28,9 @@ type transaction struct {
tx *sqlx.Tx
id uint16
lstr []Listener
status TxStatus
execCtr int
queryCtr int
}
func NewTransaction(xtx *sqlx.Tx, txid uint16, lstr []Listener) Tx {
@@ -25,6 +38,9 @@ func NewTransaction(xtx *sqlx.Tx, txid uint16, lstr []Listener) Tx {
tx: xtx,
id: txid,
lstr: lstr,
status: TxStatusInitial,
execCtr: 0,
queryCtr: 0,
}
}
@@ -38,6 +54,10 @@ func (tx *transaction) Rollback() error {
result := tx.tx.Rollback()
if result == nil {
tx.status = TxStatusRollback
}
for _, v := range tx.lstr {
v.PostTxRollback(tx.id, result)
}
@@ -55,6 +75,10 @@ func (tx *transaction) Commit() error {
result := tx.tx.Commit()
if result == nil {
tx.status = TxStatusComitted
}
for _, v := range tx.lstr {
v.PostTxRollback(tx.id, result)
}
@@ -73,6 +97,10 @@ func (tx *transaction) Exec(ctx context.Context, sqlstr string, prep PP) (sql.Re
res, err := tx.tx.NamedExecContext(ctx, sqlstr, prep)
if tx.status == TxStatusInitial && err == nil {
tx.status = TxStatusActive
}
for _, v := range tx.lstr {
v.PostExec(langext.Ptr(tx.id), origsql, sqlstr, prep)
}
@@ -94,6 +122,10 @@ func (tx *transaction) Query(ctx context.Context, sqlstr string, prep PP) (*sqlx
rows, err := sqlx.NamedQueryContext(ctx, tx.tx, sqlstr, prep)
if tx.status == TxStatusInitial && err == nil {
tx.status = TxStatusActive
}
for _, v := range tx.lstr {
v.PostQuery(langext.Ptr(tx.id), origsql, sqlstr, prep)
}
@@ -103,3 +135,11 @@ func (tx *transaction) Query(ctx context.Context, sqlstr string, prep PP) (*sqlx
}
return rows, nil
}
func (tx *transaction) Status() TxStatus {
return tx.status
}
func (tx *transaction) Traffic() (int, int) {
return tx.execCtr, tx.queryCtr
}

View File

@@ -71,12 +71,12 @@ func SupportsColors() bool {
}
}
var term256Regex = regexp.MustCompile("(?i)-256(color)?$")
var term256Regex = regexp.MustCompile(`(?i)-256(color)?$`)
if term256Regex.MatchString(termenv) {
return true
}
var termBasicRegex = regexp.MustCompile("(?i)^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux")
var termBasicRegex = regexp.MustCompile(`(?i)^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux`)
if termBasicRegex.MatchString(termenv) {
return true