diff --git a/mapper.go b/mapper.go index be41bc4..8f7b4d6 100644 --- a/mapper.go +++ b/mapper.go @@ -3,8 +3,9 @@ package exql import ( "database/sql" "errors" - "fmt" "reflect" + + "golang.org/x/xerrors" ) // Error returned when record not found @@ -44,7 +45,7 @@ func NewSerialMapper(s ColumnSplitter) SerialMapper { return &serialMapper{splitter: s} } -var errMapDestination = fmt.Errorf("destination must be a pointer of struct") +var errMapDestination = xerrors.Errorf("destination must be a pointer of struct") // MapRow reads data from single row and maps those columns into destination struct. // pointerOfStruct MUST BE a pointer of struct. @@ -85,7 +86,7 @@ func MapRow(row *sql.Rows, pointerOfStruct interface{}) error { return ErrRecordNotFound } -var errMapManyDestination = fmt.Errorf("destination must be a pointer of slice of struct") +var errMapManyDestination = xerrors.Errorf("destination must be a pointer of slice of struct") // MapRows reads all data from rows and maps those columns for each destination struct. // pointerOfSliceOfStruct MUST BE a pointer of slice of pointer of struct. @@ -181,7 +182,7 @@ func aggregateFields(dest *reflect.Value) (map[string]int, error) { tag := f.Tag.Get("exql") if tag != "" { if f.Type.Kind() == reflect.Ptr { - return nil, fmt.Errorf("struct field must not be a pointer: %s %s", f.Type.Name(), f.Type.Kind()) + return nil, xerrors.Errorf("struct field must not be a pointer: %s %s", f.Type.Name(), f.Type.Kind()) } tags, err := ParseTags(tag) if err != nil { @@ -194,13 +195,13 @@ func aggregateFields(dest *reflect.Value) (map[string]int, error) { return fields, nil } -var errMapRowSerialDestination = fmt.Errorf("destination must be either *(struct) or *((*struct)(nil))") +var errMapRowSerialDestination = xerrors.Errorf("destination must be either *(struct) or *((*struct)(nil))") func (s *serialMapper) Map(rows *sql.Rows, dest ...interface{}) error { var values []*reflect.Value if len(dest) == 0 { - return fmt.Errorf("empty dest list") + return xerrors.Errorf("empty dest list") } for _, model := range dest { @@ -251,7 +252,7 @@ func mapRowSerial( headCol := cols[colIndex] expectedHeadCol := headColProvider(destIndex) if headCol.Name() != expectedHeadCol { - return fmt.Errorf( + return xerrors.Errorf( "head col mismatch: expected=%s, actual=%s", expectedHeadCol, headCol.Name(), ) diff --git a/parser.go b/parser.go index 3c56deb..bdb2d21 100644 --- a/parser.go +++ b/parser.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/iancoleman/strcase" + "golang.org/x/xerrors" ) type parser struct{} @@ -249,5 +250,5 @@ func ParseType(t string, nullable bool) (string, error) { } return jsonType, nil } - return "", fmt.Errorf("unknown type: %s", t) + return "", xerrors.Errorf("unknown type: %s", t) } diff --git a/query.go b/query.go index 4646934..3cc32be 100644 --- a/query.go +++ b/query.go @@ -2,10 +2,10 @@ package exql import ( "errors" - "fmt" "reflect" q "github.com/loilo-inc/exql/v2/query" + "golang.org/x/xerrors" ) func Where(str string, args ...any) q.Condition { @@ -57,12 +57,12 @@ func QueryForBulkInsert[T Model](modelPtrs ...T) (q.Query, error) { func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) { if modelPtr == nil { - return nil, fmt.Errorf("pointer is nil") + return nil, xerrors.Errorf("pointer is nil") } objValue := reflect.ValueOf(modelPtr) objType := objValue.Type() if objType.Kind() != reflect.Ptr || objType.Elem().Kind() != reflect.Struct { - return nil, fmt.Errorf("object must be pointer of struct") + return nil, xerrors.Errorf("object must be pointer of struct") } data := map[string]any{} // *User -> User @@ -80,7 +80,7 @@ func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) { } colName, ok := tags["column"] if !ok || colName == "" { - return nil, fmt.Errorf("column tag is not set") + return nil, xerrors.Errorf("column tag is not set") } exqlTagCount++ if _, primary := tags["primary"]; primary { @@ -98,16 +98,16 @@ func AggregateModelMetadata(modelPtr Model) (*ModelMetadata, error) { } } if exqlTagCount == 0 { - return nil, fmt.Errorf("obj doesn't have exql tags in any fields") + return nil, xerrors.Errorf("obj doesn't have exql tags in any fields") } if len(primaryKeyColumns) == 0 { - return nil, fmt.Errorf("table has no primary key") + return nil, xerrors.Errorf("table has no primary key") } tableName := modelPtr.TableName() if tableName == "" { - return nil, fmt.Errorf("empty table name") + return nil, xerrors.Errorf("empty table name") } return &ModelMetadata{ TableName: tableName, @@ -123,17 +123,17 @@ func QueryForUpdateModel( where q.Condition, ) (q.Query, error) { if updateStructPtr == nil { - return nil, fmt.Errorf("pointer is nil") + return nil, xerrors.Errorf("pointer is nil") } objValue := reflect.ValueOf(updateStructPtr) objType := objValue.Type() if objType.Kind() != reflect.Ptr || objType.Elem().Kind() != reflect.Struct { - return nil, fmt.Errorf("must be pointer of struct") + return nil, xerrors.Errorf("must be pointer of struct") } objType = objType.Elem() values := make(map[string]any) if objType.NumField() == 0 { - return nil, fmt.Errorf("struct has no field") + return nil, xerrors.Errorf("struct has no field") } for i := 0; i < objType.NumField(); i++ { @@ -146,12 +146,12 @@ func QueryForUpdateModel( if tags, err := ParseTags(tag); err != nil { return nil, err } else if col, ok := tags["column"]; !ok { - return nil, fmt.Errorf("tag must include column") + return nil, xerrors.Errorf("tag must include column") } else { colName = col } if f.Type.Kind() != reflect.Ptr { - return nil, fmt.Errorf("field must be pointer") + return nil, xerrors.Errorf("field must be pointer") } fieldValue := objValue.Elem().Field(i) if !fieldValue.IsNil() { @@ -159,12 +159,12 @@ func QueryForUpdateModel( } } if len(values) == 0 { - return nil, fmt.Errorf("no value for update") + return nil, xerrors.Errorf("no value for update") } tableName := updateStructPtr.UpdateTableName() if tableName == "" { - return nil, fmt.Errorf("empty table name") + return nil, xerrors.Errorf("empty table name") } b := q.NewBuilder() b.Sprintf("UPDATE `%s`", tableName) diff --git a/query/query.go b/query/query.go index 2539d90..05b146a 100644 --- a/query/query.go +++ b/query/query.go @@ -2,9 +2,10 @@ package query import ( - "fmt" "regexp" "strings" + + "golang.org/x/xerrors" ) type Query interface { @@ -37,7 +38,7 @@ func (f *query) Query() (sqlStmt string, sqlArgs []any, resErr error) { break } if argIdx == len(args) { - resErr = fmt.Errorf("missing argument at %d", argIdx) + resErr = xerrors.Errorf("missing argument at %d", argIdx) return } mStart := match[0] @@ -45,7 +46,7 @@ func (f *query) Query() (sqlStmt string, sqlArgs []any, resErr error) { if mEnd-mStart == 2 { // :? if q, ok := args[argIdx].(Query); !ok { - resErr = fmt.Errorf("unexpected argument type for :? placeholder at %d", argIdx) + resErr = xerrors.Errorf("unexpected argument type for :? placeholder at %d", argIdx) return } else if stmt, vals, err := q.Query(); err != nil { resErr = err @@ -65,7 +66,7 @@ func (f *query) Query() (sqlStmt string, sqlArgs []any, resErr error) { argIdx += 1 } if len(args) != argIdx { - resErr = fmt.Errorf("arguments count mismatch: found %d, got %d", argIdx, len(args)) + resErr = xerrors.Errorf("arguments count mismatch: found %d, got %d", argIdx, len(args)) return } if len(str) > 0 { @@ -187,7 +188,7 @@ func Q(q string, args ...any) Query { // Cols("users.*") // `users`.* func Cols(cols ...string) Query { if len(cols) == 0 { - return errQuery(fmt.Errorf("empty columns")) + return errQuery(xerrors.Errorf("empty columns")) } return &query{ query: QuoteColumns(cols...), @@ -219,7 +220,7 @@ func V(a ...any) Query { // Vals is another form of V that accepts a slice in generic type. func Vals[T any](vals []T) Query { if len(vals) == 0 { - return errQuery(fmt.Errorf("empty values")) + return errQuery(xerrors.Errorf("empty values")) } var args []any for _, v := range vals { @@ -242,7 +243,7 @@ func Vals[T any](vals []T) Query { // db.DB().Exec("update users set age = ?, name = ? where id = ?", 20, "go", 1) func Set(m map[string]any) Query { if len(m) == 0 { - return errQuery(fmt.Errorf("empty values for set clause")) + return errQuery(xerrors.Errorf("empty values for set clause")) } b := NewBuilder() it := NewKeyIterator(m) diff --git a/tag.go b/tag.go index 03a0799..c812417 100644 --- a/tag.go +++ b/tag.go @@ -1,8 +1,9 @@ package exql import ( - "fmt" "strings" + + "golang.org/x/xerrors" ) func ParseTags(tag string) (map[string]string, error) { @@ -13,7 +14,7 @@ func ParseTags(tag string) (map[string]string, error) { return nil } if _, ok := ret[k]; ok { - return fmt.Errorf("duplicated tag: %s", k) + return xerrors.Errorf("duplicated tag: %s", k) } ret[k] = v return nil @@ -29,11 +30,11 @@ func ParseTags(tag string) (map[string]string, error) { return nil, err } } else { - return nil, fmt.Errorf("invalid tag format") + return nil, xerrors.Errorf("invalid tag format") } } if len(ret) == 0 { - return nil, fmt.Errorf("invalid tag format") + return nil, xerrors.Errorf("invalid tag format") } return ret, nil } diff --git a/tx.go b/tx.go index ec4ae52..ce3dcbf 100644 --- a/tx.go +++ b/tx.go @@ -3,9 +3,9 @@ package exql import ( "context" "database/sql" - "fmt" "github.com/loilo-inc/exql/v2/query" + "golang.org/x/xerrors" ) type Tx interface { @@ -129,7 +129,7 @@ func Transaction(db *sql.DB, ctx context.Context, opts *sql.TxOptions, callback return callback(tx) }() if p != nil { - txErr = fmt.Errorf("recovered: %s", p) + txErr = xerrors.Errorf("recovered: %s", p) } if txErr != nil { if err := sqlTx.Rollback(); err != nil {