diff --git a/README.md b/README.md index afb61de..5b7d782 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ `dgw` generates Golang struct, and simple Table/Row Data Gateway functions from PostgreSQL table metadata. Heavily inspired by [xo](https://github.com/knq/xo). - ## Why created Personally, I prefer Table/Row Data Gateway over ORM/Query Builder approach when using Go with RDBMS. However, it is very time consuming, tedious, and error-prone to write a lot of columns, query place holders, and struct fields that all have to be exactly in order even for a simple select/insert statement. `dgw` generate Go struct, and simple functions to get/create row from PostgreSQL table definitions to avoid manually writing simple but tedious SQL. @@ -16,14 +15,12 @@ Personally, I prefer Table/Row Data Gateway over ORM/Query Builder approach when - `dgw` can properly detect autogenerated column (e.g. serial, bigserial), and composit primary key to create appropriate SQL. - `dgw` has ability to easily customize PostgreSQL column type <-> Go type mapping using toml config file. - ## Installation ``` brew install kanmu/tools/dgw ``` - ## How to use ``` @@ -108,7 +105,7 @@ func (r *T1) Create(db Queryer) error { `INSERT INTO t1 (i, str, num_float, nullable_str, t_with_tz, t_without_tz, nullable_tz, json_data, xml_data) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id`, &r.I, &r.Str, &r.NumFloat, &r.NullableStr, &r.TWithTz, &r.TWithoutTz, &r.NullableTz, &r.JSONData, &r.XMLData).Scan(&r.ID) if err != nil { - return errors.Wrap(err, "failed to insert t1") + return errors.WithStack(err) } return nil } @@ -120,7 +117,7 @@ func GetT1ByPk(db Queryer, pk0 int64) (*T1, error) { `SELECT id, i, str, num_float, nullable_str, t_with_tz, t_without_tz, nullable_tz, json_data, xml_data FROM t1 WHERE id = $1`, pk0).Scan(&r.ID, &r.I, &r.Str, &r.NumFloat, &r.NullableStr, &r.TWithTz, &r.TWithoutTz, &r.NullableTz, &r.JSONData, &r.XMLData) if err != nil { - return nil, errors.Wrap(err, "failed to select t1") + return nil, errors.WithStack(err) } return &r, nil } @@ -140,7 +137,7 @@ func (r *T2) Create(db Queryer) error { `INSERT INTO t2 (str, t_with_tz, t_without_tz) VALUES ($1, $2, $3) RETURNING id, i`, &r.Str, &r.TWithTz, &r.TWithoutTz).Scan(&r.ID, &r.I) if err != nil { - return errors.Wrap(err, "failed to insert t2") + return errors.WithStack(err) } return nil } @@ -152,7 +149,7 @@ func GetT2ByPk(db Queryer, pk0 int64, pk1 int) (*T2, error) { `SELECT id, i, str, t_with_tz, t_without_tz FROM t2 WHERE id = $1 AND i = $2`, pk0, pk1).Scan(&r.ID, &r.I, &r.Str, &r.TWithTz, &r.TWithoutTz) if err != nil { - return nil, errors.Wrap(err, "failed to select t2") + return nil, errors.WithStack(err) } return &r, nil } @@ -169,7 +166,7 @@ func (r *T3) Create(db Queryer) error { `INSERT INTO t3 (id, i) VALUES ($1, $2)`, &r.ID, &r.I) if err != nil { - return errors.Wrap(err, "failed to insert t3") + return errors.WithStack(err) } return nil } @@ -181,7 +178,7 @@ func GetT3ByPk(db Queryer, pk0 int, pk1 int) (*T3, error) { `SELECT id, i FROM t3 WHERE id = $1 AND i = $2`, pk0, pk1).Scan(&r.ID, &r.I) if err != nil { - return nil, errors.Wrap(err, "failed to select t3") + return nil, errors.WithStack(err) } return &r, nil } diff --git a/dgw.go b/dgw.go index 22a5c40..07ee8fa 100644 --- a/dgw.go +++ b/dgw.go @@ -32,7 +32,7 @@ type Queryer interface { func OpenDB(connStr string) (*sql.DB, error) { conn, err := sql.Open("postgres", connStr) if err != nil { - return nil, errors.Wrap(err, "failed to connect to database") + return nil, errors.WithStack(err) } return conn, nil } @@ -180,7 +180,7 @@ type StructField struct { func PgLoadTypeMapFromFile(filePath string) (*PgTypeMapConfig, error) { var conf PgTypeMapConfig if _, err := toml.DecodeFile(filePath, &conf); err != nil { - return nil, errors.Wrap(err, "faild to parse config file") + return nil, errors.WithStack(err) } return &conf, nil } @@ -189,7 +189,7 @@ func PgLoadTypeMapFromFile(filePath string) (*PgTypeMapConfig, error) { func PgLoadColumnDef(db Queryer, schema string, table string) ([]*PgColumn, error) { colDefs, err := db.Query(pgLoadColumnDef, schema, table) if err != nil { - return nil, errors.Wrap(err, "failed to load table def") + return nil, errors.WithStack(err) } cols := []*PgColumn{} @@ -205,7 +205,7 @@ func PgLoadColumnDef(db Queryer, schema string, table string) ([]*PgColumn, erro &c.DDLType, ) if err != nil { - return nil, errors.Wrap(err, "failed to scan") + return nil, errors.WithStack(err) } // Some data types have an extra part e.g, "character varying(16)" and @@ -223,7 +223,7 @@ func PgLoadColumnDef(db Queryer, schema string, table string) ([]*PgColumn, erro func PgLoadTableDef(db Queryer, schema string) ([]*PgTable, error) { tbDefs, err := db.Query(pgLoadTableDef, schema) if err != nil { - return nil, errors.Wrap(err, "failed to load table def") + return nil, errors.WithStack(err) } tbs := []*PgTable{} for tbDefs.Next() { @@ -233,7 +233,7 @@ func PgLoadTableDef(db Queryer, schema string) ([]*PgTable, error) { &t.Name, ) if err != nil { - return nil, errors.Wrap(err, "failed to scan") + return nil, errors.WithStack(err) } cols, err := PgLoadColumnDef(db, schema, t.Name) if err != nil { @@ -291,7 +291,7 @@ func PgTableToStruct(t *PgTable, typeCfg *PgTypeMapConfig, keyConfig *AutoKeyMap for _, c := range t.Columns { f, err := PgColToField(c, typeCfg) if err != nil { - return nil, errors.Wrap(err, "faield to convert col to field") + return nil, errors.WithStack(err) } fs = append(fs, f) } @@ -304,11 +304,11 @@ func PgExecuteDefaultTmpl(st *StructTmpl, path string) ([]byte, error) { var src []byte d, err := Asset(path) if err != nil { - return src, errors.Wrap(err, "failed to load asset") + return src, errors.WithStack(err) } tpl, err := template.New("struct").Funcs(tmplFuncMap).Parse(string(d)) if err != nil { - return src, errors.Wrap(err, "failed to parse template") + return src, errors.WithStack(err) } buf := new(bytes.Buffer) if err := tpl.Execute(buf, st); err != nil { @@ -326,7 +326,7 @@ func PgExecuteCustomTmpl(st *StructTmpl, customTmpl string) ([]byte, error) { var src []byte tpl, err := template.New("struct").Funcs(tmplFuncMap).Parse(customTmpl) if err != nil { - return src, errors.Wrap(err, "failed to parse template") + return src, errors.WithStack(err) } buf := new(bytes.Buffer) if err := tpl.Execute(buf, st); err != nil { @@ -348,12 +348,12 @@ func PgCreateStruct( tbls, err := PgLoadTableDef(db, schema) if err != nil { - return src, errors.Wrap(err, "faield to load table definitions") + return src, errors.WithStack(err) } cfg := &PgTypeMapConfig{} if typeMapPath == "" { if _, err := toml.Decode(typeMap, cfg); err != nil { - return src, errors.Wrap(err, "faield to read type map") + return src, errors.WithStack(err) } } else { if _, err := toml.DecodeFile(typeMapPath, cfg); err != nil { @@ -366,7 +366,7 @@ func PgCreateStruct( } st, err := PgTableToStruct(tbl, cfg, autoGenKeyCfg) if err != nil { - return src, errors.Wrap(err, "faield to convert table definition to struct") + return src, errors.WithStack(err) } if customTmpl != "" { tmpl, err := ioutil.ReadFile(customTmpl) @@ -375,17 +375,17 @@ func PgCreateStruct( } s, err := PgExecuteCustomTmpl(&StructTmpl{Struct: st}, string(tmpl)) if err != nil { - return nil, errors.Wrap(err, "PgExecuteCustomTmpl failed") + return nil, errors.WithStack(err) } src = append(src, s...) } else { s, err := PgExecuteDefaultTmpl(&StructTmpl{Struct: st}, "template/struct.tmpl") if err != nil { - return src, errors.Wrap(err, "faield to execute template") + return src, errors.WithStack(err) } m, err := PgExecuteDefaultTmpl(&StructTmpl{Struct: st}, "template/method.tmpl") if err != nil { - return src, errors.Wrap(err, "faield to execute template") + return src, errors.WithStack(err) } src = append(src, s...) src = append(src, m...) diff --git a/example/conn.go b/example/conn.go index c361e5d..436cdaf 100644 --- a/example/conn.go +++ b/example/conn.go @@ -11,7 +11,7 @@ import ( func OpenDB(connStr string) (*sql.DB, error) { conn, err := sql.Open("postgres", connStr) if err != nil { - return nil, errors.Wrap(err, "failed to connect to database") + return nil, errors.WithStack(err) } return conn, nil } diff --git a/example/defaultstruct.go b/example/defaultstruct.go index af70526..d380097 100644 --- a/example/defaultstruct.go +++ b/example/defaultstruct.go @@ -27,7 +27,7 @@ func (r *T1) Create(db Queryer) error { `INSERT INTO t1 (i, str, num_float, nullable_str, t_with_tz, t_without_tz, nullable_tz, json_data, xml_data) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id`, &r.I, &r.Str, &r.NumFloat, &r.NullableStr, &r.TWithTz, &r.TWithoutTz, &r.NullableTz, &r.JSONData, &r.XMLData).Scan(&r.ID) if err != nil { - return errors.Wrap(err, "failed to insert t1") + return errors.WithStack(err) } return nil } @@ -39,7 +39,7 @@ func GetT1ByPk(db Queryer, pk0 int64) (*T1, error) { `SELECT id, i, str, num_float, nullable_str, t_with_tz, t_without_tz, nullable_tz, json_data, xml_data FROM t1 WHERE id = $1`, pk0).Scan(&r.ID, &r.I, &r.Str, &r.NumFloat, &r.NullableStr, &r.TWithTz, &r.TWithoutTz, &r.NullableTz, &r.JSONData, &r.XMLData) if err != nil { - return nil, errors.Wrap(err, "failed to select t1") + return nil, errors.WithStack(err) } return &r, nil } @@ -59,7 +59,7 @@ func (r *T2) Create(db Queryer) error { `INSERT INTO t2 (str, t_with_tz, t_without_tz) VALUES ($1, $2, $3) RETURNING id, i`, &r.Str, &r.TWithTz, &r.TWithoutTz).Scan(&r.ID, &r.I) if err != nil { - return errors.Wrap(err, "failed to insert t2") + return errors.WithStack(err) } return nil } @@ -71,7 +71,7 @@ func GetT2ByPk(db Queryer, pk0 int64, pk1 int) (*T2, error) { `SELECT id, i, str, t_with_tz, t_without_tz FROM t2 WHERE id = $1 AND i = $2`, pk0, pk1).Scan(&r.ID, &r.I, &r.Str, &r.TWithTz, &r.TWithoutTz) if err != nil { - return nil, errors.Wrap(err, "failed to select t2") + return nil, errors.WithStack(err) } return &r, nil } @@ -88,7 +88,7 @@ func (r *T3) Create(db Queryer) error { `INSERT INTO t3 (id, i) VALUES ($1, $2)`, &r.ID, &r.I) if err != nil { - return errors.Wrap(err, "failed to insert t3") + return errors.WithStack(err) } return nil } @@ -100,7 +100,7 @@ func GetT3ByPk(db Queryer, pk0 int, pk1 int) (*T3, error) { `SELECT id, i FROM t3 WHERE id = $1 AND i = $2`, pk0, pk1).Scan(&r.ID, &r.I) if err != nil { - return nil, errors.Wrap(err, "failed to select t3") + return nil, errors.WithStack(err) } return &r, nil } @@ -117,7 +117,7 @@ func (r *T4) Create(db Queryer) error { `INSERT INTO t4 (id, i) VALUES ($1, $2)`, &r.ID, &r.I) if err != nil { - return errors.Wrap(err, "failed to insert t4") + return errors.WithStack(err) } return nil } @@ -129,7 +129,7 @@ func GetT4ByPk(db Queryer, pk0 int, pk1 int) (*T4, error) { `SELECT id, i FROM t4 WHERE id = $1 AND i = $2`, pk0, pk1).Scan(&r.ID, &r.I) if err != nil { - return nil, errors.Wrap(err, "failed to select t4") + return nil, errors.WithStack(err) } return &r, nil } @@ -148,7 +148,7 @@ func (r *UserAccount) Create(db Queryer) error { `INSERT INTO user_account (email, last_name, first_name) VALUES ($1, $2, $3) RETURNING id`, &r.Email, &r.LastName, &r.FirstName).Scan(&r.ID) if err != nil { - return errors.Wrap(err, "failed to insert user_account") + return errors.WithStack(err) } return nil } @@ -160,7 +160,7 @@ func GetUserAccountByPk(db Queryer, pk0 int64) (*UserAccount, error) { `SELECT id, email, last_name, first_name FROM user_account WHERE id = $1`, pk0).Scan(&r.ID, &r.Email, &r.LastName, &r.FirstName) if err != nil { - return nil, errors.Wrap(err, "failed to select user_account") + return nil, errors.WithStack(err) } return &r, nil } @@ -179,7 +179,7 @@ func (r *UserAccountCompositePk) Create(db Queryer) error { `INSERT INTO user_account_composite_pk (id, email, last_name, first_name) VALUES ($1, $2, $3, $4)`, &r.ID, &r.Email, &r.LastName, &r.FirstName) if err != nil { - return errors.Wrap(err, "failed to insert user_account_composite_pk") + return errors.WithStack(err) } return nil } @@ -191,7 +191,7 @@ func GetUserAccountCompositePkByPk(db Queryer, pk0 int64, pk1 string) (*UserAcco `SELECT id, email, last_name, first_name FROM user_account_composite_pk WHERE id = $1 AND email = $2`, pk0, pk1).Scan(&r.ID, &r.Email, &r.LastName, &r.FirstName) if err != nil { - return nil, errors.Wrap(err, "failed to select user_account_composite_pk") + return nil, errors.WithStack(err) } return &r, nil } @@ -210,7 +210,7 @@ func (r *UserAccountUUID) Create(db Queryer) error { `INSERT INTO user_account_uuid (email, last_name, first_name) VALUES ($1, $2, $3) RETURNING uuid`, &r.Email, &r.LastName, &r.FirstName).Scan(&r.UUID) if err != nil { - return errors.Wrap(err, "failed to insert user_account_uuid") + return errors.WithStack(err) } return nil } @@ -222,7 +222,7 @@ func GetUserAccountUUIDByPk(db Queryer, pk0 string) (*UserAccountUUID, error) { `SELECT uuid, email, last_name, first_name FROM user_account_uuid WHERE uuid = $1`, pk0).Scan(&r.UUID, &r.Email, &r.LastName, &r.FirstName) if err != nil { - return nil, errors.Wrap(err, "failed to select user_account_uuid") + return nil, errors.WithStack(err) } return &r, nil } diff --git a/template/method.tmpl b/template/method.tmpl index 5aefd2a..8c2e98a 100644 --- a/template/method.tmpl +++ b/template/method.tmpl @@ -20,7 +20,7 @@ func (r *{{ .Struct.Name }}) CreateContext(ctx context.Context, db Queryer) erro {{ createInsertParams .Struct }}) {{- end }} if err != nil { - return errors.Wrap(err, "failed to insert {{ .Struct.Table.Name }}") + return errors.WithStack(err) } return nil } @@ -32,7 +32,7 @@ func Get{{ .Struct.Name }}ByPkContext(ctx context.Context, db Queryer, {{ create `{{ createSelectByPkSQL .Struct }}`, {{ createSelectByPkSQLParams .Struct }}).Scan({{ createSelectByPkScan .Struct }}) if err != nil { - return nil, errors.Wrap(err, "failed to select {{ .Struct.Table.Name }}") + return nil, errors.WithStack(err) } return &r, nil }