{"id":24083277,"url":"https://github.com/mitranim/sqlb","last_synced_at":"2025-04-30T18:23:06.568Z","repository":{"id":57546066,"uuid":"299525493","full_name":"mitranim/sqlb","owner":"mitranim","description":"SQL query builder in Go. Oriented towards plain SQL. Supports composition.","archived":false,"fork":false,"pushed_at":"2023-11-28T12:45:54.000Z","size":450,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-26T06:56:57.509Z","etag":null,"topics":["go","sql","sql-query-builder"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/mitranim/sqlb","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mitranim.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-09-29T06:31:49.000Z","updated_at":"2024-08-25T17:23:02.000Z","dependencies_parsed_at":"2023-11-28T13:43:56.888Z","dependency_job_id":"32c34eec-cc2c-499c-995b-8840b93e1e9d","html_url":"https://github.com/mitranim/sqlb","commit_stats":null,"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fsqlb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fsqlb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fsqlb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mitranim%2Fsqlb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mitranim","download_url":"https://codeload.github.com/mitranim/sqlb/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251758672,"owners_count":21639082,"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","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":["go","sql","sql-query-builder"],"created_at":"2025-01-09T23:56:16.042Z","updated_at":"2025-04-30T18:23:06.530Z","avatar_url":"https://github.com/mitranim.png","language":"Go","readme":"## Overview\n\n`sqlb`: **SQL** **B**uilder for Go. Features:\n\n* Supports plain SQL queries with ordinal or named params.\n  * Supports argument lists.\n  * Supports argument maps.\n  * Supports argument structs.\n* Supports generating SQL clauses from structs.\n  * Generate \"select\" clauses from structs.\n  * Generate \"insert\" clauses from structs.\n  * Generate \"update\" clauses from structs.\n  * Generate \"delete\" clauses from structs.\n  * Generate \"and\" and \"or\" conditional clauses from structs.\n* Provides data structures forming an SQL DSL in Go.\n  * Shortcuts for common queries such as select, insert, update, delete.\n  * Arbitrarily composable and nestable.\n  * Uses data literals, not a builder API.\n* Supports an optional \"JSON Expression Language\" (JEL) for expressing SQL expressions with nested Lisp-style calls in JSON.\n* Supports safely parsing \"order by\" clauses from JSON and text, for specific struct types, converting field names from `\"json\"` field tags to `\"db\"` field tags.\n* Supports \"sparse\" structs, where not all fields are \"present\", allowing to implement HTTP PATCH semantics without sacrificing static typing.\n* Compatible with standard SQL syntax, biased towards Postgres.\n* Decently optimized.\n* Small and dependency-free.\n\nAPI docs: https://pkg.go.dev/github.com/mitranim/sqlb.\n\nSee the sibling library https://github.com/mitranim/gos for scanning SQL rows into structs.\n\n## Examples\n\nAll examples imply the following import:\n\n```golang\nimport s \"github.com/mitranim/sqlb\"\n```\n\n### Query with named parameters and structs\n\n```golang\nfunc ExampleStrQ_structs() {\n  type Output struct {\n    Col0 string `db:\"col0\"`\n    Col1 string `db:\"col1\"`\n  }\n\n  type Filter struct {\n    Col2 int64 `db:\"col2\"`\n    Col3 int64 `db:\"col3\"`\n  }\n\n  fmt.Println(s.Reify(\n    s.StrQ{`\n      select :cols from some_table where :filter\n    `, s.Dict{\n      `cols`:   s.Cols{(*Output)(nil)},\n      `filter`: s.And{Filter{10, 20}},\n    }},\n  ))\n  // Output:\n  // select \"col0\", \"col1\" from some_table where \"col2\" = $1 and \"col3\" = $2 [10 20]\n}\n```\n\n### AST-style query building\n\n```golang\nfunc ExampleInsert_nonEmpty() {\n  type Fields struct {\n    Col0 int64 `db:\"col0\"`\n    Col1 int64 `db:\"col1\"`\n  }\n\n  fmt.Println(s.Reify(s.Insert{`some_table`, Fields{10, 20}}))\n\n  // Output:\n  // insert into \"some_table\" (\"col0\", \"col1\") values ($1, $2) returning * [10 20]\n}\n```\n\n### Composition\n\n```golang\nfunc Example_composition() {\n  inner := s.StrQ{\n    `select * from some_table where col0 = :val`,\n    s.Dict{`val`: 10},\n  }\n\n  outer := s.StrQ{\n    `select * from (:inner) as _ where col1 = :val`,\n    s.Dict{`inner`: inner, `val`: 20},\n  }\n\n  fmt.Println(s.Reify(outer))\n  // Output:\n  // select * from (select * from some_table where col0 = $1) as _ where col1 = $2 [10 20]\n}\n```\n\n## Changelog\n\n### v0.7.4\n\nMinor fix for reporting types in error messages. Some internal tweaks.\n\n### v0.7.3\n\nAdded `UpsertConflictVoid`, `UpsertConflict`.\n\n### v0.7.2\n\nAdded `ValidateUnusedArguments` that globally disables or enables argument validation.\n\nInternal improvements in errors.\n\n### v0.7.1\n\nAdded `InsertVoid`, `UpdateVoid`, `DeleteVoid`, `UpsertVoid`.\n\n### v0.7.0\n\nRenamed method `.Append` in various types to `.AppendTo` for consistency with other libraries.\n\nRenamed interface `Appender` to `AppenderTo`.\n\n### v0.6.8\n\nAdded `LaxDict`: dictionary of named arguments similar to `Dict`, but without support for validating unused arguments.\n\n### v0.6.7\n\nFixed an edge case bug in `Upsert`.\n\n### v0.6.6\n\nFixed support for non-empty sparse structs in `Upsert`.\n\n### v0.6.5\n\nAdd `Upsert`.\n\n### v0.6.4\n\n`OrdsParser` support default \"dir\" and \"nulls\" in struct tags:\n\n```go\ntype Ordable struct {\n  Name string `json:\"name\" db:\"name\" ord.dir:\"desc\" ord.nulls:\"last\"`\n}\n```\n\n### v0.6.3\n\n* `Dir` supports text parsing and encoding.\n* Minor breaking change: `Bui.Arg` now appends both an argument and a parameter.\n\n### v0.6.2\n\n`CommaAppender` and `ArrayAppender` are now parametrized on the element type.\n\n### v0.6.1\n\nAdded `StructsInsert`, `StructsInsertOf`.\n\n### v0.6.0\n\n* Support `role:\"ref\"` struct field annotation for pointer-like generic types.\n\n* Require Go 1.18.\n\n### v0.5.3\n\nAdded `SliceCommaAppender`.\n\n### v0.5.2\n\n`Update` now defaults to `where null` rather than `where true`. The new behavior is aligned with `Delete`.\n\nEmbedded struct fields tagged with `db:\"\"` or `db:\"-\"` are now completely ignored. The old behavior treated them as untagged, traversing them. The new behavior allows to completely skip an embedded struct, on an opt-in basis, without having to modify the `db` tags of its inner fields.\n\n### v0.5.1\n\nAdded optional support for a hidden `Nullable` interface, shared with the library `github.com/mitranim/gt`.\n\n### v0.5.0\n\n* Revised ords parsing.\n  * Split `OrdsParser` into two types:\n    * `ParserOrds` → suitable for inclusion into other types.\n    * `OrdsParser` → suitable for transient, stackframe-local use.\n  * Added `(*Ords).OrdsParser` suitable for use by types that embed `Ords` and implement custom parsing methods.\n  * Support arbitrary filters for struct fields.\n  * Added `TagFilter` for field filtering.\n* Renamed `Sparse.HasField` to `Sparse.AllowField`. `Filter` uses a method with the same signature, and the old name didn't make sense for it.\n* Misc:\n  * Renamed `(*Ords).AppendVals` → `(*Ords).Add`.\n  * Added `(*Ords).Zero`.\n  * Replaced `Ords.Grow` with `(*Ords).Grow` that modifies the receiver.\n\n### v0.4.3\n\nAdd `SelectCount`.\n\n### v0.4.2\n\nAdd `Limit`, `Offset`, `LimitUint`, `OffsetUint`.\n\n### v0.4.1\n\nExported `ErrEmptyAssign` used by `StructAssign` and `Update` to indicate the inability to generate a valid SQL \"update set\" clause.\n\n### v0.4.0\n\nAdded low-level tools for text encoding and SQL array encoding:\n\n  * `ArrayAppender`\n  * `CommaAppender`\n  * `String`\n  * `TryString`\n  * `Append`\n  * `TryAppend`\n  * `TryAppendWith`\n  * `AppendWith`\n  * `AppenderString`\n\nBreaking changes:\n\n  * Removed useless expression type `Int`.\n  * Renamed `Bui.TryExprs` to `Bui.CatchExprs`.\n\n### v0.3.0\n\nRevised AST-style expressions:\n\n* Removed uselessly low-level exprs such as `Space`, `ReturningStar`, and so on.\n* Added higher-level shortcuts for extremely common yet simple operations:\n  * `Select`\n  * `Insert`\n  * `Update`\n  * `Delete`\n\n### v0.2.1\n\nAdded `Sparse` and `Partial` to support \"sparse\" structs, allowing to implement HTTP PATCH semantics more easily, efficiently, and correctly.\n\n### v0.2.0\n\nFull API revision. Added many AST/DSL-like types for common expressions. Optimized parsing and expression building. Use caching and pooling to minimize redundant work. String-based query building now uses partial parsing with caching, and should no longer be a measurable expense. Ported JEL support from `github.com/mitranim/jel`.\n\n### v0.1.17\n\nAdded `Ords.OrType`.\n\n### v0.1.16\n\nAdded `NamedArg.Norm`. Improved `NamedArg.IsNil` and `NamedArgs.Conditions`. They now use the `driver.Valuer.Value` method, if present, to determine null-ness, which works for non-pointer \"nullable\" types.\n\n### v0.1.15\n\n`Ords.Or` is now a value method that returns a modified version, rather than a pointer method that mutated the original.\n\n### v0.1.14\n\n`StructMap` and `StructNamedArgs` now tolerate `nil` inputs. Previously, they tolerated non-nil interfaces where the underlying value was a nil struct pointer. Now they also allow nil interfaces.\n\n### v0.1.13\n\nFixed the bug where the `Ords.Lax` mode was appending malformed ords, instead of skipping them entirely.\n\n### v0.1.12\n\n* `StrQuery` now interpolates directly, without invoking `(*Query).Append` on the provided query. This allows to interpolate `StrQuery` strings that contain parameter placeholders. Use at your own risk.\n\n* `(*Query).Append` no longer has an argument length limit.\n\n### v0.1.11\n\nAdded `Ords.Lax`: a boolean that causes `Ords` to skip unknown fields during parsing.\n\n### v0.1.10\n\nBreaking changes in the name of efficiency:\n\n* `NamedArgs.Conditions` now uses `=` and `is null`, as appropriate, instead of previous `is not distinct from`. At the time of writing, Postgres (version \u003c= 12) is unable to use indexes for `is not distinct from`, which may result in much slower queries. The new approach avoids this gotcha.\n\n* In `Ord`, `nulls last` is now opt-in rather than default. In addition, `asc/desc` in input strings is now optional. This more precisely reflects SQL semantics and allows finer-grained control. More importantly, it avoids a potential performance gotcha. At the time of writing, Postgres (version \u003c= 12) is unable to use normal indexes for `nulls last` ordering. Instead it requires specialized indexes where `nulls last` is set explicitly. Making it opt-in reduces the chance of accidental slowness.\n\n  * Added `OrdAscNl` and `OrdDescNl` for convenient construction.\n\n  * Minor breaking change: `Ord.IsDesc` is now `Ord.Desc`.\n\n* Minor breaking change: removed `Ord.IsValid`.\n\nNon-breaking additions:\n\n* `Ords.RowNumber()`: generates a Postgres window function expression `row_number() over (order by ...)`, falling back on a constant value when the ordering is empty.\n\n* `QueryOrd()`: shortcut for making a `Query` with a single `.Append()` invocation.\n\n* `QueryNamed()`: shortcut for making a `Query` with a single `.AppendNamed()` invocation.\n\n### 0.1.9\n\nAdded `Ords` and `Ord`: structured representation of `order by`, able to decode from external input such as JSON, but also flexible enough to store arbitrary sub-queries. Ported from `github.com/mitranim/jel`, while also adding the ability to store sub-queries rather than only identifiers.\n\n### 0.1.8\n\nAdded `StrQuery`.\n\n### 0.1.7\n\nCorrected `CheckUnused` to be `true` by default, which was always intended.\n\n### 0.1.6\n\nAdded `CheckUnused` which allows to opt out of unused parameter checks in `Query.Append` and `Query.AppendNamed`. Can be convenient for development.\n\n### 0.1.5\n\nMinor bugfix: `Query.String` is now implemented on the non-pointer type, as intended. Also updated the `sqlp` dependency.\n\n### 0.1.4\n\nBreaking changes in `Query`: simpler interface, better performance.\n\nInstead of storing and operating on a parsed AST, `Query` now stores the query text as `[]byte`. We use `sqlp.Tokenizer` to parse inputs without generating an AST, transcoding parameters on the fly. `IQuery` now simply appends to an externally-passed `Query`, instead of having to return a parsed AST representation. All together, this significantly simplifies the implementation of `Query` and any external `IQuery` types.\n\n### 0.1.3\n\nAdded `Query.Clear()`.\n\n### 0.1.2\n\nBreaking: methods of `NamedArgs` now return queries, suitable for inclusion into other queries. Separate methods for strings and arg slices have been removed.\n\n### 0.1.1\n\nDependency update.\n\n### 0.1.0\n\nFirst tagged release.\n\n## License\n\nhttps://unlicense.org\n\n## Misc\n\nI'm receptive to suggestions. If this library _almost_ satisfies you but needs changes, open an issue or chat me up. Contacts: https://mitranim.com/#contacts\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmitranim%2Fsqlb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmitranim%2Fsqlb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmitranim%2Fsqlb/lists"}