qubu 0.3.5 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/{canonical-BbnqavJm.mjs → canonical-BXUguqfo.mjs} +23 -23
  2. package/dist/codegen.d.mts +25 -33
  3. package/dist/codegen.mjs +38 -45
  4. package/dist/column-hqKr7-1I.mjs +620 -0
  5. package/dist/{complete-D5Djh-zo.mjs → complete-WYyVozgK.mjs} +50 -50
  6. package/dist/{complete-types-B2PO6wQD.d.mts → complete-types-IjEn5VPN.d.mts} +56 -56
  7. package/dist/core.d.mts +2 -2
  8. package/dist/core.mjs +4 -4
  9. package/dist/ddl.d.mts +12 -12
  10. package/dist/ddl.mjs +13 -14
  11. package/dist/{dialect-b2-Z6uBF.mjs → dialect-wUKrnPMB.mjs} +2 -2
  12. package/dist/diff.d.mts +1 -1
  13. package/dist/diff.mjs +6 -7
  14. package/dist/{index-7qc6OcIC.d.mts → index-1DpA3mUh.d.mts} +20 -20
  15. package/dist/{index-CqWnouTK.d.mts → index-CPvfEheG.d.mts} +13 -15
  16. package/dist/index.d.mts +2 -2
  17. package/dist/index.mjs +148 -120
  18. package/dist/introspection.d.mts +8 -8
  19. package/dist/introspection.mjs +29 -30
  20. package/dist/{json-CUZlv4HT.mjs → json-Db7XRD91.mjs} +2 -2
  21. package/dist/migration.d.mts +20 -21
  22. package/dist/migration.mjs +5 -6
  23. package/dist/{mysql-DqkqXB6A.mjs → mysql-B_cYzzX2.mjs} +237 -7
  24. package/dist/mysql.d.mts +1 -1
  25. package/dist/mysql.mjs +3 -3
  26. package/dist/{on-conflict-BxnxubMb.mjs → on-conflict-hfPW0KmQ.mjs} +4 -4
  27. package/dist/postgres.d.mts +5 -5
  28. package/dist/postgres.mjs +6 -6
  29. package/dist/{registry-BufIskVN.mjs → registry-BRMLYwDp.mjs} +27 -135
  30. package/dist/{relational-DCZrrNia.mjs → relational-BZ3WDPzC.mjs} +4 -4
  31. package/dist/schema.d.mts +2 -2
  32. package/dist/schema.mjs +6 -6
  33. package/dist/{snapshot-CWPgzxNx.mjs → snapshot-C-W65HEd.mjs} +5 -5
  34. package/dist/snapshot.d.mts +3 -3
  35. package/dist/snapshot.mjs +5 -7
  36. package/dist/{source-DUoJVXmL.mjs → source-BcS2AsIg.mjs} +7 -9
  37. package/dist/{serialize-PF1cfH2P.mjs → sqlite-Cg0nwYEH.mjs} +326 -12
  38. package/dist/sqlite.d.mts +2 -2
  39. package/dist/sqlite.mjs +2 -2
  40. package/dist/{standard-BTVYKh_F.mjs → standard-DfcZEVOj.mjs} +1 -1
  41. package/dist/{table-CCUJ60rB.mjs → table-Bp5irMSj.mjs} +5 -7
  42. package/dist/{types-D8M1yZF4.d.mts → types-BK1COGZe.d.mts} +2661 -2150
  43. package/dist/{types-Cec0xzo4.mjs → types-JM3FcAnX.mjs} +8 -8
  44. package/dist/{types-LBt5rclR.d.mts → types-JSZHpUEj.d.mts} +83 -84
  45. package/dist/{value-BvilP0oz.mjs → value-Bi71Agyf.mjs} +1 -1
  46. package/dist/vite/ambient.d.ts +311 -390
  47. package/dist/vite.d.mts +5 -6
  48. package/dist/vite.mjs +3 -4
  49. package/docs/dialects-and-execution.md +121 -81
  50. package/docs/getting-started.md +4 -4
  51. package/docs/guides/better-auth.md +57 -0
  52. package/docs/guides/compose-queries.md +24 -67
  53. package/docs/guides/drizzle.md +23 -23
  54. package/docs/guides/extensions/dialects.md +4 -4
  55. package/docs/guides/extensions/sources-and-clauses.md +15 -15
  56. package/docs/guides/extensions/typed-expressions.md +13 -17
  57. package/docs/guides/extensions/unsafe-syntax.md +3 -3
  58. package/docs/guides/json.md +7 -7
  59. package/docs/guides/mutations.md +14 -21
  60. package/docs/guides/select/conditions.md +6 -8
  61. package/docs/guides/select/grouping-and-windows.md +4 -15
  62. package/docs/guides/select/ordering-and-pagination.md +6 -19
  63. package/docs/guides/select/overview.md +12 -26
  64. package/docs/guides/sql-templates.md +20 -24
  65. package/docs/guides/vite-plugin.md +9 -13
  66. package/docs/index.md +5 -7
  67. package/docs/query-model/fragments.md +4 -15
  68. package/docs/query-model/result-shapes.md +11 -14
  69. package/docs/query-model/source-scope.md +31 -49
  70. package/docs/reference/mysql-snapshot.md +2 -5
  71. package/docs/reference/postgres-snapshot.md +3 -3
  72. package/docs/reference/sqlite-snapshot.md +2 -5
  73. package/docs/reference/supported-surface.md +33 -33
  74. package/docs/schema/catalog-model.md +2 -5
  75. package/docs/schema/code-generation.md +18 -18
  76. package/docs/schema/columns-and-writes.md +17 -25
  77. package/docs/schema/constraints-and-indexes.md +36 -52
  78. package/docs/schema/ddl-emission.md +6 -6
  79. package/docs/schema/diff.md +5 -5
  80. package/docs/schema/introspection.md +7 -7
  81. package/docs/schema/migration-plans.md +9 -9
  82. package/docs/schema/snapshots.md +3 -3
  83. package/docs/schema/storage-and-schema-sql.md +11 -11
  84. package/docs/schema/tables-and-names.md +11 -14
  85. package/docs/sql-semantic-types.md +10 -10
  86. package/docs/troubleshooting.md +10 -10
  87. package/package.json +21 -33
  88. package/skills/qubu/agents/openai.yaml +3 -3
  89. package/dist/column-CXMxx8Hq.mjs +0 -118
  90. package/dist/column-CYMbKbOy.mjs +0 -290
  91. package/dist/drizzle-mysql.d.mts +0 -24
  92. package/dist/drizzle-mysql.mjs +0 -72
  93. package/dist/drizzle-postgres.d.mts +0 -24
  94. package/dist/drizzle-postgres.mjs +0 -73
  95. package/dist/drizzle-sqlite.d.mts +0 -50
  96. package/dist/drizzle-sqlite.mjs +0 -108
  97. package/dist/drizzle.d.mts +0 -13
  98. package/dist/drizzle.mjs +0 -2
  99. package/dist/errors-BGCoLe_r.mjs +0 -14
  100. package/dist/naming-QVCOnSj2.mjs +0 -20
  101. package/dist/postgres-DEBBeh52.mjs +0 -235
  102. package/dist/runtime-Cn_Xgzta.mjs +0 -193
  103. package/dist/sqlite-BU6DBxef.mjs +0 -320
  104. package/dist/types-Ctlxz1ip.d.mts +0 -45
@@ -5,11 +5,11 @@
5
5
 
6
6
  ## Install the optional integration
7
7
 
8
- Install Drizzle next to Qubu. The Drizzle entrypoints use an optional peer
9
- dependency, so importing the rest of Qubu does not load the ORM.
8
+ Install the integration next to Qubu and Drizzle. The `@qubu/drizzle` package
9
+ owns schema conversion; the root `qubu` package does not depend on Drizzle.
10
10
 
11
11
  ```bash
12
- pnpm add qubu drizzle-orm@rc
12
+ pnpm add qubu @qubu/drizzle drizzle-orm@rc
13
13
  ```
14
14
 
15
15
  The converter supports PostgreSQL, MySQL, and SQLite with Drizzle 1.0.0-rc.4
@@ -21,29 +21,29 @@ Declare tables and the root registry with Qubu, then import the converter for
21
21
  your database:
22
22
 
23
23
  ```ts
24
- import { integer, schema, table, text } from 'qubu'
25
- import { toPostgresDrizzleSchema } from 'qubu/drizzle/postgres'
24
+ import { integer, schema, table, text } from "qubu"
25
+ import { toPostgresDrizzleSchema } from "@qubu/drizzle/postgres"
26
26
 
27
- const users = table('user_records', {
27
+ const users = table("user_records", {
28
28
  id: integer({ generated: true }),
29
29
  name: text(),
30
30
  nickname: text({ nullable: true }),
31
31
  })
32
32
 
33
- const appSchema = schema({ users }, { namespace: 'app' })
33
+ const appSchema = schema({ users }, { namespace: "app" })
34
34
  const drizzleTables = toPostgresDrizzleSchema(appSchema)
35
35
  ```
36
36
 
37
37
  The import path selects the dialect. Each module imports only its matching
38
38
  Drizzle core package:
39
39
 
40
- | Database | Import | Converter |
41
- | ---------- | ----------------------- | --------------------------- |
42
- | PostgreSQL | `qubu/drizzle/postgres` | `toPostgresDrizzleSchema()` |
43
- | MySQL | `qubu/drizzle/mysql` | `toMysqlDrizzleSchema()` |
44
- | SQLite | `qubu/drizzle/sqlite` | `toSqliteDrizzleSchema()` |
40
+ | Database | Import | Converter |
41
+ | ---------- | ------------------------ | --------------------------- |
42
+ | PostgreSQL | `@qubu/drizzle/postgres` | `toPostgresDrizzleSchema()` |
43
+ | MySQL | `@qubu/drizzle/mysql` | `toMysqlDrizzleSchema()` |
44
+ | SQLite | `@qubu/drizzle/sqlite` | `toSqliteDrizzleSchema()` |
45
45
 
46
- `qubu/drizzle` exports the shared conversion error and dialect types. It does
46
+ `@qubu/drizzle` exports the shared conversion error and dialect types. It does
47
47
  not import a dialect core or provide a universal runtime converter.
48
48
 
49
49
  `drizzleTables.users` is a real Drizzle `PgTable`. The logical `users` key,
@@ -54,8 +54,8 @@ Use the converted tables in ordinary Drizzle queries. Table objects do not need
54
54
  to be passed to `drizzle()`:
55
55
 
56
56
  ```ts
57
- import { eq } from 'drizzle-orm'
58
- import { drizzle } from 'drizzle-orm/node-postgres'
57
+ import { eq } from "drizzle-orm"
58
+ import { drizzle } from "drizzle-orm/node-postgres"
59
59
 
60
60
  const db = drizzle(pool)
61
61
 
@@ -74,12 +74,12 @@ Use `sqliteTimestamp()` when an existing SQLite schema stores dates as integer
74
74
  Unix timestamps and Drizzle must continue reading and writing `Date` values:
75
75
 
76
76
  ```ts
77
- import { schema, table } from 'qubu'
78
- import { sqliteTimestamp, toSqliteDrizzleSchema } from 'qubu/drizzle/sqlite'
77
+ import { schema, table } from "qubu"
78
+ import { sqliteTimestamp, toSqliteDrizzleSchema } from "@qubu/drizzle/sqlite"
79
79
 
80
- const events = table('events', {
80
+ const events = table("events", {
81
81
  createdAt: sqliteTimestamp({
82
- mode: 'timestamp',
82
+ mode: "timestamp",
83
83
  defaultFn: () => new Date(),
84
84
  }),
85
85
  })
@@ -127,11 +127,11 @@ unique constraints, checks, foreign keys, and indexes. Native storage must
127
127
  belong to the selected dialect:
128
128
 
129
129
  ```ts
130
- import { nativeColumn, schema, table } from 'qubu'
131
- import { toPostgresDrizzleSchema } from 'qubu/drizzle/postgres'
130
+ import { nativeColumn, schema, table } from "qubu"
131
+ import { toPostgresDrizzleSchema } from "@qubu/drizzle/postgres"
132
132
 
133
- const records = table('records', {
134
- handle: nativeColumn('postgresql', 'CITEXT'),
133
+ const records = table("records", {
134
+ handle: nativeColumn("postgresql", "CITEXT"),
135
135
  })
136
136
 
137
137
  const tables = toPostgresDrizzleSchema(schema({ records }))
@@ -8,12 +8,12 @@ identifiers, placeholders, or pagination:
8
8
  The examples assume a query has already been built.
9
9
 
10
10
  ```ts
11
- import { render } from 'qubu'
12
- import { createDialect } from 'qubu/core'
11
+ import { render } from "qubu"
12
+ import { createDialect } from "qubu/core"
13
13
 
14
14
  const colonDialect = createDialect({
15
- name: 'colon',
16
- placeholder: position => ':p' + position,
15
+ name: "colon",
16
+ placeholder: (position) => ":p" + position,
17
17
  })
18
18
 
19
19
  render(query, colonDialect)
@@ -8,18 +8,18 @@ Qubu extensions are ordinary fragments. A custom clause supplies a placement,
8
8
  render order, and renderer:
9
9
 
10
10
  ```ts
11
- import { from, render, select, table, text } from 'qubu'
12
- import { customClause } from 'qubu/core'
11
+ import { from, render, select, table, text } from "qubu"
12
+ import { customClause } from "qubu/core"
13
13
 
14
- const users = table('users', { name: text() })
14
+ const users = table("users", { name: text() })
15
15
 
16
16
  const fetchWithTies = customClause({
17
- name: 'fetch-with-ties',
17
+ name: "fetch-with-ties",
18
18
  order: 100,
19
19
  render(context) {
20
- context.append('FETCH FIRST ')
20
+ context.append("FETCH FIRST ")
21
21
  context.parameter(10)
22
- context.append(' ROWS WITH TIES')
22
+ context.append(" ROWS WITH TIES")
23
23
  },
24
24
  })
25
25
 
@@ -41,23 +41,23 @@ shape is known to the application but cannot be declared with `table()`. Its
41
41
  table, while `from()` or a join supplies the source to the query scope:
42
42
 
43
43
  ```ts
44
- import { from, integer, render, select, text } from 'qubu'
45
- import { identifier } from 'qubu/core'
46
- import { customSource } from 'qubu/schema'
44
+ import { from, integer, render, select, text } from "qubu"
45
+ import { identifier } from "qubu/core"
46
+ import { customSource } from "qubu/schema"
47
47
 
48
48
  const rows = customSource({
49
- identity: { sourceKind: 'table-function', name: 'json_each', alias: 'row' },
50
- sourceKind: 'table-function',
51
- reference: identifier('row'),
49
+ identity: { sourceKind: "table-function", name: "json_each", alias: "row" },
50
+ sourceKind: "table-function",
51
+ reference: identifier("row"),
52
52
  columns: {
53
53
  key: integer(),
54
54
  value: text({ nullable: true }),
55
55
  },
56
56
  render(context) {
57
- context.append('json_each(')
57
+ context.append("json_each(")
58
58
  context.parameter('{"a":1}')
59
- context.append(') AS ')
60
- context.render(identifier('row'))
59
+ context.append(") AS ")
60
+ context.render(identifier("row"))
61
61
  },
62
62
  })
63
63
 
@@ -29,22 +29,18 @@ actually supports. Compatibility groups allow a dialect-specific domain to
29
29
  interoperate with a built-in family:
30
30
 
31
31
  ```ts
32
- import { cast, column } from 'qubu'
33
- import type {
34
- SqlEqualityComparable,
35
- SqlOrderable,
36
- SqlSemanticType,
37
- SqlTextLike,
38
- } from 'qubu'
32
+ import { cast, column } from "qubu"
33
+ import type { SqlEqualityComparable, SqlOrderable, SqlSemanticType, SqlTextLike } from "qubu"
39
34
 
40
35
  interface SqlCitext
41
- extends SqlSemanticType<'postgres.citext'>,
36
+ extends
37
+ SqlSemanticType<"postgres.citext">,
42
38
  SqlTextLike,
43
- SqlOrderable<'text'>,
44
- SqlEqualityComparable<'text'> {}
39
+ SqlOrderable<"text">,
40
+ SqlEqualityComparable<"text"> {}
45
41
 
46
42
  const citext = column<string, string, string, SqlCitext>({
47
- castType: 'CITEXT',
43
+ castType: "CITEXT",
48
44
  })
49
45
 
50
46
  const nameAsCitext = cast(users.name, citext)
@@ -61,13 +57,13 @@ nullability comes from the operand and write flags have no cast meaning.
61
57
  Declare result domains at other extension boundaries too:
62
58
 
63
59
  ```ts
64
- import { typedCall, typedCast, typedValue, unsafeExpression } from 'qubu/core'
65
- import type { SqlText, SqlUuid } from 'qubu'
60
+ import { typedCall, typedCast, typedValue, unsafeExpression } from "qubu/core"
61
+ import type { SqlText, SqlUuid } from "qubu"
66
62
 
67
- const id = typedValue<SqlUuid, string>('108cb836-20d2-41b2-8c23-f0c94700aa7e')
68
- const normalized = typedCall<SqlText, string>()('custom_text', users.name)
69
- const rawNameAsText = typedCast<string, SqlText>()(users.name, 'TEXT')
70
- const generated = unsafeExpression<string, SqlText>('custom_text()')
63
+ const id = typedValue<SqlUuid, string>("108cb836-20d2-41b2-8c23-f0c94700aa7e")
64
+ const normalized = typedCall<SqlText, string>()("custom_text", users.name)
65
+ const rawNameAsText = typedCast<string, SqlText>()(users.name, "TEXT")
66
+ const generated = unsafeExpression<string, SqlText>("custom_text()")
71
67
  ```
72
68
 
73
69
  `typedCall()` preserves source requirements from its arguments. `typedCast()`
@@ -6,11 +6,11 @@
6
6
  modeled yet. They do not quote identifiers or bind values for you:
7
7
 
8
8
  ```ts
9
- import { select } from 'qubu'
10
- import { unsafeExpression } from 'qubu/core'
9
+ import { select } from "qubu"
10
+ import { unsafeExpression } from "qubu/core"
11
11
 
12
12
  const query = select({
13
- today: unsafeExpression('CURRENT_DATE'),
13
+ today: unsafeExpression("CURRENT_DATE"),
14
14
  })
15
15
  ```
16
16
 
@@ -16,9 +16,9 @@ import {
16
16
  jsonText,
17
17
  select,
18
18
  table,
19
- } from 'qubu'
19
+ } from "qubu"
20
20
 
21
- const events = table('events', {
21
+ const events = table("events", {
22
22
  payload: json<{
23
23
  user?: { name?: string; active?: boolean; score?: number }
24
24
  }>(),
@@ -26,12 +26,12 @@ const events = table('events', {
26
26
 
27
27
  const query = select(
28
28
  {
29
- name: jsonText(events.payload, jsonPath('user', 'name')),
30
- active: jsonBoolean(events.payload, jsonPath('user', 'active')),
31
- score: jsonNumber(events.payload, jsonPath('user', 'score')),
32
- hasUser: jsonExists(events.payload, jsonPath('user')),
29
+ name: jsonText(events.payload, jsonPath("user", "name")),
30
+ active: jsonBoolean(events.payload, jsonPath("user", "active")),
31
+ score: jsonNumber(events.payload, jsonPath("user", "score")),
32
+ hasUser: jsonExists(events.payload, jsonPath("user")),
33
33
  },
34
- from(events)
34
+ from(events),
35
35
  )
36
36
  ```
37
37
 
@@ -9,9 +9,9 @@ columns accept `null` as a value, which is distinct from omitting a defaulted
9
9
  field:
10
10
 
11
11
  ```ts
12
- import { integer, table, text } from 'qubu'
12
+ import { integer, table, text } from "qubu"
13
13
 
14
- const users = table('users', {
14
+ const users = table("users", {
15
15
  id: integer({ generated: true }),
16
16
  name: text(),
17
17
  email: text({ nullable: true, hasDefault: true }),
@@ -27,15 +27,12 @@ Pass one or more rows to `values()`. Qubu checks that every row uses the same
27
27
  columns and that required, non-generated fields are present:
28
28
 
29
29
  ```ts
30
- import { insertInto, render, returning, values } from 'qubu'
30
+ import { insertInto, render, returning, values } from "qubu"
31
31
 
32
32
  const query = insertInto(
33
33
  users,
34
- values(
35
- { name: 'Ada', email: null },
36
- { name: 'Grace', email: 'grace@example.com' }
37
- ),
38
- returning({ id: users.id, name: users.name })
34
+ values({ name: "Ada", email: null }, { name: "Grace", email: "grace@example.com" }),
35
+ returning({ id: users.id, name: users.name }),
39
36
  )
40
37
 
41
38
  render(query)
@@ -54,13 +51,13 @@ default. Use `insertSelect(query, columns)` for an `INSERT ... SELECT` source.
54
51
  the target table:
55
52
 
56
53
  ```ts
57
- import { eq, returning, update, upper, where } from 'qubu'
54
+ import { eq, returning, update, upper, where } from "qubu"
58
55
 
59
56
  const query = update(
60
57
  users,
61
58
  { name: upper(users.name) },
62
59
  where(eq(users.id, 7)),
63
- returning({ id: users.id, name: users.name })
60
+ returning({ id: users.id, name: users.name }),
64
61
  )
65
62
  ```
66
63
 
@@ -71,15 +68,15 @@ Use `omit` for a runtime-conditional assignment. Qubu removes omitted fields
71
68
  before validating and rendering the effective assignment set:
72
69
 
73
70
  ```ts
74
- import { eq, omit, update, where } from 'qubu'
71
+ import { eq, omit, update, where } from "qubu"
75
72
 
76
73
  const query = update(
77
74
  users,
78
75
  {
79
- name: rename ? 'Archived' : omit,
76
+ name: rename ? "Archived" : omit,
80
77
  email: clearEmail ? null : omit,
81
78
  },
82
- where(eq(users.id, 7))
79
+ where(eq(users.id, 7)),
83
80
  )
84
81
  ```
85
82
 
@@ -93,13 +90,9 @@ remain source- and capability-aware even when their runtime alternative is
93
90
  ## Delete with a predicate
94
91
 
95
92
  ```ts
96
- import { deleteFrom, eq, returning, where } from 'qubu'
93
+ import { deleteFrom, eq, returning, where } from "qubu"
97
94
 
98
- const query = deleteFrom(
99
- users,
100
- where(eq(users.id, 8)),
101
- returning({ id: users.id })
102
- )
95
+ const query = deleteFrom(users, where(eq(users.id, 8)), returning({ id: users.id }))
103
96
  ```
104
97
 
105
98
  ## Keep unrestricted writes explicit
@@ -108,9 +101,9 @@ Both `UPDATE` and `DELETE` require a `WHERE` clause by default. If an operation
108
101
  really must affect every row, opt in at the call site:
109
102
 
110
103
  ```ts
111
- import { allowAll, update } from 'qubu'
104
+ import { allowAll, update } from "qubu"
112
105
 
113
- const query = update(users, { name: 'Archived' }, allowAll())
106
+ const query = update(users, { name: "Archived" }, allowAll())
114
107
  ```
115
108
 
116
109
  `allowAll()` is a safety boundary, not a replacement for authorization or
@@ -11,14 +11,14 @@ Use `omit` as the other branch of a JavaScript conditional when a `WHERE`,
11
11
  `HAVING`, `ORDER BY`, or `DISTINCT` clause is optional:
12
12
 
13
13
  ```ts
14
- import { eq, from, omit, select, where } from 'qubu'
14
+ import { eq, from, omit, select, where } from "qubu"
15
15
 
16
16
  declare const userId: number | undefined
17
17
 
18
18
  const query = select(
19
19
  { id: users.id, name: users.name },
20
20
  from(users),
21
- userId === undefined ? omit : where(eq(users.id, userId))
21
+ userId === undefined ? omit : where(eq(users.id, userId)),
22
22
  )
23
23
  ```
24
24
 
@@ -29,14 +29,12 @@ Use the same token inside `and()`, `or()`, and `orderBy()` when individual
29
29
  predicates or ordering terms are conditional:
30
30
 
31
31
  ```ts
32
- import { and, desc, eq, omit, orderBy, where } from 'qubu'
32
+ import { and, desc, eq, omit, orderBy, where } from "qubu"
33
33
 
34
34
  declare const includeName: boolean
35
35
  declare const newestFirst: boolean
36
36
 
37
- const filter = where(
38
- and(eq(users.id, 7), includeName ? eq(users.name, 'Ada') : omit)
39
- )
37
+ const filter = where(and(eq(users.id, 7), includeName ? eq(users.name, "Ada") : omit))
40
38
  const ordering = orderBy(newestFirst ? desc(users.name) : omit)
41
39
  ```
42
40
 
@@ -56,7 +54,7 @@ const query = select(
56
54
  id: users.id,
57
55
  email: includeEmail ? users.email : omit,
58
56
  },
59
- from(users)
57
+ from(users),
60
58
  )
61
59
 
62
60
  // typeof query.row:
@@ -82,7 +80,7 @@ separate queries when those structural parts differ at runtime.
82
80
  Equality with `null` is translated to the SQL null predicate:
83
81
 
84
82
  ```ts
85
- import { eq, isDistinctFrom, ne } from 'qubu'
83
+ import { eq, isDistinctFrom, ne } from "qubu"
86
84
 
87
85
  eq(users.name, null) // ... IS NULL
88
86
  ne(users.name, null) // ... IS NOT NULL
@@ -11,18 +11,7 @@ Object projection keys provide stable names for aggregates. Group every
11
11
  non-aggregate column dependency:
12
12
 
13
13
  ```ts
14
- import {
15
- count,
16
- desc,
17
- eq,
18
- from,
19
- groupBy,
20
- gt,
21
- having,
22
- leftJoin,
23
- orderBy,
24
- select,
25
- } from 'qubu'
14
+ import { count, desc, eq, from, groupBy, gt, having, leftJoin, orderBy, select } from "qubu"
26
15
 
27
16
  const counts = select(
28
17
  {
@@ -33,7 +22,7 @@ const counts = select(
33
22
  leftJoin(posts, eq(users.id, posts.authorId)),
34
23
  groupBy(users.name),
35
24
  having(gt(count(posts.id), 0)),
36
- orderBy(desc(count(posts.id)))
25
+ orderBy(desc(count(posts.id))),
37
26
  )
38
27
  ```
39
28
 
@@ -52,7 +41,7 @@ The initial window scope supports `PARTITION BY` and `ORDER BY`; the same
52
41
  `asc()` and `desc()` terms used by a query-level `orderBy()` can be reused:
53
42
 
54
43
  ```ts
55
- import { desc, from, over, rowNumber, select } from 'qubu'
44
+ import { desc, from, over, rowNumber, select } from "qubu"
56
45
 
57
46
  const rankedUsers = select(
58
47
  {
@@ -62,7 +51,7 @@ const rankedUsers = select(
62
51
  orderBy: [desc(users.id)],
63
52
  }),
64
53
  },
65
- from(users)
54
+ from(users),
66
55
  )
67
56
  ```
68
57
 
@@ -9,13 +9,9 @@ The examples use the `users` table from [Build a `SELECT`](overview.md).
9
9
  Wrap ordering terms in `orderBy()`:
10
10
 
11
11
  ```ts
12
- import { desc, from, orderBy, select } from 'qubu'
12
+ import { desc, from, orderBy, select } from "qubu"
13
13
 
14
- const ordered = select(
15
- { id: users.id, name: users.name },
16
- from(users),
17
- orderBy(desc(users.name))
18
- )
14
+ const ordered = select({ id: users.id, name: users.name }, from(users), orderBy(desc(users.name)))
19
15
  ```
20
16
 
21
17
  Use `asc()` or `desc()` for each term. The selected dialect controls the
@@ -26,16 +22,7 @@ identifier quoting and any dialect-specific ordering syntax.
26
22
  Choose `fetchFirst()` or `offset()` for pagination:
27
23
 
28
24
  ```ts
29
- import {
30
- desc,
31
- eq,
32
- fetchFirst,
33
- from,
34
- offset,
35
- orderBy,
36
- select,
37
- where,
38
- } from 'qubu'
25
+ import { desc, eq, fetchFirst, from, offset, orderBy, select, where } from "qubu"
39
26
 
40
27
  const page = select(
41
28
  { id: users.id, name: users.name },
@@ -43,7 +30,7 @@ const page = select(
43
30
  where(eq(users.id, 7)),
44
31
  orderBy(desc(users.name)),
45
32
  offset(20),
46
- fetchFirst(20)
33
+ fetchFirst(20),
47
34
  )
48
35
  ```
49
36
 
@@ -54,14 +41,14 @@ pagination. The active dialect decides whether pagination uses standard
54
41
  Pair a pagination clause with `omit` when the row bound is optional at runtime:
55
42
 
56
43
  ```ts
57
- import { fetchFirst, omit } from 'qubu'
44
+ import { fetchFirst, omit } from "qubu"
58
45
 
59
46
  declare const pageSize: number | undefined
60
47
 
61
48
  const page = select(
62
49
  { id: users.id, name: users.name },
63
50
  from(users),
64
- pageSize === undefined ? omit : fetchFirst(pageSize)
51
+ pageSize === undefined ? omit : fetchFirst(pageSize),
65
52
  )
66
53
  ```
67
54
 
@@ -9,19 +9,15 @@ independent clauses. A source-aware column must be provided by `from()` or a
9
9
  join:
10
10
 
11
11
  ```ts
12
- import { eq, from, integer, render, select, table, text, where } from 'qubu'
12
+ import { eq, from, integer, render, select, table, text, where } from "qubu"
13
13
 
14
- const users = table('users', {
14
+ const users = table("users", {
15
15
  id: integer(),
16
16
  name: text(),
17
17
  email: text({ nullable: true }),
18
18
  })
19
19
 
20
- const query = select(
21
- { id: users.id, name: users.name },
22
- from(users),
23
- where(eq(users.id, 7))
24
- )
20
+ const query = select({ id: users.id, name: users.name }, from(users), where(eq(users.id, 7)))
25
21
 
26
22
  render(query).text
27
23
  // SELECT "users"."id" AS "id", "users"."name" AS "name" FROM "users" WHERE ("users"."id" = ?)
@@ -34,12 +30,9 @@ named projection object, so it can still be spread alongside computed
34
30
  expressions:
35
31
 
36
32
  ```ts
37
- import { all, from, select, upper } from 'qubu'
33
+ import { all, from, select, upper } from "qubu"
38
34
 
39
- const query = select(
40
- { ...all(users), normalizedName: upper(users.name) },
41
- from(users)
42
- )
35
+ const query = select({ ...all(users), normalizedName: upper(users.name) }, from(users))
43
36
  ```
44
37
 
45
38
  `all(source)` expands to explicit named columns rather than emitting
@@ -66,9 +59,9 @@ import {
66
59
  text,
67
60
  integer,
68
61
  where,
69
- } from 'qubu'
62
+ } from "qubu"
70
63
 
71
- const posts = table('posts', {
64
+ const posts = table("posts", {
72
65
  id: integer(),
73
66
  authorId: integer(),
74
67
  title: text(),
@@ -78,7 +71,7 @@ const query = select(
78
71
  { userId: users.id, title: posts.title },
79
72
  from(users),
80
73
  innerJoin(posts, eq(users.id, posts.authorId)),
81
- where(isNotNull(users.email))
74
+ where(isNotNull(users.email)),
82
75
  )
83
76
  ```
84
77
 
@@ -98,7 +91,7 @@ const summary = select(
98
91
  postCount: count(posts.id),
99
92
  },
100
93
  from(users),
101
- leftJoin(posts, eq(users.id, posts.authorId))
94
+ leftJoin(posts, eq(users.id, posts.authorId)),
102
95
  )
103
96
 
104
97
  // typeof summary.row:
@@ -108,18 +101,11 @@ const summary = select(
108
101
  Compose boolean expressions explicitly:
109
102
 
110
103
  ```ts
111
- import { and, gt, inList, or } from 'qubu'
104
+ import { and, gt, inList, or } from "qubu"
112
105
 
113
- const filter = and(
114
- gt(users.id, 0),
115
- or(inList(users.id, [7, 8]), eq(users.name, 'Ada'))
116
- )
106
+ const filter = and(gt(users.id, 0), or(inList(users.id, [7, 8]), eq(users.name, "Ada")))
117
107
 
118
- const filtered = select(
119
- { id: users.id, name: users.name },
120
- from(users),
121
- where(filter)
122
- )
108
+ const filtered = select({ id: users.id, name: users.name }, from(users), where(filter))
123
109
  ```
124
110
 
125
111
  Values such as `7`, `'Ada'`, and list members become parameters. They are not