qubu 0.4.0 → 0.4.2

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 (103) 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-BavBtv8J.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-DH0qV6aS.d.mts → index-1DpA3mUh.d.mts} +20 -20
  15. package/dist/{index-D3ZOwPT-.d.mts → index-CPvfEheG.d.mts} +13 -15
  16. package/dist/index.d.mts +1 -1
  17. package/dist/index.mjs +94 -95
  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-CKEKGnj4.mjs → mysql-B_cYzzX2.mjs} +237 -7
  24. package/dist/mysql.d.mts +2 -2
  25. package/dist/mysql.mjs +3 -3
  26. package/dist/{on-conflict-4MOBl51J.mjs → on-conflict-hfPW0KmQ.mjs} +3 -4
  27. package/dist/postgres.d.mts +5 -5
  28. package/dist/postgres.mjs +6 -6
  29. package/dist/{registry-CXV8u7Pt.mjs → registry-BRMLYwDp.mjs} +26 -29
  30. package/dist/{relational-DuQ9IHSb.mjs → relational-BZ3WDPzC.mjs} +2 -2
  31. package/dist/schema.d.mts +1 -1
  32. package/dist/schema.mjs +5 -6
  33. package/dist/{snapshot-DJpfmxhQ.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-DGO3DRgg.mjs → source-BcS2AsIg.mjs} +6 -8
  37. package/dist/{serialize-CFtYYAdk.mjs → sqlite-Cg0nwYEH.mjs} +326 -12
  38. package/dist/sqlite.d.mts +1 -1
  39. package/dist/sqlite.mjs +2 -2
  40. package/dist/{standard-BTVYKh_F.mjs → standard-DfcZEVOj.mjs} +1 -1
  41. package/dist/{table-D6rcs8SB.mjs → table-Bp5irMSj.mjs} +2 -3
  42. package/dist/{types-Deo_q43Y.d.mts → types-BK1COGZe.d.mts} +1113 -1128
  43. package/dist/{types-g-vVvj1B.mjs → types-JM3FcAnX.mjs} +7 -8
  44. package/dist/{types-CSNJTYaM.d.mts → types-JSZHpUEj.d.mts} +83 -84
  45. package/dist/{value-b6OFZXVS.mjs → value-Bi71Agyf.mjs} +1 -1
  46. package/dist/vite/ambient.d.ts +309 -340
  47. package/dist/vite.d.mts +5 -6
  48. package/dist/vite.mjs +3 -4
  49. package/docs/dialects-and-execution.md +45 -55
  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 +26 -26
  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-D-8OqGuV.mjs +0 -328
  90. package/dist/column-LV7oGQde.mjs +0 -296
  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 -57
  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/postgres-BK2APkKP.mjs +0 -236
  101. package/dist/runtime-Cn_Xgzta.mjs +0 -193
  102. package/dist/sqlite-CrsK0Fza.mjs +0 -320
  103. package/dist/types-DZsueVoI.d.mts +0 -45
package/dist/vite.d.mts CHANGED
@@ -1,9 +1,8 @@
1
1
  //#region src/vite/globals.d.ts
2
2
  /**
3
- * Public runtime names that the `"use qubu"` transform can auto-import.
4
- * Keep this catalog aligned with the ordinary authoring surface of `qubu`;
5
- * fragment internals, dialect construction, and schema extensions belong to
6
- * the layered entrypoints.
3
+ * Public runtime names that the `"use qubu"` transform can auto-import. Keep this catalog aligned
4
+ * with the ordinary authoring surface of `qubu`; fragment internals, dialect construction, and
5
+ * schema extensions belong to the layered entrypoints.
7
6
  */
8
7
  declare const qubuGlobals: readonly ["add", "alias", "all", "allowAll", "and", "asc", "asValue", "avg", "bigint", "between", "binary", "boolean", "call", "caseWhen", "cast", "check", "coalesce", "column", "concat", "count", "countDistinct", "correlate", "crossJoin", "cte", "date", "denseRank", "defaultValues", "deleteFrom", "desc", "distinct", "divide", "eq", "except", "execute", "executeRows", "externalDefault", "externalGeneratedColumn", "exists", "fetchFirst", "fetchNext", "foreignKey", "from", "fullJoin", "generatedColumn", "gt", "gte", "groupBy", "having", "identityColumn", "inList", "inQuery", "index", "innerJoin", "insertInto", "insertSelect", "integer", "intersect", "isDistinctFrom", "isNotDistinctFrom", "isNotNull", "isNull", "isTrue", "json", "jsonBoolean", "jsonExists", "jsonNumber", "jsonPath", "jsonText", "lateral", "leftJoin", "like", "lower", "lt", "lte", "max", "min", "modulo", "multiply", "naturalJoin", "nativeColumn", "nativeStorage", "ne", "not", "notExists", "notIn", "notLike", "nullsFirst", "nullsLast", "numeric", "nullable", "offset", "omit", "or", "order", "orderBy", "over", "portableStorage", "primaryKey", "qubu", "references", "recursiveCte", "render", "returning", "rightJoin", "rank", "rowNumber", "scalar", "schema", "schemaCall", "select", "sql", "stream", "subtract", "sum", "table", "text", "timestamp", "union", "unionAll", "unique", "uniqueConstraint", "update", "upper", "value", "values", "where", "withCte", "uuid"];
9
8
  type QubuGlobal = (typeof qubuGlobals)[number];
@@ -25,8 +24,8 @@ interface QubuViteTransformResult {
25
24
  }
26
25
  /** A Vite-compatible plugin without a runtime dependency on Vite itself. */
27
26
  interface QubuVitePlugin {
28
- readonly name: 'qubu:compiler-hint';
29
- readonly enforce: 'pre';
27
+ readonly name: "qubu:compiler-hint";
28
+ readonly enforce: "pre";
30
29
  transform(code: string, id: string): QubuViteTransformResult | null;
31
30
  }
32
31
  declare function qubu(options?: QubuVitePluginOptions): QubuVitePlugin;
package/dist/vite.mjs CHANGED
@@ -70,10 +70,9 @@ function isWhitespace$1(character) {
70
70
  //#endregion
71
71
  //#region src/vite/globals.ts
72
72
  /**
73
- * Public runtime names that the `"use qubu"` transform can auto-import.
74
- * Keep this catalog aligned with the ordinary authoring surface of `qubu`;
75
- * fragment internals, dialect construction, and schema extensions belong to
76
- * the layered entrypoints.
73
+ * Public runtime names that the `"use qubu"` transform can auto-import. Keep this catalog aligned
74
+ * with the ordinary authoring surface of `qubu`; fragment internals, dialect construction, and
75
+ * schema extensions belong to the layered entrypoints.
77
76
  */
78
77
  const qubuGlobals = [
79
78
  "add",
@@ -20,8 +20,8 @@ Construct the query without choosing a driver, then render it with the policy
20
20
  the adapter expects:
21
21
 
22
22
  ```ts
23
- import { render } from 'qubu'
24
- import { postgresDialect } from 'qubu/postgres'
23
+ import { render } from "qubu"
24
+ import { postgresDialect } from "qubu/postgres"
25
25
 
26
26
  const standard = render(query)
27
27
  const postgres = render(query, postgresDialect())
@@ -40,15 +40,11 @@ capability requirement to the rendering boundary. PostgreSQL's `ilike()` is
40
40
  the first such feature:
41
41
 
42
42
  ```ts
43
- import { from, like, render, select, where } from 'qubu'
44
- import { ilike, postgresDialect } from 'qubu/postgres'
45
- import { sqliteDialect } from 'qubu/sqlite'
43
+ import { from, like, render, select, where } from "qubu"
44
+ import { ilike, postgresDialect } from "qubu/postgres"
45
+ import { sqliteDialect } from "qubu/sqlite"
46
46
 
47
- const postgresQuery = select(
48
- { name: users.name },
49
- from(users),
50
- where(ilike(users.name, '%ada%'))
51
- )
47
+ const postgresQuery = select({ name: users.name }, from(users), where(ilike(users.name, "%ada%")))
52
48
 
53
49
  render(postgresQuery, postgresDialect()) // supported
54
50
  render(postgresQuery, sqliteDialect()) // TypeScript error
@@ -59,14 +55,10 @@ received from an untyped integration. Use the portable operator when the
59
55
  query must render across dialects:
60
56
 
61
57
  ```ts
62
- import { from, like, render, select, where } from 'qubu'
63
- import { sqliteDialect } from 'qubu/sqlite'
58
+ import { from, like, render, select, where } from "qubu"
59
+ import { sqliteDialect } from "qubu/sqlite"
64
60
 
65
- const portableQuery = select(
66
- { name: users.name },
67
- from(users),
68
- where(like(users.name, '%ada%'))
69
- )
61
+ const portableQuery = select({ name: users.name }, from(users), where(like(users.name, "%ada%")))
70
62
 
71
63
  render(portableQuery)
72
64
  render(portableQuery, sqliteDialect())
@@ -88,15 +80,15 @@ to produce the typed `ExecutionResult`. A `TransactionalQueryAdapter` can also
88
80
  pin one driver connection for a callback transaction:
89
81
 
90
82
  ```ts
91
- import { qubu } from 'qubu'
92
- import { postgresDialect } from 'qubu/postgres'
93
- import type { ExecutionRequest, QueryAdapter } from 'qubu'
83
+ import { qubu } from "qubu"
84
+ import { postgresDialect } from "qubu/postgres"
85
+ import type { ExecutionRequest, QueryAdapter } from "qubu"
94
86
 
95
87
  declare const driver: {
96
88
  query<TRow extends object>(
97
89
  text: string,
98
90
  parameters: readonly unknown[],
99
- options: { signal?: AbortSignal }
91
+ options: { signal?: AbortSignal },
100
92
  ): Promise<{ rows: readonly TRow[]; rowCount: number | null }>
101
93
  }
102
94
 
@@ -107,13 +99,11 @@ const adapter: QueryAdapter = {
107
99
  const result = await driver.query<Record<string, unknown>>(
108
100
  statement.text,
109
101
  statement.parameters,
110
- { signal }
102
+ { signal },
111
103
  )
112
104
  return {
113
105
  rows: result.rows,
114
- ...(queryKind !== 'select' &&
115
- queryKind !== 'set' &&
116
- result.rowCount !== null
106
+ ...(queryKind !== "select" && queryKind !== "set" && result.rowCount !== null
117
107
  ? { affectedRows: result.rowCount }
118
108
  : {}),
119
109
  }
@@ -134,9 +124,9 @@ import {
134
124
  dateResultDecoder,
135
125
  jsonTextResultDecoder,
136
126
  timestampResultDecoder,
137
- } from 'qubu'
138
- import type { AdapterExecutionResult, QueryAdapter, RenderedQuery } from 'qubu'
139
- import { sqliteDialect } from 'qubu/sqlite'
127
+ } from "qubu"
128
+ import type { AdapterExecutionResult, QueryAdapter, RenderedQuery } from "qubu"
129
+ import { sqliteDialect } from "qubu/sqlite"
140
130
 
141
131
  declare const sqliteDriver: {
142
132
  execute(statement: RenderedQuery): Promise<AdapterExecutionResult>
@@ -165,10 +155,10 @@ Use a column decoder for a custom stored type, or `mapResult()` for one
165
155
  expression. Both override adapter policy for that field:
166
156
 
167
157
  ```ts
168
- import { column, mapResult, value } from 'qubu'
158
+ import { column, mapResult, value } from "qubu"
169
159
 
170
- const score = column<number>({ decode: value => Number(value) })
171
- const decodedTotal = mapResult(value('42'), value => Number(value))
160
+ const score = column<number>({ decode: (value) => Number(value) })
161
+ const decodedTotal = mapResult(value("42"), (value) => Number(value))
172
162
  ```
173
163
 
174
164
  ## Stream read results
@@ -180,20 +170,20 @@ Mutations stay on `execute()` and `executeRows()`, including mutations with
180
170
  `RETURNING`.
181
171
 
182
172
  ```ts
183
- import { qubu } from 'qubu'
184
- import type { ExecutionRequest, StreamingQueryAdapter } from 'qubu'
185
- import { postgresDialect } from 'qubu/postgres'
173
+ import { qubu } from "qubu"
174
+ import type { ExecutionRequest, StreamingQueryAdapter } from "qubu"
175
+ import { postgresDialect } from "qubu/postgres"
186
176
 
187
177
  declare const driver: {
188
178
  query<TRow extends object>(
189
179
  text: string,
190
180
  parameters: readonly unknown[],
191
- options: { signal?: AbortSignal }
181
+ options: { signal?: AbortSignal },
192
182
  ): Promise<{ rows: readonly TRow[]; rowCount: number | null }>
193
183
  stream<TRow extends object>(
194
184
  text: string,
195
185
  parameters: readonly unknown[],
196
- options: { signal?: AbortSignal }
186
+ options: { signal?: AbortSignal },
197
187
  ): AsyncIterable<TRow>
198
188
  }
199
189
 
@@ -203,7 +193,7 @@ const adapter: StreamingQueryAdapter = {
203
193
  const result = await driver.query<Record<string, unknown>>(
204
194
  request.statement.text,
205
195
  request.statement.parameters,
206
- { signal: request.signal }
196
+ { signal: request.signal },
207
197
  )
208
198
  return {
209
199
  rows: result.rows,
@@ -214,7 +204,7 @@ const adapter: StreamingQueryAdapter = {
214
204
  return driver.stream<Record<string, unknown>>(
215
205
  request.statement.text,
216
206
  request.statement.parameters,
217
- { signal: request.signal }
207
+ { signal: request.signal },
218
208
  )
219
209
  },
220
210
  }
@@ -259,10 +249,10 @@ transaction callback receives a streaming client. The adapter must keep its
259
249
  cursor and connection valid until the callback's streams finish or close:
260
250
 
261
251
  ```ts
262
- declare const transactionalAdapter: import('qubu').StreamingTransactionalQueryAdapter
252
+ declare const transactionalAdapter: import("qubu").StreamingTransactionalQueryAdapter
263
253
  const transactionalDb = qubu(transactionalAdapter)
264
254
 
265
- await transactionalDb.transaction(async transaction => {
255
+ await transactionalDb.transaction(async (transaction) => {
266
256
  for await (const row of transaction.stream(readQuery)) {
267
257
  consume(row)
268
258
  }
@@ -281,17 +271,17 @@ standalone `explain()` function and the bound `db.explain()` method render a
281
271
  plan request without calling `execute()`:
282
272
 
283
273
  ```ts
284
- import { explain, qubu } from 'qubu'
285
- import type { ExplainableQueryAdapter } from 'qubu'
286
- import { postgresDialect } from 'qubu/postgres'
274
+ import { explain, qubu } from "qubu"
275
+ import type { ExplainableQueryAdapter } from "qubu"
276
+ import { postgresDialect } from "qubu/postgres"
287
277
 
288
- type PostgresPlanRow = { 'QUERY PLAN': string }
278
+ type PostgresPlanRow = { "QUERY PLAN": string }
289
279
 
290
280
  declare const driver: {
291
281
  query<TRow extends object>(
292
282
  text: string,
293
283
  parameters: readonly unknown[],
294
- options: { signal?: AbortSignal }
284
+ options: { signal?: AbortSignal },
295
285
  ): Promise<{ rows: readonly TRow[] }>
296
286
  }
297
287
 
@@ -304,7 +294,7 @@ const adapter: ExplainableQueryAdapter<PostgresPlanRow> = {
304
294
  const result = await driver.query<PostgresPlanRow>(
305
295
  request.statement.text,
306
296
  request.statement.parameters,
307
- { signal: request.signal }
297
+ { signal: request.signal },
308
298
  )
309
299
  return { rows: result.rows }
310
300
  },
@@ -369,13 +359,13 @@ Use a transactional adapter when several queries must share one commit or
369
359
  rollback boundary:
370
360
 
371
361
  ```ts
372
- import { qubu } from 'qubu'
373
- import type { TransactionalQueryAdapter } from 'qubu'
362
+ import { qubu } from "qubu"
363
+ import type { TransactionalQueryAdapter } from "qubu"
374
364
 
375
365
  declare const transactionalAdapter: TransactionalQueryAdapter
376
366
  const transactionalDb = qubu(transactionalAdapter)
377
367
 
378
- const result = await transactionalDb.transaction(async transaction => {
368
+ const result = await transactionalDb.transaction(async (transaction) => {
379
369
  await transaction.execute(firstMutation)
380
370
  await transaction.execute(secondMutation)
381
371
  return transaction.rows(readQuery)
@@ -400,7 +390,7 @@ The standalone functions remain useful when the adapter varies by call or a
400
390
  small module does not need a bound client:
401
391
 
402
392
  ```ts
403
- import { execute, executeRows } from 'qubu'
393
+ import { execute, executeRows } from "qubu"
404
394
 
405
395
  const result = await execute(query, adapter)
406
396
  const rows = await executeRows(readQuery, adapter)
@@ -449,13 +439,13 @@ Use `createDialect()` when a driver needs a different policy but the query
449
439
  syntax stays portable:
450
440
 
451
441
  ```ts
452
- import { render } from 'qubu'
453
- import { createDialect } from 'qubu/core'
442
+ import { render } from "qubu"
443
+ import { createDialect } from "qubu/core"
454
444
 
455
445
  const namedParameters = createDialect({
456
- name: 'named-parameters',
457
- placeholder: position => `:p${position}`,
458
- castTypes: { text: 'STRING' },
446
+ name: "named-parameters",
447
+ placeholder: (position) => `:p${position}`,
448
+ castTypes: { text: "STRING" },
459
449
  })
460
450
 
461
451
  const statement = render(query, namedParameters)
@@ -24,9 +24,9 @@ Use `table()` once for each query-facing table. Column helpers describe the
24
24
  application values that can be selected and, for mutations, written.
25
25
 
26
26
  ```ts
27
- import { integer, table, text } from 'qubu'
27
+ import { integer, table, text } from "qubu"
28
28
 
29
- const users = table('users', {
29
+ const users = table("users", {
30
30
  id: integer(),
31
31
  name: text(),
32
32
  email: text({ nullable: true }),
@@ -44,7 +44,7 @@ it, then renders the normalized statement in SQL order. The example uses the
44
44
  `users` table from the previous section.
45
45
 
46
46
  ```ts
47
- import { eq, from, render, select, where } from 'qubu'
47
+ import { eq, from, render, select, where } from "qubu"
48
48
 
49
49
  const query = select(
50
50
  {
@@ -52,7 +52,7 @@ const query = select(
52
52
  displayName: users.name,
53
53
  },
54
54
  from(users),
55
- where(eq(users.id, 7))
55
+ where(eq(users.id, 7)),
56
56
  )
57
57
 
58
58
  const statement = render(query)
@@ -0,0 +1,57 @@
1
+ # Better Auth
2
+
3
+ > Derive Qubu-owned auth tables and run Better Auth through a transactional Qubu client.
4
+
5
+ Install the integration next to Qubu and Better Auth:
6
+
7
+ ```sh
8
+ pnpm add qubu @qubu/better-auth better-auth
9
+ ```
10
+
11
+ Define the Better Auth options once. The schema derivation reads Better Auth's
12
+ resolved public metadata, so core tables, renamed models and fields, additional
13
+ fields, plugin tables, references, unique constraints, and compound indexes all
14
+ participate.
15
+
16
+ ```ts
17
+ import { betterAuth } from "better-auth"
18
+ import type { BetterAuthOptions } from "better-auth/types"
19
+ import { twoFactor } from "better-auth/plugins"
20
+ import { betterAuthSchema, qubuAdapter } from "@qubu/better-auth"
21
+ import { qubu } from "qubu"
22
+ import { pgAdapter } from "@qubu/adapter-pg"
23
+
24
+ const options = {
25
+ user: {
26
+ modelName: "auth_users",
27
+ additionalFields: {
28
+ locale: { type: "string", required: false },
29
+ },
30
+ },
31
+ plugins: [twoFactor()],
32
+ } satisfies BetterAuthOptions
33
+
34
+ const authSchema = betterAuthSchema(options, "postgresql")
35
+ const db = qubu(pgAdapter(pool))
36
+
37
+ export const auth = betterAuth({
38
+ ...options,
39
+ database: qubuAdapter(db, { schema: authSchema }),
40
+ })
41
+ ```
42
+
43
+ `authSchema` is an ordinary Qubu `Schema`. Hand it to Qubu snapshot, diff,
44
+ migration-plan, and DDL workflows. The adapter's Better Auth `createSchema`
45
+ hook emits a TypeScript module that reconstructs the same Qubu-owned metadata.
46
+
47
+ The package never imports PostgreSQL, MySQL, or SQLite drivers. It executes
48
+ through Qubu's query and transaction boundaries. PostgreSQL and SQLite use one
49
+ limited mutation statement for atomic consume and guarded increment operations;
50
+ MySQL locks one selected row inside the Qubu-owned transaction. A client without
51
+ transaction support, or a dialect other than PostgreSQL, MySQL, or SQLite, is
52
+ rejected during adapter construction.
53
+
54
+ Better Auth enum metadata is currently rejected because Qubu cannot preserve
55
+ the closed value set as a portable column without adding a database constraint.
56
+ The error includes the model and field path instead of silently widening it to
57
+ text.
@@ -8,37 +8,19 @@
8
8
  Attach it with `withCte()` and use the CTE source in `from()`:
9
9
 
10
10
  ```ts
11
- import {
12
- cte,
13
- eq,
14
- from,
15
- integer,
16
- select,
17
- table,
18
- text,
19
- where,
20
- withCte,
21
- } from 'qubu'
22
-
23
- const users = table('users', {
11
+ import { cte, eq, from, integer, select, table, text, where, withCte } from "qubu"
12
+
13
+ const users = table("users", {
24
14
  id: integer(),
25
15
  name: text(),
26
16
  })
27
17
 
28
18
  const activeUsers = cte(
29
- 'active_users',
30
- select(
31
- { id: users.id, name: users.name },
32
- from(users),
33
- where(eq(users.id, 7))
34
- )
19
+ "active_users",
20
+ select({ id: users.id, name: users.name }, from(users), where(eq(users.id, 7))),
35
21
  )
36
22
 
37
- const report = select(
38
- { displayName: activeUsers.name },
39
- withCte(activeUsers),
40
- from(activeUsers)
41
- )
23
+ const report = select({ displayName: activeUsers.name }, withCte(activeUsers), from(activeUsers))
42
24
  ```
43
25
 
44
26
  `activeUsers.name` is a typed column derived from the first query's row shape.
@@ -53,24 +35,10 @@ member. The callback receives a typed self-reference; introduce it through
53
35
  `from()` or a join before selecting its fields:
54
36
 
55
37
  ```ts
56
- import {
57
- add,
58
- cast,
59
- from,
60
- integer,
61
- lt,
62
- recursiveCte,
63
- select,
64
- value,
65
- where,
66
- withCte,
67
- } from 'qubu'
68
-
69
- const numbers = recursiveCte(
70
- 'numbers',
71
- select({ value: cast(value(1), integer()) }),
72
- self =>
73
- select({ value: add(self.value, 1) }, from(self), where(lt(self.value, 3)))
38
+ import { add, cast, from, integer, lt, recursiveCte, select, value, where, withCte } from "qubu"
39
+
40
+ const numbers = recursiveCte("numbers", select({ value: cast(value(1), integer()) }), (self) =>
41
+ select({ value: add(self.value, 1) }, from(self), where(lt(self.value, 3))),
74
42
  )
75
43
 
76
44
  const query = select({ value: numbers.value }, withCte(numbers), from(numbers))
@@ -89,11 +57,11 @@ recursive CTEs can share one `withCte()` clause.
89
57
  Alias a query when it should be used as an inline source:
90
58
 
91
59
  ```ts
92
- import { alias, from, lower, select } from 'qubu'
93
- import type { SqlTypeOf } from 'qubu'
60
+ import { alias, from, lower, select } from "qubu"
61
+ import type { SqlTypeOf } from "qubu"
94
62
 
95
63
  const names = select({ name: lower(users.name) }, from(users))
96
- const namesSource = alias(names, 'names')
64
+ const namesSource = alias(names, "names")
97
65
 
98
66
  const query = select({ name: namesSource.name }, from(namesSource))
99
67
  type NameSqlDomain = SqlTypeOf<typeof namesSource.name>
@@ -112,7 +80,7 @@ so downstream text operations remain checked without redeclaring the field.
112
80
  `scalar()` turns a query with exactly one selected field into an expression:
113
81
 
114
82
  ```ts
115
- import { from, scalar, select, value } from 'qubu'
83
+ import { from, scalar, select, value } from "qubu"
116
84
 
117
85
  const firstId = select({ id: users.id }, from(users))
118
86
  const query = select(
@@ -120,7 +88,7 @@ const query = select(
120
88
  name: users.name,
121
89
  firstId: scalar(firstId),
122
90
  },
123
- from(users)
91
+ from(users),
124
92
  )
125
93
  ```
126
94
 
@@ -139,7 +107,7 @@ Set operations preserve the left query's row shape. Both queries must select
139
107
  compatible rows:
140
108
 
141
109
  ```ts
142
- import { eq, from, select, unionAll, where } from 'qubu'
110
+ import { eq, from, select, unionAll, where } from "qubu"
143
111
 
144
112
  const first = select({ id: users.id }, from(users))
145
113
  const second = select({ id: users.id }, from(users), where(eq(users.id, 7)))
@@ -156,17 +124,12 @@ are collected in traversal order.
156
124
  Build reusable pieces as ordinary values and pass them into the final query:
157
125
 
158
126
  ```ts
159
- import { desc, eq, from, orderBy, select, where } from 'qubu'
127
+ import { desc, eq, from, orderBy, select, where } from "qubu"
160
128
 
161
129
  const byId = where(eq(users.id, 7))
162
130
  const newest = orderBy(desc(users.id))
163
131
 
164
- const query = select(
165
- { id: users.id, name: users.name },
166
- from(users),
167
- byId,
168
- newest
169
- )
132
+ const query = select({ id: users.id, name: users.name }, from(users), byId, newest)
170
133
  ```
171
134
 
172
135
  This makes it possible to share a predicate or projection without mutating a
@@ -185,13 +148,10 @@ generic function retains its exact source identity.
185
148
  For an application-level requirement, describe the required JavaScript row:
186
149
 
187
150
  ```ts
188
- import { eq, where } from 'qubu'
189
- import type { TableLike } from 'qubu'
151
+ import { eq, where } from "qubu"
152
+ import type { TableLike } from "qubu"
190
153
 
191
- function byStringId<TTable extends TableLike<{ id: string }>>(
192
- table: TTable,
193
- id: string
194
- ) {
154
+ function byStringId<TTable extends TableLike<{ id: string }>>(table: TTable, id: string) {
195
155
  return where(eq(table.columns.id, id))
196
156
  }
197
157
  ```
@@ -203,18 +163,15 @@ extra fields and rejects `string | null`, but it does not distinguish
203
163
  Use `FieldLike` when the fragment depends on SQL semantics:
204
164
 
205
165
  ```ts
206
- import { eq, where } from 'qubu'
207
- import type { FieldLike, SourceLike, SqlTextLike } from 'qubu'
166
+ import { eq, where } from "qubu"
167
+ import type { FieldLike, SourceLike, SqlTextLike } from "qubu"
208
168
 
209
169
  type NonNullTextId = FieldLike<{
210
170
  sqlType: SqlTextLike
211
171
  nullable: false
212
172
  }>
213
173
 
214
- function byTextId<TSource extends SourceLike<{ id: NonNullTextId }>>(
215
- source: TSource,
216
- id: string
217
- ) {
174
+ function byTextId<TSource extends SourceLike<{ id: NonNullTextId }>>(source: TSource, id: string) {
218
175
  return where(eq(source.columns.id, id))
219
176
  }
220
177
  ```
@@ -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)