{"id":25549503,"url":"https://github.com/khoa-bit/go-db-tools","last_synced_at":"2026-05-08T09:32:33.255Z","repository":{"id":278428286,"uuid":"935585828","full_name":"Khoa-bit/go-db-tools","owner":"Khoa-bit","description":"My personal tools for working with DB. Because I love zero dependency \u003c3","archived":false,"fork":false,"pushed_at":"2025-02-19T17:42:41.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-30T17:36:36.955Z","etag":null,"topics":["db","go","sql","sqlite"],"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/Khoa-bit.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}},"created_at":"2025-02-19T17:25:42.000Z","updated_at":"2025-02-19T17:44:11.000Z","dependencies_parsed_at":"2025-02-19T18:47:52.398Z","dependency_job_id":null,"html_url":"https://github.com/Khoa-bit/go-db-tools","commit_stats":null,"previous_names":["khoa-bit/go-db-tools"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Khoa-bit/go-db-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Khoa-bit%2Fgo-db-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Khoa-bit%2Fgo-db-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Khoa-bit%2Fgo-db-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Khoa-bit%2Fgo-db-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Khoa-bit","download_url":"https://codeload.github.com/Khoa-bit/go-db-tools/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Khoa-bit%2Fgo-db-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274557583,"owners_count":25307516,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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","go","sql","sqlite"],"created_at":"2025-02-20T10:18:26.064Z","updated_at":"2026-05-08T09:32:33.210Z","avatar_url":"https://github.com/Khoa-bit.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# go-db-tools\n\nThis is my personal tools for working with DB instances.\nBecause **I love zero dependency \u003c3**\n\n## build nested model\n\n### Models struct:\n\n```go\ntype Layer0 struct {\n\tID      int64\n\tLayers1  []Layer1\n\tLayers12 []Layer2\n}\n\ntype Layer1 struct {\n\tID     int64\n\tLayers2 []Layer2\n}\n\ntype Layer2 struct {\n\tID int64\n}\n```\n\n### Rows returned by DB one at a time:\n\n#### Situation 1 - Many results at base level (aka. Level0 - Different IDs):\n\n```sql\nSELECT layer0.*, layer1.*, layer12.*, layer2.*\nFROM layer0\nLEFT JOIN layer1 ON ...\nLEFT JOIN layer12 ON ...\nLEFT JOIN layer2 ON ...\nWHERE ...\nLIMIT 1;\n```\n\n```go\ntype Row struct {\n\tLayer0  Layer0\n\tLayer1  Layer1\n\tLayer12 Layer2\n\tLayer2  Layer2\n}\n\nrows := []Row{\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 201}, Layer12: Layer2{ID: 5301}, Layer2: Layer2{ID: 301}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 201}, Layer12: Layer2{ID: 5302}, Layer2: Layer2{ID: 302}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 201}, Layer12: Layer2{ID: 5303}, Layer2: Layer2{ID: 303}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 204}, Layer12: Layer2{ID: 5304}, Layer2: Layer2{ID: 304}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 205}, Layer12: Layer2{ID: 5305}, Layer2: Layer2{ID: 305}},\n    {Layer0: Layer0{ID: 106}, Layer1: Layer1{ID: 206}, Layer12: Layer2{ID: 5306}, Layer2: Layer2{ID: 306}},\n    {Layer0: Layer0{ID: 106}, Layer1: Layer1{ID: 206}, Layer12: Layer2{ID: 5307}, Layer2: Layer2{ID: 307}},\n    {Layer0: Layer0{ID: 106}, Layer1: Layer1{ID: 206}, Layer12: Layer2{ID: 5308}, Layer2: Layer2{ID: 308}},\n    {Layer0: Layer0{ID: 109}, Layer1: Layer1{ID: 209}, Layer12: Layer2{ID: 5000}, Layer2: Layer2{ID: 000}},\n    {Layer0: Layer0{ID: 110}, Layer1: Layer1{ID: 000}, Layer12: Layer2{ID: 5000}, Layer2: Layer2{ID: 000}},\n}\n```\n\n=\u003e Results:\n\n```json\n{\n  \"ID\": 101,\n  \"Layer1\": [\n    {\n      \"ID\": 201,\n      \"Layer2\": [\n        {\n          \"ID\": 301\n        },\n        {\n          \"ID\": 302\n        },\n        {\n          \"ID\": 303\n        }\n      ]\n    },\n    {\n      \"ID\": 204,\n      \"Layer2\": [\n        {\n          \"ID\": 304\n        }\n      ]\n    },\n    {\n      \"ID\": 205,\n      \"Layer2\": [\n        {\n          \"ID\": 305\n        }\n      ]\n    },\n    {\n      \"ID\": 206,\n      \"Layer2\": [\n        {\n          \"ID\": 306\n        },\n        {\n          \"ID\": 307\n        },\n        {\n          \"ID\": 308\n        }\n      ]\n    },\n    {\n      \"ID\": 209,\n      \"Layer2\": null\n    }\n  ],\n  \"Layer12\": [\n    {\n      \"ID\": 5301\n    },\n    {\n      \"ID\": 5302\n    },\n    {\n      \"ID\": 5303\n    },\n    {\n      \"ID\": 5304\n    },\n    {\n      \"ID\": 5305\n    },\n    {\n      \"ID\": 5306\n    },\n    {\n      \"ID\": 5307\n    },\n    {\n      \"ID\": 5308\n    },\n    {\n      \"ID\": 5000\n    }\n  ]\n}\n```\n\n#### Situation 2 - One result at base level (aka. Level0 - Same IDs):\n\n```sql\nSELECT layer0.*, layer1.*, layer12.*, layer2.*\nFROM layer0\nLEFT JOIN layer1 ON ...\nLEFT JOIN layer12 ON ...\nLEFT JOIN layer2 ON ...\nWHERE ...;\n```\n\n```go\ntype Row struct {\n\tLayer0  Layer0\n\tLayer1  Layer1\n\tLayer12 Layer2\n\tLayer2  Layer2\n}\n\nrows := []Row{\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 201}, Layer12: Layer2{ID: 5301}, Layer2: Layer2{ID: 301}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 201}, Layer12: Layer2{ID: 5302}, Layer2: Layer2{ID: 302}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 201}, Layer12: Layer2{ID: 5303}, Layer2: Layer2{ID: 303}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 204}, Layer12: Layer2{ID: 5304}, Layer2: Layer2{ID: 304}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 205}, Layer12: Layer2{ID: 5305}, Layer2: Layer2{ID: 305}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 206}, Layer12: Layer2{ID: 5306}, Layer2: Layer2{ID: 306}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 206}, Layer12: Layer2{ID: 5307}, Layer2: Layer2{ID: 307}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 206}, Layer12: Layer2{ID: 5308}, Layer2: Layer2{ID: 308}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 209}, Layer12: Layer2{ID: 5000}, Layer2: Layer2{ID: 000}},\n    {Layer0: Layer0{ID: 101}, Layer1: Layer1{ID: 000}, Layer12: Layer2{ID: 5000}, Layer2: Layer2{ID: 000}},\n}\n```\n\n=\u003e Result:\n\n```json\n{\n  \"ID\": 101,\n  \"Layer1\": [\n    {\n      \"ID\": 201,\n      \"Layer2\": [\n        {\n          \"ID\": 301\n        },\n        {\n          \"ID\": 302\n        },\n        {\n          \"ID\": 303\n        }\n      ]\n    },\n    {\n      \"ID\": 204,\n      \"Layer2\": [\n        {\n          \"ID\": 304\n        }\n      ]\n    },\n    {\n      \"ID\": 205,\n      \"Layer2\": [\n        {\n          \"ID\": 305\n        }\n      ]\n    },\n    {\n      \"ID\": 206,\n      \"Layer2\": [\n        {\n          \"ID\": 306\n        },\n        {\n          \"ID\": 307\n        },\n        {\n          \"ID\": 308\n        }\n      ]\n    },\n    {\n      \"ID\": 209,\n      \"Layer2\": null\n    }\n  ],\n  \"Layer12\": [\n    {\n      \"ID\": 5301\n    },\n    {\n      \"ID\": 5302\n    },\n    {\n      \"ID\": 5303\n    },\n    {\n      \"ID\": 5304\n    },\n    {\n      \"ID\": 5305\n    },\n    {\n      \"ID\": 5306\n    },\n    {\n      \"ID\": 5307\n    },\n    {\n      \"ID\": 5308\n    },\n    {\n      \"ID\": 5000\n    }\n  ]\n}\n```\n\n### Notes\n\n- No matter what the DB driver or library we use, there should be an easy way to convert `query columns` into `a model struct`.\n- Here is my example of mapping `stmt` from [zombiezen.com/go/sqlite](https://github.com/zombiezen/go-sqlite) into `a model struct`:\n\n```go\nimport (\n\t\"context\"\n\t\"zombiezen.com/go/sqlite\"\n\t\"zombiezen.com/go/sqlite/sqlitex\"\n)\n\ntype Model struct {\n\tID        int64\n\tCreatedAt time.Time\n\tUpdatedAt time.Time\n\tDeletedAt time.Time\n\tDeletedBy string\n}\n\nfunc stmtModel(stmt *sqlite.Stmt, start int) Model {\n\treturn Model{\n\t\tID:        stmt.ColumnInt64(start),\n\t\tCreatedAt: stmtColumnTime(stmt, start+1),\n\t\tUpdatedAt: stmtColumnTime(stmt, start+2),\n\t\tDeletedAt: stmtColumnTime(stmt, start+3),\n\t\tDeletedBy: stmt.ColumnText(start + 4),\n\t}\n}\n\n// ---------------------\n\ntype Classroom struct {\n\tModel\n\tField1 int64\n\tField2 string\n\tField3 string\n}\n\nfunc stmtClassroom(stmt *sqlite.Stmt, start int) (end int, classroom Classroom) {\n\tvar buffer []byte\n\tstmt.ColumnBytes(1, buffer)\n\n\treturn start + 9, Classroom{\n\t\tModel:    stmtModel(stmt, start),\n\t\tField1:   stmt.ColumnInt64(start + 5),\n\t\tField2:   stmt.ColumnText(start + 6),\n\t\tField3:   stmt.ColumnText(start + 7),\n\t}\n}\n\n// ---------------------\n\ntype ClassroomWithStudents struct {\n\tClassroom\n\tStudents []Student\n}\n\n// ---------------------\n\nbuilder := NestedModelBuilder{}\nerr := sqlitex.Execute(conn, getClassroomWithStudents, \u0026sqlitex.ExecOptions{\n    Args: []any{userID, id},\n    ResultFunc: func(stmt *sqlite.Stmt) error {\n        next, classroom := stmtClassroom(stmt, 0)\n        _, student := stmtStudent(stmt, next)\n        builder.Build(\u0026ClassroomWithStudents{Classroom: classroom}, \u0026student)\n        return nil\n    },\n})\nresults := GetAll[*Layer0](builder)\n```\n\n## build IN query:\n\n```sql\nSELECT *\nFROM classroom\nWHERE classroom.number IN (?1)\n```\n\n=\u003e If there are 6 inputs, it will generate 10 slots, which a configuration step number to reduce the amount the prepared query\n\n```sql\nSELECT *\nFROM classroom\nWHERE classroom.number IN (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhoa-bit%2Fgo-db-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkhoa-bit%2Fgo-db-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkhoa-bit%2Fgo-db-tools/lists"}