qubu 0.6.2 → 0.6.3

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 (50) hide show
  1. package/dist/mysql.d.mts +1 -1
  2. package/dist/postgres.d.mts +1 -1
  3. package/docs/dialects-and-execution.md +54 -25
  4. package/docs/getting-started.md +9 -9
  5. package/docs/guides/better-auth.md +16 -5
  6. package/docs/guides/compose-queries.md +21 -9
  7. package/docs/guides/drizzle.md +8 -3
  8. package/docs/guides/extensions/dialects.md +1 -1
  9. package/docs/guides/extensions/overview.md +1 -1
  10. package/docs/guides/extensions/sources-and-clauses.md +7 -3
  11. package/docs/guides/extensions/typed-expressions.md +25 -13
  12. package/docs/guides/extensions/unsafe-syntax.md +10 -6
  13. package/docs/guides/json.md +52 -27
  14. package/docs/guides/mutations.md +15 -6
  15. package/docs/guides/select/conditions.md +18 -11
  16. package/docs/guides/select/grouping-and-windows.md +5 -2
  17. package/docs/guides/select/ordering-and-pagination.md +5 -3
  18. package/docs/guides/select/overview.md +6 -3
  19. package/docs/guides/sql-templates.md +11 -5
  20. package/docs/guides/valtio-sync.md +11 -5
  21. package/docs/guides/vite-plugin.md +2 -2
  22. package/docs/index.md +24 -17
  23. package/docs/migrations/adapters.md +47 -19
  24. package/docs/migrations/artifacts-and-policy.md +49 -20
  25. package/docs/migrations/index.md +15 -8
  26. package/docs/migrations/lotta-adoption.md +16 -5
  27. package/docs/migrations/operations.md +29 -15
  28. package/docs/migrations/recovery.md +34 -17
  29. package/docs/query-model/fragments.md +13 -5
  30. package/docs/query-model/result-shapes.md +2 -2
  31. package/docs/query-model/source-scope.md +5 -3
  32. package/docs/reference/introspection-support.md +26 -19
  33. package/docs/reference/mysql-snapshot.md +19 -4
  34. package/docs/reference/postgres-snapshot.md +17 -4
  35. package/docs/reference/sqlite-snapshot.md +19 -2
  36. package/docs/reference/supported-surface.md +221 -85
  37. package/docs/schema/catalog-model.md +24 -7
  38. package/docs/schema/code-generation.md +40 -21
  39. package/docs/schema/columns-and-writes.md +21 -11
  40. package/docs/schema/constraints-and-indexes.md +12 -5
  41. package/docs/schema/ddl-emission.md +16 -5
  42. package/docs/schema/diff.md +12 -4
  43. package/docs/schema/introspection.md +47 -21
  44. package/docs/schema/migration-plans.md +18 -10
  45. package/docs/schema/snapshots.md +57 -29
  46. package/docs/schema/storage-and-schema-sql.md +10 -4
  47. package/docs/schema/tables-and-names.md +1 -1
  48. package/docs/sql-semantic-types.md +11 -8
  49. package/docs/troubleshooting.md +14 -6
  50. package/package.json +1 -1
@@ -60,9 +60,11 @@ each item a stable application name in the constraints or indexes record. The
60
60
  record key becomes `constraint.id` or `index.id`. Qubu resolves `physicalName` from
61
61
  the explicit option or the version-one snake_case policy.
62
62
 
63
- Index terms may use `asc()` or `desc()`. Set `unique: true` for a unique index,
64
- `where` for a partial index, and `include` for columns stored in the index payload but not
65
- used as key terms.
63
+ Index terms may use `asc()` or `desc()`. Set these options as needed:
64
+
65
+ - `unique: true` creates a unique index.
66
+ - `where` supplies a partial-index predicate.
67
+ - `include` lists columns stored in the index payload but not used as key terms.
66
68
 
67
69
  ## Distinguish candidate keys from unique constraints
68
70
 
@@ -100,8 +102,11 @@ same length and matching known `SqlSemanticType` identities. `SqlUnknown` cannot
100
102
  prove a foreign-key match.
101
103
 
102
104
  The target tuple must exactly match a primary key, unique() constraint, or
103
- eligible unique index. Options such as onUpdate, onDelete, match, deferrable,
104
- and initially remain metadata:
105
+ eligible unique index. These options record database behavior as metadata:
106
+
107
+ - `onUpdate` and `onDelete`.
108
+ - `match`.
109
+ - `deferrable` and `initially`.
105
110
 
106
111
  ```ts
107
112
  const memberships = table("memberships", { accountId: integer() }, (memberships) => ({
@@ -118,6 +123,8 @@ const memberships = table("memberships", { accountId: integer() }, (memberships)
118
123
  Use the preliminary callback table for direct self-references. Wrap the target
119
124
  in a function when two modules import each other's tables.
120
125
 
126
+ ### Restrictions on schema expressions
127
+
121
128
  Checks, index expressions, and partial-index predicates may read only columns
122
129
  from their callback table. They cannot contain aggregates, window functions, or
123
130
  subqueries. Check expressions and partial predicates must have the boolean SQL
@@ -1,6 +1,6 @@
1
1
  # DDL emission
2
2
 
3
- > Preview deterministic SQL from a migration plan without confusing preview policy with a sealed executable program.
3
+ > Preview the SQL for a migration plan before preparing it for execution.
4
4
 
5
5
  The `@qubu/migrate/ddl` entrypoint accepts only a `MigrationPlan` and a `SchemaDialect`.
6
6
  It does not read a catalog, open a connection, start a transaction, or write a
@@ -22,8 +22,13 @@ for (const statement of result.statements) {
22
22
  }
23
23
  ```
24
24
 
25
- `statements` is a deterministic preview surface. Each statement carries its
26
- operation ID, topological position, SQL text, and an ordered parameter list.
25
+ `statements` contains the SQL preview in dependency order. Each statement has:
26
+
27
+ - Its operation ID.
28
+ - Its position in that order.
29
+ - SQL text.
30
+ - An ordered parameter list.
31
+
27
32
  Schema literals and expressions are parameter-free by contract. `sql` joins
28
33
  the statements with a newline and adds a semicolon for migration-file writers.
29
34
 
@@ -31,12 +36,16 @@ the statements with a newline and adds a semicolon for migration-file writers.
31
36
 
32
37
  The emitter rejects a plan with `ready: false`, `decision-required` operations,
33
38
  unknown or lossy facts, unsupported safety, or destructive changes unless the
34
- caller supplies the matching explicit option. `allowUnsafe` is available for
39
+ caller supplies the matching explicit option.
40
+
41
+ `allowUnsafe` is available for
35
42
  preview integrations, but it is not accepted as an artifact approval and does
36
43
  not make an opaque object renderable. Opaque and deferred catalog records need
37
44
  an explicit tagged `custom-sql` operation for preview and an operation-scoped
38
45
  custom program for sealed execution.
39
46
 
47
+ ### Check execution requirements
48
+
40
49
  Lock and transaction requirements describe what a later executor must provide.
41
50
  Pass `lock` or `transaction` to preflight those requirements against the
42
51
  executor's context. A required transaction with `transaction: 'autocommit'`
@@ -74,7 +83,9 @@ an inline constraint declaration or an explicit rebuild/custom-SQL operation.
74
83
  Custom SQL stays opaque and appears at its plan position. The emitter does not
75
84
  inspect it for object names or infer SQL from an opaque catalog record.
76
85
 
77
- For execution, lower the plan with `compileMigrationProgram()` from
86
+ ## Prepare for execution
87
+
88
+ For execution, compile the plan with `compileMigrationProgram()` from
78
89
  `@qubu/migrate/artifact`. The versioned program—not the aggregate `sql`
79
90
  string—is authoritative. See [Artifacts and approval
80
91
  policy](../migrations/artifacts-and-policy.md).
@@ -1,11 +1,15 @@
1
1
  # Snapshot diffing
2
2
 
3
- > Compare canonical Snapshot v1 values and review identity changes before a later planning step.
3
+ > Compare two snapshots and review changes before planning a migration.
4
4
 
5
5
  The optional `qubu/diff` entrypoint compares immutable snapshot data. It does
6
- not open a connection, render SQL, execute a change, or infer migration history.
7
- It keeps the object kind, namespace, logical ID, physical name, dialect, path,
8
- and catalog evidence on every result object.
6
+ not access a database or execute changes. Each result keeps the information
7
+ needed to review it:
8
+
9
+ - Object kind and namespace.
10
+ - Logical ID and physical name.
11
+ - Dialect and path.
12
+ - Catalog evidence.
9
13
 
10
14
  ```ts
11
15
  import { diffSnapshots } from "qubu/diff"
@@ -17,6 +21,8 @@ for (const change of result.changes) {
17
21
  }
18
22
  ```
19
23
 
24
+ ## How objects are matched
25
+
20
26
  The matcher first uses an explicit rename hint, then a stable logical ID. A
21
27
  physical-name change for a stable match is a `physical-rename` operation. Other
22
28
  matched fields become `property-change` operations. Unmatched records remain
@@ -61,6 +67,8 @@ classification. Opaque and deferred Snapshot v1 records remain visible as
61
67
  `add` or `remove` data and produce `lossy` or `unsupported` diagnostics. They
62
68
  cannot be silently promoted to a rename.
63
69
 
70
+ ### Equality and ordering
71
+
64
72
  `result.equal` means that no diff operation was emitted. A result can therefore
65
73
  be equal while still carrying a warning about an unchanged opaque record. The
66
74
  diagnostics remain part of the review boundary.
@@ -1,12 +1,16 @@
1
1
  # Database introspection
2
2
 
3
- > Read one existing database namespace into explainable catalog data and a canonical Snapshot v1 without giving Qubu ownership of the connection.
3
+ > Read an existing database schema and turn it into a Qubu snapshot.
4
4
 
5
5
  Database introspection is an optional capability exported from
6
6
  `qubu/introspection`. It discovers database facts; it does not recreate the
7
- original TypeScript declarations. Planning and DDL emission use the separate
7
+ original TypeScript declarations.
8
+
9
+ Planning and DDL emission use the separate
8
10
  `@qubu/migrate/plan` and `@qubu/migrate/ddl` entrypoints, while migration
9
- execution remains application-owned. The separate
11
+ execution remains application-owned.
12
+
13
+ The separate
10
14
  `qubu/codegen` entrypoint can create a new machine-owned schema module from a
11
15
  complete Snapshot v1 result.
12
16
 
@@ -32,9 +36,12 @@ continuity, and strict versus lossy output.
32
36
 
33
37
  ## Supply a connection
34
38
 
35
- Qubu does not open or close a connection, select a driver, manage a pool, retry
36
- queries, authenticate, or start a transaction. Adapt the driver you already
37
- use to `CatalogConnection`:
39
+ Adapt your existing driver to `CatalogConnection`. Your application handles:
40
+
41
+ - Opening and closing connections.
42
+ - Driver selection and connection pools.
43
+ - Authentication.
44
+ - Retries and transactions.
38
45
 
39
46
  ```ts
40
47
  import type { CatalogConnection } from "qubu/introspection"
@@ -127,6 +134,8 @@ generated expressions, checks, predicates, and expression index terms remain
127
134
  dialect-tagged SQL. Falsy values such as `0`, `false`, `NULL`, and empty
128
135
  strings are preserved.
129
136
 
137
+ ### References and dialect metadata
138
+
130
139
  References to nested columns, constraints, and indexes include their owning
131
140
  table, view, or domain in the complete Snapshot v1 output. References to
132
141
  top-level objects remain unscoped, and table-local backing relationships must
@@ -135,21 +144,34 @@ native storage, and typed expressions are checked against the selected
135
144
  snapshot dialect; arbitrary catalog `data` and `configuration` JSON remains
136
145
  opaque.
137
146
 
138
- PostgreSQL readers expose views, materialized views, sequences, enums, domains,
139
- collations, routines, triggers, policies, partitions, extensions, comments,
140
- and ownership as typed complete catalog records. `mapCatalogToCompleteSnapshot`
141
- retains those records in Snapshot v1. `mapCatalogToSnapshot()` uses the same
142
- complete mapping and does not fabricate these objects into tables. If a
143
- PostgreSQL catalog row lacks the evidence needed for
144
- safe normalization, the reader retains a deferred or opaque record and emits a
145
- diagnostic.
147
+ ## PostgreSQL catalog support
148
+
149
+ PostgreSQL readers expose typed catalog records for:
150
+
151
+ - Views and materialized views.
152
+ - Sequences, enums, and domains.
153
+ - Collations.
154
+ - Routines and triggers.
155
+ - Policies and partitions.
156
+ - Extensions.
157
+ - Comments and ownership.
158
+
159
+ `mapCatalogToCompleteSnapshot()` retains those records in Snapshot v1.
160
+ `mapCatalogToSnapshot()` uses the same complete mapping and keeps each object
161
+ as its own kind.
162
+
163
+ If a PostgreSQL catalog row lacks the evidence needed for safe normalization,
164
+ the reader retains a deferred or opaque record and emits a diagnostic.
165
+
166
+ ## SQLite catalog support
146
167
 
147
168
  SQLite readers expose recoverable views and triggers as typed complete records.
148
169
  They retain virtual and shadow tables as deferred objects, and keep attached
149
170
  databases outside the selected namespace as opaque boundary records. SQLite
150
171
  declared types, derived affinity, generated expressions, rowid identity, and
151
- `AUTOINCREMENT` stay tagged with SQLite dialect metadata. When an attached
152
- database is selected, table PRAGMAs may be visible but CREATE SQL remains
172
+ `AUTOINCREMENT` stay tagged with SQLite dialect metadata.
173
+
174
+ When an attached database is selected, table PRAGMAs may be visible but CREATE SQL remains
153
175
  limited to the fixed `main` and `temp` catalog statements, so the reader marks
154
176
  the catalog visibility as limited instead of combining namespaces.
155
177
 
@@ -191,11 +213,15 @@ MySQL families and their opaque or deferred boundaries.
191
213
 
192
214
  ## Diagnostics and safety
193
215
 
194
- Diagnostics include a severity, stable code, catalog path, physical reference
195
- when available, and a remediation hint. They distinguish connection/query
196
- failures, permission limits, unsupported products or versions, unresolved
197
- references, expression recovery failures, unmodeled objects, and lossy
198
- mappings.
216
+ Each diagnostic includes:
217
+
218
+ - Severity and a stable code.
219
+ - A catalog path.
220
+ - A physical reference, when available.
221
+ - A hint for fixing the problem.
222
+
223
+ Codes distinguish connection failures and permission limits from unsupported
224
+ features or incomplete mappings.
199
225
 
200
226
  Introspection is read-only from Qubu's perspective. Do not pass credentials or
201
227
  DSNs through diagnostic fields. Keep driver-specific error text in the
@@ -1,11 +1,16 @@
1
1
  # Migration plans
2
2
 
3
- > Describe reviewed snapshot changes as deterministic data before selecting a DDL emitter.
3
+ > Turn a reviewed schema diff into an ordered migration plan.
4
4
 
5
- The `@qubu/migrate/plan` entrypoint consumes a resolved `SnapshotDiff` and
6
- returns an immutable migration-plan IR. It contains operation IDs, paths,
7
- logical and physical identity evidence, dependency edges, preconditions, safety,
8
- lock and transaction requirements, and reversibility markers.
5
+ The `@qubu/migrate/plan` entrypoint takes a resolved `SnapshotDiff` and returns
6
+ an immutable plan. Each operation records:
7
+
8
+ - Its ID and path.
9
+ - Evidence for logical and physical identities.
10
+ - Dependencies and preconditions.
11
+ - Safety classification.
12
+ - Lock and transaction requirements.
13
+ - Whether the change can be reversed.
9
14
 
10
15
  ```ts
11
16
  import { createMigrationPlan } from "@qubu/migrate/plan"
@@ -16,8 +21,9 @@ if (!result.ok) {
16
21
  }
17
22
  ```
18
23
 
19
- Creation is pure. The planner does not open a connection, execute a transaction,
20
- render SQL, or create migration history. A physical rename remains a
24
+ The planner only returns data. It does not access the database or render SQL.
25
+
26
+ A physical rename remains a
21
27
  `physical-rename` operation; it is never represented as custom SQL or silently
22
28
  changed into a drop and add.
23
29
 
@@ -64,9 +70,11 @@ extracts SQL from opaque catalog payloads.
64
70
 
65
71
  ## Ordering and validation
66
72
 
67
- Parent creation precedes child creation, while child removal precedes parent
68
- removal. Reference edges and explicit custom-SQL dependencies are included in
69
- the stable topological ordering. `encodeMigrationPlan()` emits canonical JSON;
73
+ The planner creates parents before children and removes children before
74
+ parents. It also orders operations by their references and explicit custom-SQL
75
+ dependencies. The same inputs produce the same order.
76
+
77
+ `encodeMigrationPlan()` emits canonical JSON;
70
78
  `decodeMigrationPlan()` and `validateMigrationPlan()` reject unknown fields,
71
79
  future versions, malformed operations, missing edges, and dependency cycles.
72
80
 
@@ -1,6 +1,6 @@
1
1
  # Canonical schema snapshots
2
2
 
3
- > Serialize schema metadata into strict, deterministic data and keep serialization separate from diffing, planning, and DDL emission.
3
+ > Save a schema as versioned data that you can compare and check into source control.
4
4
 
5
5
  Qubu's schema tooling lives behind the `qubu/snapshot` entrypoint. It converts
6
6
  an immutable `schema()` registry into versioned data that can be inspected,
@@ -14,21 +14,33 @@ const snapshot = createSchemaSnapshot(appSchema)
14
14
  const json = encodeSchemaSnapshot(snapshot)
15
15
  ```
16
16
 
17
- The Snapshot v1 envelope contains a format version, an independently versioned
18
- dialect extension, a versioned naming-policy description, a namespace,
19
- capability facts, and arrays for every supported object family. Tables,
20
- columns, constraints, and indexes are sorted by stable logical ID. Physical
17
+ ## What a snapshot contains
18
+
19
+ The Snapshot v1 envelope contains:
20
+
21
+ - A format version.
22
+ - An independently versioned dialect extension.
23
+ - A versioned naming-policy description.
24
+ - A namespace.
25
+ - Supported-capability facts.
26
+ - Arrays for each supported object family.
27
+
28
+ Tables, columns, constraints, and indexes are sorted by stable logical ID. Physical
21
29
  names are values in the snapshot, not identities:
22
30
  changing a physical name does not change the TypeScript field or metadata key.
23
31
 
24
- Snapshot data is deliberately not executable Qubu state. Expressions are
25
- parameter-free data records, and decoding never creates tables, column
26
- references, or render closures. The neutral fallback renders branded built-in
27
- expressions through the standard schema context; a dialect adapter may replace
32
+ Snapshot expressions are data records without parameters. Decoding does not
33
+ create executable table or column objects, or rendering functions.
34
+
35
+ The neutral fallback renders branded built-in expressions through the standard schema context; a dialect adapter may replace
28
36
  that hook with its own literal and expression policy. An explicitly unsafe
29
37
  expression retains its dialect tag and is rejected when it does not match the
30
38
  selected snapshot dialect.
31
39
 
40
+ ## Decode and validate a snapshot
41
+
42
+ Use `decodeSchemaSnapshot()` to read saved JSON and inspect validation failures:
43
+
32
44
  ```ts
33
45
  import { decodeSchemaSnapshot } from "qubu/snapshot"
34
46
 
@@ -46,6 +58,8 @@ dialect metadata, and broken foreign-key or column references as structured
46
58
  diagnostics. It does not call `process.exit()` and has no runtime validation
47
59
  library dependency.
48
60
 
61
+ ### References and ownership
62
+
49
63
  References to nested columns, constraints, and indexes carry an explicit
50
64
  `owner: { kind, id }` scope. Table columns, constraints, and indexes are owned
51
65
  by their table; view columns are owned by their view; and domain constraints
@@ -55,6 +69,8 @@ checked only in typed snapshot fields. Extension `data`, `configuration`, and
55
69
  other opaque JSON payloads are retained as data and are not interpreted as
56
70
  typed metadata.
57
71
 
72
+ ### Content fingerprints
73
+
58
74
  `schemaSnapshotFingerprint()` computes a deterministic content fingerprint from canonical
59
75
  JSON. The fingerprint is useful for cache keys and fixture assertions only. It is not
60
76
  an entity identity, a rename marker, or migration lineage.
@@ -69,15 +85,23 @@ and advertised capabilities while adding schema encoders and validation under
69
85
  second query dialect. The schema snapshot format version remains independent
70
86
  from the dialect identity.
71
87
 
72
- The common traversal owns logical IDs, fixed property order, canonical sorting,
73
- portable constraints, cross-reference checks, and the immutable snapshot
74
- envelope. A dialect adapter owns physical storage mapping, SQL literal and
75
- expression encoding, dialect extensions, capability checks, and any dialect
76
- naming policy. PostgreSQL, SQLite, and MySQL adapters can implement
77
- `SchemaSnapshotAdapter` without duplicating traversal or decoder rules.
78
- The neutral API stays at `qubu/snapshot`; built-in dialect adapters have
79
- dedicated subpaths so importing neutral snapshot utilities does not widen that
80
- API:
88
+ The shared serializer handles:
89
+
90
+ - Logical IDs and fixed property order.
91
+ - Canonical sorting and portable constraints.
92
+ - Cross-reference checks.
93
+ - The immutable snapshot envelope.
94
+
95
+ A dialect adapter handles:
96
+
97
+ - Physical storage mapping.
98
+ - SQL literal and expression encoding.
99
+ - Dialect extensions and capability checks.
100
+ - Any dialect-specific naming policy.
101
+
102
+ PostgreSQL, SQLite, and MySQL adapters can implement `SchemaSnapshotAdapter`
103
+ without duplicating traversal or decoder rules. Import built-in adapters from
104
+ their dedicated subpaths:
81
105
 
82
106
  ```ts
83
107
  import { createSchemaSnapshot } from "qubu/snapshot"
@@ -97,17 +121,21 @@ matrix](../reference/mysql-snapshot.md). Its query and snapshot dialects both
97
121
  use `mysql`, while MySQL-only `ON UPDATE` and `AUTO_INCREMENT` details remain
98
122
  inside the column and identity metadata they describe.
99
123
 
100
- Snapshot serialization remains separate from database introspection,
101
- comparison, rename resolution, migration planning, and DDL emission. The
102
- optional `qubu/introspection` entrypoint can produce the same canonical
103
- Snapshot v1 data from a user-owned catalog connection. The complete normalized
104
- catalog can also be encoded with the explicit complete-snapshot APIs described
105
- in [the catalog model](catalog-model.md).
106
- Readers and connection lifecycle do not belong to this pure serialization
107
- layer. Diffing consumes Snapshot v1. Resolved diffs feed
108
- migration plans, and approved plans feed DDL emission. The package-wide
109
- [ownership map](../reference/supported-surface.md#ownership-boundary) keeps
110
- those pure steps separate from application-owned database execution.
124
+ ## Use a snapshot in later steps
125
+
126
+ The optional `qubu/introspection` entrypoint can produce Snapshot v1 data from
127
+ a catalog connection you provide. The [catalog model](catalog-model.md)
128
+ describes the complete-snapshot APIs.
129
+
130
+ A snapshot then passes through separate steps:
131
+
132
+ 1. Diffing compares Snapshot v1 values.
133
+ 2. Migration planning uses the resolved diff.
134
+ 3. DDL emission renders an approved plan.
135
+
136
+ These steps return data without accessing the database. The
137
+ [ownership map](../reference/supported-surface.md#ownership-boundary) explains
138
+ how they connect to application-owned execution.
111
139
 
112
140
  The optional [schema source generator](code-generation.md) consumes a complete,
113
141
  non-lossy introspection result and makes its generated schema the next identity
@@ -1,11 +1,15 @@
1
1
  # Storage and schema SQL
2
2
 
3
- > Keep application types, SQL domains, physical storage, and schema expressions separate so each adapter can make its own rendering decision.
3
+ > Describe database storage types and write expressions for schema definitions.
4
4
 
5
5
  ## Keep application and SQL types separate
6
6
 
7
- A column can have an application value type, a SQL semantic domain, a physical
8
- storage descriptor, and a cast target. These facts answer different questions.
7
+ A column can describe four different things:
8
+
9
+ - Its application value type.
10
+ - Its SQL semantic domain, which controls compatible operations.
11
+ - Its physical database storage type.
12
+ - Its target type when used in a cast.
9
13
 
10
14
  For example, `numeric()` decodes to a TypeScript number, carries `SqlDecimal`,
11
15
  uses portable numeric storage, and has a logical decimal cast target. Read
@@ -45,7 +49,9 @@ const accounts = table("accounts", {
45
49
  `nativeStorage()` preserves the declaration text and freezes the descriptor. The
46
50
  `ColumnStorageOf`, `ColumnStorageTypeOf`, `ColumnStorageDialectOf`, and
47
51
  `ColumnStorageDeclarationOf` helpers read its metadata. Native storage is
48
- descriptive. The optional `sqlType` field is the runtime semantic domain passed
52
+ descriptive.
53
+
54
+ The optional `sqlType` field is the runtime semantic domain passed
49
55
  to adapters; provide it for custom domains because the compile-time SQL type is
50
56
  not available at runtime. It does not change selection, mutation, or query
51
57
  rendering.
@@ -1,6 +1,6 @@
1
1
  # Tables and names
2
2
 
3
- > Define query-facing tables, keep their TypeScript identities stable, and control how fields become SQL names.
3
+ > Define tables and control how TypeScript field names map to database names.
4
4
 
5
5
  `table()` definitions describe the columns Qubu can select and write. They are
6
6
  not database introspection and they do not create or migrate a database.
@@ -1,6 +1,6 @@
1
1
  # SQL semantic types
2
2
 
3
- > Use SQL domains to constrain valid query composition without conflating database semantics with driver-decoded application values.
3
+ > Understand which SQL operations a column supports, even when its JavaScript type looks the same as another column’s.
4
4
 
5
5
  Qubu tracks four independent facts for a field or result expression:
6
6
 
@@ -11,7 +11,7 @@ Qubu tracks four independent facts for a field or result expression:
11
11
  | Nullability | Can the selected value be `null`? | `false` |
12
12
  | SQL domain | Which portable SQL operations may consume the expression? | `SqlText` or `SqlUuid` |
13
13
 
14
- The axes are deliberately separate. Both `text()` and `uuid()` decode to a
14
+ These facts are separate. Both `text()` and `uuid()` decode to a
15
15
  JavaScript `string`, but their SQL behavior differs. Likewise, two
16
16
  `timestamp()` definitions may share `SqlTimestamp` while a custom column uses
17
17
  different JavaScript output and write types for its driver.
@@ -111,12 +111,15 @@ target is vendor-specific.
111
111
 
112
112
  ## Known incompatibility is rejected
113
113
 
114
- Qubu checks capabilities and compatibility when it knows both SQL domains.
115
- Arithmetic and `SUM`/`AVG` require numeric-like expressions; text functions,
116
- concatenation, `LIKE`, and PostgreSQL `ILIKE` require text-like expressions;
117
- ordering and range comparisons require compatible ordering groups; and
118
- equality, `IN`, `CASE`, `COALESCE`, and set-operation fields require compatible
119
- equality groups. Boolean clauses require a boolean SQL domain.
114
+ When Qubu knows both SQL domains, it checks these rules:
115
+
116
+ - Arithmetic and `SUM`/`AVG` require numeric-like expressions.
117
+ - Text functions, concatenation, and pattern matching (`LIKE` or `ILIKE`)
118
+ require text-like expressions.
119
+ - Ordering and range comparisons require compatible ordering groups.
120
+ - Equality comparisons and `IN` require compatible equality groups. The same
121
+ rule applies to `CASE`, `COALESCE`, and set-operation fields.
122
+ - Boolean clauses require a boolean SQL domain.
120
123
 
121
124
  These checks model portable capability and group relationships, not every
122
125
  database's implicit casts. An expression accepted by one database after an
@@ -1,6 +1,6 @@
1
1
  # Troubleshooting
2
2
 
3
- > Start from the observed error or output, verify the boundary that produced it, and apply the smallest fix that changes the result.
3
+ > Find a common error, check its cause, and fix the query.
4
4
 
5
5
  ## Column is not available in this query scope
6
6
 
@@ -73,9 +73,13 @@ driver that expects `?` placeholders.
73
73
  ## Read and repair query diagnostics
74
74
 
75
75
  Type-level query failures carry stable properties in the diagnostic type, and
76
- runtime authoring failures throw `QueryValidationError`. Read the code, context,
77
- path, and hint before changing the query. The hint names the repair boundary;
78
- the path points to the clause or field that needs attention.
76
+ runtime authoring failures throw `QueryValidationError`. Check these fields
77
+ before changing the query:
78
+
79
+ - `code`: the kind of error.
80
+ - `context`: where the error occurred.
81
+ - `path`: the clause or field that needs attention.
82
+ - `hint`: how to fix it.
79
83
 
80
84
  ```ts
81
85
  import { QueryValidationError, fetchFirst } from "qubu"
@@ -130,8 +134,12 @@ Verify all three opt-ins:
130
134
  3. TypeScript includes `qubu/globals` in its `types` list or includes the
131
135
  declaration explicitly.
132
136
 
133
- The transform skips non-script files, dependencies under `node_modules`, files
134
- excluded by filters, and modules that reference no eligible Qubu global.
137
+ The transform skips:
138
+
139
+ - Non-script files.
140
+ - Dependencies under `node_modules`.
141
+ - Files excluded by filters.
142
+ - Modules that reference no eligible Qubu global.
135
143
 
136
144
  ## Parameters are in an unexpected order
137
145
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qubu",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/aleclarson/qubu"