github.com/mitranim/sqlb@v0.7.2/readme.md (about) 1 ## Overview 2 3 `sqlb`: **SQL** **B**uilder for Go. Features: 4 5 * Supports plain SQL queries with ordinal or named params. 6 * Supports argument lists. 7 * Supports argument maps. 8 * Supports argument structs. 9 * Supports generating SQL clauses from structs. 10 * Generate "select" clauses from structs. 11 * Generate "insert" clauses from structs. 12 * Generate "update" clauses from structs. 13 * Generate "delete" clauses from structs. 14 * Generate "and" and "or" conditional clauses from structs. 15 * Provides data structures forming an SQL DSL in Go. 16 * Shortcuts for common queries such as select, insert, update, delete. 17 * Arbitrarily composable and nestable. 18 * Uses data literals, not a builder API. 19 * Supports an optional "JSON Expression Language" (JEL) for expressing SQL expressions with nested Lisp-style calls in JSON. 20 * 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. 21 * Supports "sparse" structs, where not all fields are "present", allowing to implement HTTP PATCH semantics without sacrificing static typing. 22 * Compatible with standard SQL syntax, biased towards Postgres. 23 * Decently optimized. 24 * Small and dependency-free. 25 26 API docs: https://pkg.go.dev/github.com/mitranim/sqlb. 27 28 See the sibling library https://github.com/mitranim/gos for scanning SQL rows into structs. 29 30 ## Examples 31 32 All examples imply the following import: 33 34 ```golang 35 import s "github.com/mitranim/sqlb" 36 ``` 37 38 ### Query with named parameters and structs 39 40 ```golang 41 func ExampleStrQ_structs() { 42 type Output struct { 43 Col0 string `db:"col0"` 44 Col1 string `db:"col1"` 45 } 46 47 type Filter struct { 48 Col2 int64 `db:"col2"` 49 Col3 int64 `db:"col3"` 50 } 51 52 fmt.Println(s.Reify( 53 s.StrQ{` 54 select :cols from some_table where :filter 55 `, s.Dict{ 56 `cols`: s.Cols{(*Output)(nil)}, 57 `filter`: s.And{Filter{10, 20}}, 58 }}, 59 )) 60 // Output: 61 // select "col0", "col1" from some_table where "col2" = $1 and "col3" = $2 [10 20] 62 } 63 ``` 64 65 ### AST-style query building 66 67 ```golang 68 func ExampleInsert_nonEmpty() { 69 type Fields struct { 70 Col0 int64 `db:"col0"` 71 Col1 int64 `db:"col1"` 72 } 73 74 fmt.Println(s.Reify(s.Insert{`some_table`, Fields{10, 20}})) 75 76 // Output: 77 // insert into "some_table" ("col0", "col1") values ($1, $2) returning * [10 20] 78 } 79 ``` 80 81 ### Composition 82 83 ```golang 84 func Example_composition() { 85 inner := s.StrQ{ 86 `select * from some_table where col0 = :val`, 87 s.Dict{`val`: 10}, 88 } 89 90 outer := s.StrQ{ 91 `select * from (:inner) as _ where col1 = :val`, 92 s.Dict{`inner`: inner, `val`: 20}, 93 } 94 95 fmt.Println(s.Reify(outer)) 96 // Output: 97 // select * from (select * from some_table where col0 = $1) as _ where col1 = $2 [10 20] 98 } 99 ``` 100 101 ## Changelog 102 103 ### v0.7.2 104 105 Added `ValidateUnusedArguments` that globally disables or enables argument validation. 106 107 Internal improvements in errors. 108 109 ### v0.7.1 110 111 Added `InsertVoid`, `UpdateVoid`, `DeleteVoid`, `UpsertVoid`. 112 113 ### v0.7.0 114 115 Renamed method `.Append` in various types to `.AppendTo` for consistency with other libraries. 116 117 Renamed interface `Appender` to `AppenderTo`. 118 119 ### v0.6.8 120 121 Added `LaxDict`: dictionary of named arguments similar to `Dict`, but without support for validating unused arguments. 122 123 ### v0.6.7 124 125 Fixed an edge case bug in `Upsert`. 126 127 ### v0.6.6 128 129 Fixed support for non-empty sparse structs in `Upsert`. 130 131 ### v0.6.5 132 133 Add `Upsert`. 134 135 ### v0.6.4 136 137 `OrdsParser` support default "dir" and "nulls" in struct tags: 138 139 ```go 140 type Ordable struct { 141 Name string `json:"name" db:"name" ord.dir:"desc" ord.nulls:"last"` 142 } 143 ``` 144 145 ### v0.6.3 146 147 * `Dir` supports text parsing and encoding. 148 * Minor breaking change: `Bui.Arg` now appends both an argument and a parameter. 149 150 ### v0.6.2 151 152 `CommaAppender` and `ArrayAppender` are now parametrized on the element type. 153 154 ### v0.6.1 155 156 Added `StructsInsert`, `StructsInsertOf`. 157 158 ### v0.6.0 159 160 * Support `role:"ref"` struct field annotation for pointer-like generic types. 161 162 * Require Go 1.18. 163 164 ### v0.5.3 165 166 Added `SliceCommaAppender`. 167 168 ### v0.5.2 169 170 `Update` now defaults to `where null` rather than `where true`. The new behavior is aligned with `Delete`. 171 172 Embedded 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. 173 174 ### v0.5.1 175 176 Added optional support for a hidden `Nullable` interface, shared with the library `github.com/mitranim/gt`. 177 178 ### v0.5.0 179 180 * Revised ords parsing. 181 * Split `OrdsParser` into two types: 182 * `ParserOrds` → suitable for inclusion into other types. 183 * `OrdsParser` → suitable for transient, stackframe-local use. 184 * Added `(*Ords).OrdsParser` suitable for use by types that embed `Ords` and implement custom parsing methods. 185 * Support arbitrary filters for struct fields. 186 * Added `TagFilter` for field filtering. 187 * Renamed `Sparse.HasField` to `Sparse.AllowField`. `Filter` uses a method with the same signature, and the old name didn't make sense for it. 188 * Misc: 189 * Renamed `(*Ords).AppendVals` → `(*Ords).Add`. 190 * Added `(*Ords).Zero`. 191 * Replaced `Ords.Grow` with `(*Ords).Grow` that modifies the receiver. 192 193 ### v0.4.3 194 195 Add `SelectCount`. 196 197 ### v0.4.2 198 199 Add `Limit`, `Offset`, `LimitUint`, `OffsetUint`. 200 201 ### v0.4.1 202 203 Exported `ErrEmptyAssign` used by `StructAssign` and `Update` to indicate the inability to generate a valid SQL "update set" clause. 204 205 ### v0.4.0 206 207 Added low-level tools for text encoding and SQL array encoding: 208 209 * `ArrayAppender` 210 * `CommaAppender` 211 * `String` 212 * `TryString` 213 * `Append` 214 * `TryAppend` 215 * `TryAppendWith` 216 * `AppendWith` 217 * `AppenderString` 218 219 Breaking changes: 220 221 * Removed useless expression type `Int`. 222 * Renamed `Bui.TryExprs` to `Bui.CatchExprs`. 223 224 ### v0.3.0 225 226 Revised AST-style expressions: 227 228 * Removed uselessly low-level exprs such as `Space`, `ReturningStar`, and so on. 229 * Added higher-level shortcuts for extremely common yet simple operations: 230 * `Select` 231 * `Insert` 232 * `Update` 233 * `Delete` 234 235 ### v0.2.1 236 237 Added `Sparse` and `Partial` to support "sparse" structs, allowing to implement HTTP PATCH semantics more easily, efficiently, and correctly. 238 239 ### v0.2.0 240 241 Full 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`. 242 243 ### v0.1.17 244 245 Added `Ords.OrType`. 246 247 ### v0.1.16 248 249 Added `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. 250 251 ### v0.1.15 252 253 `Ords.Or` is now a value method that returns a modified version, rather than a pointer method that mutated the original. 254 255 ### v0.1.14 256 257 `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. 258 259 ### v0.1.13 260 261 Fixed the bug where the `Ords.Lax` mode was appending malformed ords, instead of skipping them entirely. 262 263 ### v0.1.12 264 265 * `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. 266 267 * `(*Query).Append` no longer has an argument length limit. 268 269 ### v0.1.11 270 271 Added `Ords.Lax`: a boolean that causes `Ords` to skip unknown fields during parsing. 272 273 ### v0.1.10 274 275 Breaking changes in the name of efficiency: 276 277 * `NamedArgs.Conditions` now uses `=` and `is null`, as appropriate, instead of previous `is not distinct from`. At the time of writing, Postgres (version <= 12) is unable to use indexes for `is not distinct from`, which may result in much slower queries. The new approach avoids this gotcha. 278 279 * 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 <= 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. 280 281 * Added `OrdAscNl` and `OrdDescNl` for convenient construction. 282 283 * Minor breaking change: `Ord.IsDesc` is now `Ord.Desc`. 284 285 * Minor breaking change: removed `Ord.IsValid`. 286 287 Non-breaking additions: 288 289 * `Ords.RowNumber()`: generates a Postgres window function expression `row_number() over (order by ...)`, falling back on a constant value when the ordering is empty. 290 291 * `QueryOrd()`: shortcut for making a `Query` with a single `.Append()` invocation. 292 293 * `QueryNamed()`: shortcut for making a `Query` with a single `.AppendNamed()` invocation. 294 295 ### 0.1.9 296 297 Added `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. 298 299 ### 0.1.8 300 301 Added `StrQuery`. 302 303 ### 0.1.7 304 305 Corrected `CheckUnused` to be `true` by default, which was always intended. 306 307 ### 0.1.6 308 309 Added `CheckUnused` which allows to opt out of unused parameter checks in `Query.Append` and `Query.AppendNamed`. Can be convenient for development. 310 311 ### 0.1.5 312 313 Minor bugfix: `Query.String` is now implemented on the non-pointer type, as intended. Also updated the `sqlp` dependency. 314 315 ### 0.1.4 316 317 Breaking changes in `Query`: simpler interface, better performance. 318 319 Instead 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. 320 321 ### 0.1.3 322 323 Added `Query.Clear()`. 324 325 ### 0.1.2 326 327 Breaking: methods of `NamedArgs` now return queries, suitable for inclusion into other queries. Separate methods for strings and arg slices have been removed. 328 329 ### 0.1.1 330 331 Dependency update. 332 333 ### 0.1.0 334 335 First tagged release. 336 337 ## License 338 339 https://unlicense.org 340 341 ## Misc 342 343 I'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