{"id":15111473,"url":"https://github.com/kanmu/dgw","last_synced_at":"2026-01-19T05:00:41.408Z","repository":{"id":10239693,"uuid":"60824623","full_name":"kanmu/dgw","owner":"kanmu","description":"dgw generates Golang struct, and simple Table/Row Data Gateway functions from PostgreSQL table metadata","archived":false,"fork":false,"pushed_at":"2026-01-15T05:09:23.000Z","size":125,"stargazers_count":191,"open_issues_count":2,"forks_count":33,"subscribers_count":24,"default_branch":"master","last_synced_at":"2026-01-15T11:54:09.726Z","etag":null,"topics":["db","generator","go","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kanmu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-06-10T04:45:56.000Z","updated_at":"2026-01-15T05:08:05.000Z","dependencies_parsed_at":"2024-12-28T02:11:50.107Z","dependency_job_id":"e903f02a-2fe5-4013-9197-af7eb027038b","html_url":"https://github.com/kanmu/dgw","commit_stats":{"total_commits":71,"total_committers":10,"mean_commits":7.1,"dds":"0.21126760563380287","last_synced_commit":"b4af6809857036edc5c08357a246ae6b3afdb9ab"},"previous_names":["achiku/dgw"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/kanmu/dgw","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanmu%2Fdgw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanmu%2Fdgw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanmu%2Fdgw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanmu%2Fdgw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kanmu","download_url":"https://codeload.github.com/kanmu/dgw/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanmu%2Fdgw/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28479409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["db","generator","go","postgresql","sql"],"created_at":"2024-09-26T00:20:24.135Z","updated_at":"2026-01-19T05:00:41.401Z","avatar_url":"https://github.com/kanmu.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dgw\n\n[![test](https://github.com/kanmu/dgw/actions/workflows/test.yml/badge.svg)](https://github.com/kanmu/dgw/actions/workflows/test.yml)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/kanmu/dgw/master/LICENSE)\n[![Go Report Card](https://goreportcard.com/badge/github.com/kanmu/dgw)](https://goreportcard.com/report/github.com/kanmu/dgw)\n\n## Description\n\n`dgw` generates Golang struct, and simple Table/Row Data Gateway functions from PostgreSQL table metadata. Heavily inspired by [xo](https://github.com/knq/xo).\n\n## Why created\n\nPersonally, 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.\n\n- `dgw` can properly detect autogenerated column (e.g. serial, bigserial), and composit primary key to create appropriate SQL.\n- `dgw` has ability to easily customize PostgreSQL column type \u003c-\u003e Go type mapping using toml config file.\n\n## Installation\n\n```\nbrew install kanmu/tools/dgw\n```\n\n## How to use\n\n```\nusage: dgw [\u003cflags\u003e] \u003cconn\u003e\n\nFlags:\n      --help                 Show context-sensitive help (also try --help-long and --help-man).\n  -s, --schema=\"public\"      PostgreSQL schema name\n  -p, --package=\"main\"       package name\n  -t, --typemap=TYPEMAP      column type and go type map file path\n  -k, --autogenkey=AUTOGENKEY ...\n                             auto generate key list\n  -x, --exclude=EXCLUDE ...  table names to exclude\n      --template=TEMPLATE    custom template path\n  -o, --output=OUTPUT        output file path\n      --no-interface         output without Queryer interface\n      --deprecated=DEPRECATED ...\n                             deprecated table names\n      --queryer=QUERYER      Queryer type name\n      --version              Show application version.\n\nArgs:\n  \u003cconn\u003e  PostgreSQL connection string in URL format\n```\n\n```\ndgw postgres://dbuser@localhost/dbname?sslmode=disable\n```\n\n## Example\n\n- https://github.com/kanmu/dgw/tree/master/example\n\n```sql\nCREATE TABLE t1 (\n  id bigserial primary key\n  , i integer not null unique\n  , str text not null\n  , num_float numeric not null\n  , nullable_str text\n  , t_with_tz timestamp without time zone not null\n  , t_without_tz timestamp with time zone not null\n  , nullable_tz timestamp with time zone\n  , json_data json not null\n  , xml_data xml not null\n);\n\nCREATE TABLE t2 (\n  id bigserial not null\n  , i integer not null\n  , str text not null\n  , t_with_tz timestamp without time zone not null\n  , t_without_tz timestamp with time zone not null\n  , PRIMARY KEY(id, i)\n);\n\nCREATE TABLE t3 (\n  id integer not null\n  , i integer not null\n  , PRIMARY KEY(id, i)\n);\n```\n\nGenerate Go code by the following command.\n\n```\n$ dgw postgres://dgw_test@localhost/dgw_test?sslmode=disable --typemap=./typemap.toml --schema=public --package=dgwexample --output=example.go\n```\n\n```go\n// T1 represents public.t1\ntype T1 struct {\n\tID          int64          // id\n\tI           int            // i\n\tStr         string         // str\n\tNumFloat    float64        // num_float\n\tNullableStr sql.NullString // nullable_str\n\tTWithTz     time.Time      // t_with_tz\n\tTWithoutTz  time.Time      // t_without_tz\n\tNullableTz  *time.Time     // nullable_tz\n\tJSONData    []byte         // json_data\n\tXMLData     []byte         // xml_data\n}\n\n// Create inserts the T1 to the database.\nfunc (r *T1) Create(db Queryer) error {\n\terr := db.QueryRow(\n\t\t`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`,\n\t\t\u0026r.I, \u0026r.Str, \u0026r.NumFloat, \u0026r.NullableStr, \u0026r.TWithTz, \u0026r.TWithoutTz, \u0026r.NullableTz, \u0026r.JSONData, \u0026r.XMLData).Scan(\u0026r.ID)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\treturn nil\n}\n\n// GetT1ByPk select the T1 from the database.\nfunc GetT1ByPk(db Queryer, pk0 int64) (*T1, error) {\n\tvar r T1\n\terr := db.QueryRow(\n\t\t`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`,\n\t\tpk0).Scan(\u0026r.ID, \u0026r.I, \u0026r.Str, \u0026r.NumFloat, \u0026r.NullableStr, \u0026r.TWithTz, \u0026r.TWithoutTz, \u0026r.NullableTz, \u0026r.JSONData, \u0026r.XMLData)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\treturn \u0026r, nil\n}\n\n// T2 represents public.t2\ntype T2 struct {\n\tID         int64     // id\n\tI          int       // i\n\tStr        string    // str\n\tTWithTz    time.Time // t_with_tz\n\tTWithoutTz time.Time // t_without_tz\n}\n\n// Create inserts the T2 to the database.\nfunc (r *T2) Create(db Queryer) error {\n\terr := db.QueryRow(\n\t\t`INSERT INTO t2 (str, t_with_tz, t_without_tz) VALUES ($1, $2, $3) RETURNING id, i`,\n\t\t\u0026r.Str, \u0026r.TWithTz, \u0026r.TWithoutTz).Scan(\u0026r.ID, \u0026r.I)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\treturn nil\n}\n\n// GetT2ByPk select the T2 from the database.\nfunc GetT2ByPk(db Queryer, pk0 int64, pk1 int) (*T2, error) {\n\tvar r T2\n\terr := db.QueryRow(\n\t\t`SELECT id, i, str, t_with_tz, t_without_tz FROM t2 WHERE id = $1 AND i = $2`,\n\t\tpk0, pk1).Scan(\u0026r.ID, \u0026r.I, \u0026r.Str, \u0026r.TWithTz, \u0026r.TWithoutTz)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\treturn \u0026r, nil\n}\n\n// T3 represents public.t3\ntype T3 struct {\n\tID int // id\n\tI  int // i\n}\n\n// Create inserts the T3 to the database.\nfunc (r *T3) Create(db Queryer) error {\n\t_, err := db.Exec(\n\t\t`INSERT INTO t3 (id, i) VALUES ($1, $2)`,\n\t\t\u0026r.ID, \u0026r.I)\n\tif err != nil {\n\t\treturn errors.WithStack(err)\n\t}\n\treturn nil\n}\n\n// GetT3ByPk select the T3 from the database.\nfunc GetT3ByPk(db Queryer, pk0 int, pk1 int) (*T3, error) {\n\tvar r T3\n\terr := db.QueryRow(\n\t\t`SELECT id, i FROM t3 WHERE id = $1 AND i = $2`,\n\t\tpk0, pk1).Scan(\u0026r.ID, \u0026r.I)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n\treturn \u0026r, nil\n}\n```\n\n## Test\n\n### Using Docker (Recommended)\n\n```bash\n# Start PostgreSQL 16 with pre-configured test database and user\n$ docker compose up -d\n\n# Wait for PostgreSQL to be ready\n$ docker compose exec postgres pg_isready -U dgw_test\n\n# Run tests\n$ go test -v\n\n# Stop PostgreSQL when done\n$ docker compose down\n```\n\n### Manual Setup\n\n```bash\n$ psql -d template1\n\u003e CREATE USER dgw_test;\n\u003e CREATE DATABASE  dgw_test OWNER dgw_test;\n\u003e \\q\n$ go test -v\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanmu%2Fdgw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkanmu%2Fdgw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanmu%2Fdgw/lists"}