{"id":27341454,"url":"https://github.com/ylonely/sqldb","last_synced_at":"2025-09-14T04:42:05.311Z","repository":{"id":61629356,"uuid":"552290402","full_name":"YLonely/sqldb","owner":"YLonely","description":"A go package which uses generics to simplify the manipulating of sql database.","archived":false,"fork":false,"pushed_at":"2023-04-18T07:29:30.000Z","size":164,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-15T00:38:26.876Z","etag":null,"topics":["database","generics","go","golang","golang-library","gorm","orm"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/YLonely.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":"2022-10-16T08:46:39.000Z","updated_at":"2024-12-15T15:44:07.000Z","dependencies_parsed_at":"2024-06-20T04:16:18.291Z","dependency_job_id":"31ca51ec-4242-44da-8125-770e5963e089","html_url":"https://github.com/YLonely/sqldb","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/YLonely/sqldb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YLonely%2Fsqldb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YLonely%2Fsqldb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YLonely%2Fsqldb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YLonely%2Fsqldb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/YLonely","download_url":"https://codeload.github.com/YLonely/sqldb/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YLonely%2Fsqldb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271314372,"owners_count":24738161,"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-08-20T02:00:09.606Z","response_time":69,"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":["database","generics","go","golang","golang-library","gorm","orm"],"created_at":"2025-04-12T16:09:05.201Z","updated_at":"2025-08-20T12:04:27.169Z","avatar_url":"https://github.com/YLonely.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Introduction\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/YLonely/sqldb)](https://goreportcard.com/report/github.com/YLonely/sqldb)\n[![Go Reference](https://pkg.go.dev/badge/github.com/YLonely/sqldb.svg)](https://pkg.go.dev/github.com/YLonely/sqldb)\n\nsqldb is a useful package which defines some common types and interfaces in manipulating data of models in sql database.\n\nIt also provides an implementation of the interfaces based on the [GORM](https://gorm.io/) library.\n\n# Getting Started\n\n## The Model interface\nThe `Model` and `Executor` defined in `model.go` contains a set of commonly used methods when handling data in a database.\n```golang\n// Model is an interface defines commonly used methods to manipulate data.\ntype Model[T any] interface {\n\t// DB returns the db instance.\n\tDB(context.Context) *gorm.DB\n\t// Table returns the table name in the database.\n\tTable() string\n\t// Columns returns a instance of type T,\n\t// all fields of type sqldb.Column[U] in the instance are populated with corresponding column name.\n\tColumns() T\n\t// ColumnNames returns all column names the model has.\n\tColumnNames() []ColumnNameGetter\n\t// Create creates an new entity of type T.\n\tCreate(ctx context.Context, entity *T) error\n\tQuery(queries ...FilterOption) Executor[T]\n}\n\n// Executor is an interface wraps operations related to db queries.\ntype Executor[T any] interface {\n\tGet(ctx context.Context) (T, error)\n\tList(ctx context.Context, opts ListOptions) ([]T, uint64, error)\n\tUpdate(ctx context.Context, opts ...UpdateOption) (uint64, error)\n\tDelete(ctx context.Context) error\n}\n```\n## Declaring models\nBefore using the `Model` you have to declaring your model, `User` for example:\n```golang\nimport (\n\t\"gorm.io/gorm\"\n\t\"github.com/YLonely/sqldb\"\n)\n\ntype User struct {\n\tID      sqldb.Column[uint64] `gorm:\"column:id;primaryKey\"`\n\tName    sqldb.Column[string] `gorm:\"column:user_name\"`\n\tAge     sqldb.PtrColumn[int]\n\tCreatedAt sqldb.Column[time.Time]\n\tDeletedAt sqldb.Column[gorm.DeletedAt]\n}\n```\nHere `sqldb.Column` or `sqldb.PtrColumn` is a generic type which represents a table column in the database, it contains the value of the corresponding field and also the column name of it. \n\n## Operating the model\nNow we can initialize a `Model` type for `User`:\n```golang\nimport (\n\t\"context\"\n\n\t\"gorm.io/gorm\"\n\t\"github.com/YLonely/sqldb\"\n)\n\nfunc main(){\n\t// Use gorm to open the database.\n\tdsn := \"user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4\u0026parseTime=True\u0026loc=Local\"\n  \tdb, err := gorm.Open(mysql.Open(dsn), \u0026gorm.Config{})\n\tif err != nil{\n\t\tpanic(err)\n\t}\n\n\tif err := db.AutoMigrate(User{}); err != nil {\n\t\tpanic(err)\n\t}\n\tm := sqldb.NewModel[User](db)\n\tcols := m.Columns()\n\tctx := context.Background()\n\n\tu := \u0026User{\n\t\tID:   sqldb.NewColumn(uint64(1)),\n\t\tName: sqldb.NewColumn(\"lazy\"),\n\t\tAge:  sqldb.NewPtrColumn(10),\n\t}\n\tif err := m.Create(ctx, u); err != nil {\n\t\tpanic(err)\n\t}\n\n\tu.ID.V = 2\n\tu.Name.V = \"jump\"\n\tif err := m.Create(ctx, u); err != nil {\n\t\tpanic(err)\n\t}\n\n\tusers, _, err := m.Query(\n\t\tcols.Name.NE(\"lazy\"),\n\t\tcols.Age.In([]int{10, 11, 12}),\n\t\t// not recommended\n\t\tsqldb.NewOpQueryOption(\n\t\t\tsqldb.NewColumnName(\"user_name\"),\n\t\t\tsqldb.OpEq,\n\t\t\t\"jump\",\n\t\t),\n\t).List(ctx, sqldb.ListOptions{})\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tfor _, u := range users {\n\t\tfmt.Printf(\"id: %v\\tname: %s\\tage: %v\\n\",\n\t\t\tu.ID.V, u.Name.V, *u.Age.V)\n\t}\n}\n```\n\nIt is worth noting that you do not write string literals of columns when constructing query options, every `Model[T]` type has a method `Columns()` which returns a instance of type T, all fields of type `sqldb.Column` or `sqldb.PtrColumn` in type T provide a bunch of useful methods for users to construct query options. \n```golang\nfunc EQ(value any) OpOption {}\nfunc NE(value any) OpOption {}\nfunc GT(value any) OpOption {}\nfunc LT(value any) OpOption {}\nfunc GTE(value any) OpOption {}\nfunc LTE(value any) OpOption {}\nfunc In(values []T) RangeQueryOption {}\nfunc NotIn(values []T) RangeQueryOption {}\nfunc FuzzyIn(values []T) FuzzyQueryOption {}\nfunc Update(value any) UpdateOption {}\n```\nYou can also use the option structs directly, but you have to confirm the column name by yourself, which is extremely not recommended.\n\n## Transactions\n`sqldb.go` also defines a function type which abstracts transactions:\n```golang\ntype TransactionFunc func(ctx context.Context, run func(context.Context) error) error\n```\n\nTo create a `TransactionFunc` implemented by GORM and process models in the transaction:\n```golang\nTransaction := sqldb.NewTransactionFunc(db)\n\nTransaction(context.Background(), func(ctx context.Context) error {\n\tif err := Users.Query(Users.Columns().Age.In([]int{10, 11, 12})).Delete(ctx); err != nil {\n\t\treturn err\n\t}\n\n\t// nested transaction.\n\tTransaction(ctx, func(ctx context.Context) error {\n\t})\n})\n```\n## Joining tables\n\nsqldb provides a more convenient way to join tables. The complexity of renaming duplicate column names and writing lengthy sql statements is hidden in the internal processing of sqldb. All you need to do is to call the encapsulated join functions. \n```golang\nimport (\n\t\"context\"\n\n\t\"gorm.io/gorm\"\n\t\"github.com/YLonely/sqldb\"\n)\n\ntype User struct {\n\tName sqldb.Column[string]\n\tAge  sqldb.Column[int]\n}\n\ntype Class struct {\n\tName    sqldb.Column[string]\n\tAddress sqldb.Column[string]\n\tAge     sqldb.Column[int]\n}\n\nfunc main(){\n\t// Use gorm to open the database.\n\tusers := sqldb.NewModel[User](db)\n\tclasses := sqldb.NewModel[Class](db)\n\tctx := context.Background()\n\n\tresults, total, err := Join(ctx, users, classes, \n\t\tNewJoinOptions(\n\t\t\tappend(users.ColumnNames(), classes.ColumnNames()...),\n\t\t\tusers.Columns().Name.EQ(classes.Columns().Name),\n\t\t),\n\t).Query().List(ctx, sqldb.ListOptions{})\n\n\tfor _, result := range results {\n\t\tfmt.Printf(\"user.name: %s, class.name: %s\\n\", result.Left.Name, result.Right.Name)\n\t}\n}\n```\nThe join functions also return a `Model` type, which allows you to concatenate other complex query operations. The type `JoinedEntity` contains both Model types that are joined which provides a view of the joined tables.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fylonely%2Fsqldb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fylonely%2Fsqldb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fylonely%2Fsqldb/lists"}