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.
- package/dist/mysql.d.mts +1 -1
- package/dist/postgres.d.mts +1 -1
- package/docs/dialects-and-execution.md +54 -25
- package/docs/getting-started.md +9 -9
- package/docs/guides/better-auth.md +16 -5
- package/docs/guides/compose-queries.md +21 -9
- package/docs/guides/drizzle.md +8 -3
- package/docs/guides/extensions/dialects.md +1 -1
- package/docs/guides/extensions/overview.md +1 -1
- package/docs/guides/extensions/sources-and-clauses.md +7 -3
- package/docs/guides/extensions/typed-expressions.md +25 -13
- package/docs/guides/extensions/unsafe-syntax.md +10 -6
- package/docs/guides/json.md +52 -27
- package/docs/guides/mutations.md +15 -6
- package/docs/guides/select/conditions.md +18 -11
- package/docs/guides/select/grouping-and-windows.md +5 -2
- package/docs/guides/select/ordering-and-pagination.md +5 -3
- package/docs/guides/select/overview.md +6 -3
- package/docs/guides/sql-templates.md +11 -5
- package/docs/guides/valtio-sync.md +11 -5
- package/docs/guides/vite-plugin.md +2 -2
- package/docs/index.md +24 -17
- package/docs/migrations/adapters.md +47 -19
- package/docs/migrations/artifacts-and-policy.md +49 -20
- package/docs/migrations/index.md +15 -8
- package/docs/migrations/lotta-adoption.md +16 -5
- package/docs/migrations/operations.md +29 -15
- package/docs/migrations/recovery.md +34 -17
- package/docs/query-model/fragments.md +13 -5
- package/docs/query-model/result-shapes.md +2 -2
- package/docs/query-model/source-scope.md +5 -3
- package/docs/reference/introspection-support.md +26 -19
- package/docs/reference/mysql-snapshot.md +19 -4
- package/docs/reference/postgres-snapshot.md +17 -4
- package/docs/reference/sqlite-snapshot.md +19 -2
- package/docs/reference/supported-surface.md +221 -85
- package/docs/schema/catalog-model.md +24 -7
- package/docs/schema/code-generation.md +40 -21
- package/docs/schema/columns-and-writes.md +21 -11
- package/docs/schema/constraints-and-indexes.md +12 -5
- package/docs/schema/ddl-emission.md +16 -5
- package/docs/schema/diff.md +12 -4
- package/docs/schema/introspection.md +47 -21
- package/docs/schema/migration-plans.md +18 -10
- package/docs/schema/snapshots.md +57 -29
- package/docs/schema/storage-and-schema-sql.md +10 -4
- package/docs/schema/tables-and-names.md +1 -1
- package/docs/sql-semantic-types.md +11 -8
- package/docs/troubleshooting.md +14 -6
- package/package.json +1 -1
package/docs/guides/mutations.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Write mutations
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Insert, update, and delete rows with typed inputs and explicit safeguards.
|
|
4
4
|
|
|
5
5
|
## Define write-time rules
|
|
6
6
|
|
|
@@ -121,6 +121,8 @@ const query = update(
|
|
|
121
121
|
The assignment expression is source-aware, so a column from an unrelated table
|
|
122
122
|
cannot silently enter the update.
|
|
123
123
|
|
|
124
|
+
### Update from another source
|
|
125
|
+
|
|
124
126
|
PostgreSQL updates can introduce one or more typed sources with `updateFrom()`.
|
|
125
127
|
Those sources are available to assignments, the predicate, and `RETURNING`:
|
|
126
128
|
|
|
@@ -153,6 +155,8 @@ with the default, SQLite, or MySQL dialect is rejected. Qubu still requires a
|
|
|
153
155
|
predicate or an explicit `allowAll()` marker; introducing a source does not
|
|
154
156
|
authorize an unrestricted update.
|
|
155
157
|
|
|
158
|
+
### Omit an assignment at runtime
|
|
159
|
+
|
|
156
160
|
Use `omit` for a runtime-conditional assignment. Qubu removes omitted fields
|
|
157
161
|
before validating and rendering the effective assignment set:
|
|
158
162
|
|
|
@@ -171,7 +175,9 @@ const query = update(
|
|
|
171
175
|
|
|
172
176
|
`omit` means that the column is absent from `SET`. It is distinct from `null`
|
|
173
177
|
and explicit `undefined`, which remain bound assignment values, and it does not
|
|
174
|
-
emit SQL `DEFAULT`.
|
|
178
|
+
emit SQL `DEFAULT`.
|
|
179
|
+
|
|
180
|
+
At least one assignment must remain; `update()` throws
|
|
175
181
|
before rendering when every field is omitted. Possible expression branches
|
|
176
182
|
remain source- and capability-aware even when their runtime alternative is
|
|
177
183
|
`omit`.
|
|
@@ -237,11 +243,14 @@ unrestricted operation is intended.
|
|
|
237
243
|
|
|
238
244
|
## Return typed rows
|
|
239
245
|
|
|
240
|
-
`returning()` uses the same named object projection as `SELECT`.
|
|
241
|
-
`{ ...all(table) }`
|
|
242
|
-
|
|
246
|
+
`returning()` uses the same named object projection as `SELECT`. Use
|
|
247
|
+
`{ ...all(table) }` when you want every table column.
|
|
248
|
+
|
|
249
|
+
The mutation’s `row` type is inferred from that projection, so
|
|
243
250
|
`(await db.execute(query)).rows` has the same shape as a read query when `db`
|
|
244
|
-
comes from `qubu(adapter)`.
|
|
251
|
+
comes from `qubu(adapter)`.
|
|
252
|
+
|
|
253
|
+
The projection’s SQL semantic domains are
|
|
245
254
|
retained too, so a returned query used by typed composition does not collapse
|
|
246
255
|
UUID, text, numeric, or other known fields to their JavaScript types alone.
|
|
247
256
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Add optional conditions
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
> the query keeps the same structural shape.
|
|
3
|
+
> Add or omit conditions at runtime, and handle NULL values and empty lists.
|
|
5
4
|
|
|
6
5
|
The examples use the `users` table from [Build a `SELECT`](overview.md).
|
|
7
6
|
|
|
@@ -65,15 +64,23 @@ Here `omit` affects only whether `email` belongs to the projection. It does
|
|
|
65
64
|
not make the expression nullable: a non-nullable expression would produce
|
|
66
65
|
`email?: string`, while this nullable column produces `email?: string | null`.
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
67
|
+
### Where omission is supported
|
|
68
|
+
|
|
69
|
+
Use `omit` in the clauses and expression lists shown above. Generic
|
|
70
|
+
`sequence()` and `commaSeparated()` collections do not discard it.
|
|
71
|
+
|
|
72
|
+
Pagination also supports `omit`: pair it with `offset()`, `fetchFirst()`, or
|
|
73
|
+
`fetchNext()`. A conditional limit keeps the inferred cardinality at `many`
|
|
74
|
+
because the limit may be absent.
|
|
75
|
+
|
|
76
|
+
Build separate queries when any of these parts differ at runtime. They cannot
|
|
77
|
+
be paired with `omit`:
|
|
78
|
+
|
|
79
|
+
- `from()` or joins.
|
|
80
|
+
- `groupBy()`.
|
|
81
|
+
- Correlation.
|
|
82
|
+
- CTEs.
|
|
83
|
+
- Custom clauses.
|
|
77
84
|
|
|
78
85
|
## Handle `NULL` and empty lists deliberately
|
|
79
86
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Group and rank rows
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Summarize rows with aggregates and rank them with window functions.
|
|
4
4
|
|
|
5
5
|
The examples use the `users` and `posts` tables from [Build a
|
|
6
6
|
`SELECT`](overview.md).
|
|
@@ -28,6 +28,7 @@ const counts = select(
|
|
|
28
28
|
|
|
29
29
|
`users.name` is grouped, while `posts.id` is consumed by `COUNT()`. The
|
|
30
30
|
same dependency rule applies to `HAVING` and grouped `ORDER BY` expressions.
|
|
31
|
+
|
|
31
32
|
A projection such as `{ email: users.email, postCount: count(posts.id) }` is
|
|
32
33
|
rejected unless `users.email` is grouped or is functionally determined by a
|
|
33
34
|
grouped primary or unique key declared in the table schema. Qubu uses only
|
|
@@ -58,7 +59,9 @@ const rankedUsers = select(
|
|
|
58
59
|
Window expressions remain ordinary expressions. They can be projected, aliased,
|
|
59
60
|
and passed to `orderBy()`. Their source requirements and result types are
|
|
60
61
|
retained through `over()`, and values rendered inside the window
|
|
61
|
-
specification remain parameters.
|
|
62
|
+
specification remain parameters.
|
|
63
|
+
|
|
64
|
+
Named windows and frame clauses are outside
|
|
62
65
|
the initial inline scope.
|
|
63
66
|
|
|
64
67
|
## Read next
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Order and paginate
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Sort results and limit the rows a query returns.
|
|
4
4
|
|
|
5
5
|
The examples use the `users` table from [Build a `SELECT`](overview.md).
|
|
6
6
|
|
|
@@ -34,10 +34,12 @@ const page = select(
|
|
|
34
34
|
)
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
The rendered
|
|
38
|
-
pagination. The active dialect decides whether pagination uses standard
|
|
37
|
+
The rendered clauses follow SQL order: `FROM` comes before `WHERE`, followed
|
|
38
|
+
by `ORDER BY` and pagination. The active dialect decides whether pagination uses standard
|
|
39
39
|
`FETCH` syntax or a driver-specific `LIMIT` form.
|
|
40
40
|
|
|
41
|
+
### Make the limit optional
|
|
42
|
+
|
|
41
43
|
Pair a pagination clause with `omit` when the row bound is optional at runtime:
|
|
42
44
|
|
|
43
45
|
```ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Build a `SELECT`
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Choose fields, add a source, and join tables to build a typed SELECT query.
|
|
4
4
|
|
|
5
5
|
## Start with a projection and a source
|
|
6
6
|
|
|
@@ -24,8 +24,7 @@ render(query).text
|
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
An object projection uses its keys as result names. Name the fields you intend
|
|
27
|
-
to return in the usual case.
|
|
28
|
-
intentionally returns every source column. It returns the source's columns as a
|
|
27
|
+
to return in the usual case. Use `all(source)` when you want every source column. It returns the source's columns as a
|
|
29
28
|
named projection object, so it can still be spread alongside computed
|
|
30
29
|
expressions:
|
|
31
30
|
|
|
@@ -79,6 +78,8 @@ Use `innerJoin`, `leftJoin`, `rightJoin`, or `fullJoin` with an `ON`
|
|
|
79
78
|
condition. `crossJoin` and `naturalJoin` add a source without a condition;
|
|
80
79
|
use them only when that SQL behavior is intentional.
|
|
81
80
|
|
|
81
|
+
### Handle missing joined rows
|
|
82
|
+
|
|
82
83
|
`leftJoin()` also carries nullability into the selected row. A column from the
|
|
83
84
|
joined source is nullable because the row may be missing, while an expression
|
|
84
85
|
with a deliberately non-nullable result such as `count()` remains non-null:
|
|
@@ -98,6 +99,8 @@ const summary = select(
|
|
|
98
99
|
// { userName: string; postTitle: string | null; postCount: number }
|
|
99
100
|
```
|
|
100
101
|
|
|
102
|
+
### Add conditions
|
|
103
|
+
|
|
101
104
|
Compose boolean expressions explicitly:
|
|
102
105
|
|
|
103
106
|
```ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Compose SQL templates
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Write SQL templates that bind values safely and preserve type information from Qubu expressions.
|
|
4
4
|
|
|
5
5
|
## Bind every runtime value
|
|
6
6
|
|
|
@@ -108,10 +108,16 @@ reaches `unsafeExpression()`.
|
|
|
108
108
|
|
|
109
109
|
## Preserve metadata through interpolated fragments
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
Qubu fragment substitutions pass these facts to the template:
|
|
112
|
+
|
|
113
|
+
- Required sources.
|
|
114
|
+
- Possible nulls from outer joins.
|
|
115
|
+
- Grouping dependencies.
|
|
116
|
+
- Aggregate and window state.
|
|
117
|
+
- Subquery state.
|
|
118
|
+
- Required dialect capabilities.
|
|
119
|
+
|
|
120
|
+
Qubu does not infer these facts from template text.
|
|
115
121
|
|
|
116
122
|
Use a built-in expression as the substitution when its semantics matter:
|
|
117
123
|
|
|
@@ -102,11 +102,17 @@ const handlers = applyOpsWithQubu<SyncContext>({
|
|
|
102
102
|
export const sync = valtioSync({ schema: { todos }, handlers })
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
105
|
+
Each mutation runs these steps in one Qubu transaction:
|
|
106
|
+
|
|
107
|
+
1. Check authorization.
|
|
108
|
+
2. Check conflicts.
|
|
109
|
+
3. Apply the application mutation.
|
|
110
|
+
4. Write the sync event with `syncEvents.write()`.
|
|
111
|
+
|
|
112
|
+
If any step fails, the adapter rolls the transaction back.
|
|
113
|
+
|
|
114
|
+
The event sequence becomes `serverVersion` unless the mutation handler returns
|
|
115
|
+
an explicit version. Read handlers pass through unchanged.
|
|
110
116
|
|
|
111
117
|
The integration does not define persistence tables, import Drizzle, or execute
|
|
112
118
|
driver APIs. The application owns table design, authorization, conflict policy,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vite compiler hint
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Use a "use qubu" directive to add the Qubu imports a module needs.
|
|
4
4
|
|
|
5
5
|
The optional Vite plugin recognizes the `"use qubu"` directive and injects only
|
|
6
6
|
the referenced named imports from the configured module.
|
|
@@ -33,7 +33,7 @@ ambient value and type declarations for the TypeScript compiler.
|
|
|
33
33
|
|
|
34
34
|
## Mark a module explicitly
|
|
35
35
|
|
|
36
|
-
Put the directive
|
|
36
|
+
Put the directive at the start of the module, alongside any other directives:
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
39
|
"use qubu"
|
package/docs/index.md
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# Qubu
|
|
2
2
|
|
|
3
|
-
> Build
|
|
3
|
+
> Build SQL queries from typed tables and reusable values.
|
|
4
4
|
|
|
5
|
-
Qubu builds SQL from values.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Qubu builds SQL from reusable values. You can combine query parts without
|
|
6
|
+
changing a shared query-builder object.
|
|
7
|
+
|
|
8
|
+
TypeScript checks:
|
|
9
|
+
|
|
10
|
+
- Which fields the query returns and their types.
|
|
11
|
+
- Whether each column belongs to a source in the query.
|
|
12
|
+
- Whether a result can be `null`.
|
|
13
|
+
|
|
14
|
+
Render a query to inspect its SQL text and ordered parameters.
|
|
9
15
|
|
|
10
16
|
The preferred source style names each projected field and writes the final
|
|
11
17
|
`select()` clauses in SQL order. Clause values remain order-independent at
|
|
@@ -17,7 +23,7 @@ and placed in that final call where it reads best.
|
|
|
17
23
|
If this is your first query, follow [Getting started](getting-started.md) to
|
|
18
24
|
define a table, build a `SELECT`, and inspect its SQL and parameters.
|
|
19
25
|
|
|
20
|
-
##
|
|
26
|
+
## Build and run queries
|
|
21
27
|
|
|
22
28
|
- [Build a `SELECT`](guides/select/overview.md) with projections, joins,
|
|
23
29
|
predicates, ordering, and grouping.
|
|
@@ -36,18 +42,18 @@ define a table, build a `SELECT`, and inspect its SQL and parameters.
|
|
|
36
42
|
- [Query nested JSON](guides/json.md) or read scalars from structured paths.
|
|
37
43
|
- [Enable the Vite compiler hint](guides/vite-plugin.md) when query modules
|
|
38
44
|
should opt into named imports through a directive.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
|
|
46
|
+
## Work with schemas and migrations
|
|
47
|
+
|
|
48
|
+
- [Inspect an existing database](schema/introspection.md) using a connection you provide.
|
|
49
|
+
- [Generate a schema module](schema/code-generation.md) from an introspection result without losing schema facts.
|
|
43
50
|
- [Compare snapshots](schema/diff.md) with explicit rename hints and reviewable
|
|
44
51
|
safety diagnostics.
|
|
45
52
|
- [Build migration plans](schema/migration-plans.md) as reviewed, deterministic
|
|
46
53
|
data before DDL emission.
|
|
47
54
|
- [Emit DDL](schema/ddl-emission.md) from an approved migration plan without
|
|
48
55
|
handing Qubu a database connection.
|
|
49
|
-
- [Operate migrations](migrations/index.md) with
|
|
50
|
-
adapter profiles, baselines, a portable executor, and explicit recovery.
|
|
56
|
+
- [Operate migrations](migrations/index.md) with reviewed migration files and a verified adapter.
|
|
51
57
|
|
|
52
58
|
## The query pipeline
|
|
53
59
|
|
|
@@ -106,8 +112,9 @@ render(query)
|
|
|
106
112
|
The inferred row is `{ id: number; name: string }`. The value `7` stays out
|
|
107
113
|
of the SQL text and appears in the `parameters` array in placeholder order.
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
starts from common errors and
|
|
115
|
+
## Find support details
|
|
116
|
+
|
|
117
|
+
- [Supported features](reference/supported-surface.md) lists package imports and
|
|
118
|
+
explains which responsibilities stay with your application.
|
|
119
|
+
- [Troubleshooting](troubleshooting.md) starts from common errors and explains
|
|
120
|
+
how to fix them.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Adapter capability profiles
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Choose a migration adapter based on what its driver and environment have been tested to support.
|
|
4
4
|
|
|
5
5
|
Every executable migration adapter opens a migration session and
|
|
6
6
|
advertises the exact behavior the executor may use:
|
|
@@ -25,12 +25,12 @@ executor never treats one as proof of the other.
|
|
|
25
25
|
|
|
26
26
|
## Trusted migration SQL
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
Qubu validates program structure and adapter capabilities. It trusts the SQL
|
|
29
|
+
you supply, including SQL conditions, and does not parse it for safety.
|
|
30
|
+
|
|
31
|
+
Migration SQL must preserve the executor’s transactions, connection settings,
|
|
32
|
+
and journal state. For example, an explicit `COMMIT` can apply schema changes
|
|
33
|
+
without their journal record, breaking the executor’s recovery guarantees.
|
|
34
34
|
|
|
35
35
|
## Current profiles
|
|
36
36
|
|
|
@@ -44,11 +44,24 @@ The following stable profiles have live conformance coverage in this checkout:
|
|
|
44
44
|
| `@qubu/adapter-postgresjs/migration` | PostgreSQL | required, optional, forbidden | none, exclusive | checkpointed | Reserves and releases one connection |
|
|
45
45
|
| `@qubu/adapter-pglite/migration` | PostgreSQL | required, optional, forbidden | none, exclusive | checkpointed | Uses the database query queue as the pinned session |
|
|
46
46
|
|
|
47
|
-
All five support
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
All five support:
|
|
48
|
+
|
|
49
|
+
- Every current tagged parameter kind.
|
|
50
|
+
- A journal and migrator lease stored in the database.
|
|
51
|
+
- An atomic update of the applied record and journal head.
|
|
52
|
+
- A recovery-required result when a commit’s outcome is uncertain.
|
|
53
|
+
|
|
54
|
+
Parameter kinds are:
|
|
55
|
+
|
|
56
|
+
- `null` and `boolean`.
|
|
57
|
+
- `string` and `number`.
|
|
58
|
+
- `bigint` and `bytes`.
|
|
59
|
+
- `json`.
|
|
60
|
+
|
|
61
|
+
The artifact’s server, feature, transaction, and lock requirements must still
|
|
62
|
+
match the adapter.
|
|
63
|
+
|
|
64
|
+
### Unavailable profiles
|
|
52
65
|
|
|
53
66
|
These exported profiles are unavailable and must not be passed to the
|
|
54
67
|
executor:
|
|
@@ -62,6 +75,8 @@ executor:
|
|
|
62
75
|
Unavailable profiles expose `reason` and `missingCapabilities`; they do not
|
|
63
76
|
fall back to a generic executor.
|
|
64
77
|
|
|
78
|
+
### Configure libSQL inspection
|
|
79
|
+
|
|
65
80
|
For libSQL, let the migration entrypoint exclude all reserved journal objects
|
|
66
81
|
during strict inspection:
|
|
67
82
|
|
|
@@ -84,7 +99,9 @@ Each executable artifact must contain exactly one phase and an embedded before
|
|
|
84
99
|
snapshot. The adapter submits its statements, SQL assertions, applied-history
|
|
85
100
|
record, head update, and terminal attempt state in one `client.migrate()` call.
|
|
86
101
|
For example, creating a table and recording that migration either both commit
|
|
87
|
-
or both roll back.
|
|
102
|
+
or both roll back.
|
|
103
|
+
|
|
104
|
+
Multiple artifacts are separate batches; earlier successful
|
|
88
105
|
artifacts remain applied if a later one fails.
|
|
89
106
|
|
|
90
107
|
Preparation reads the schema in a read transaction. The submitted batch checks
|
|
@@ -92,13 +109,24 @@ that the catalog still matches that inspection, the lease is still owned, and
|
|
|
92
109
|
the head still equals the expected parent. Foreign-key validation runs before
|
|
93
110
|
commit because libSQL temporarily disables enforcement during `migrate()`.
|
|
94
111
|
|
|
112
|
+
### Supported conditions
|
|
113
|
+
|
|
95
114
|
Schema fingerprint and property preconditions are checked against the embedded
|
|
96
|
-
before snapshot
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
115
|
+
before snapshot. Preparation verifies its physical facts, and the batch
|
|
116
|
+
asserts that the catalog still matches.
|
|
117
|
+
|
|
118
|
+
Object-presence and scalar SQL checks run inside the batch. Postconditions
|
|
119
|
+
must use either:
|
|
120
|
+
|
|
121
|
+
- Object-presence or absence checks without fingerprints.
|
|
122
|
+
- Scalar SQL checks returning `1`.
|
|
123
|
+
|
|
124
|
+
Unsupported conditions and multiple phases are rejected.
|
|
125
|
+
|
|
126
|
+
SQL is passed to the driver without safety validation. Each program entry
|
|
127
|
+
must follow the driver’s statement contract.
|
|
128
|
+
|
|
129
|
+
### Crashes and uncertain outcomes
|
|
102
130
|
|
|
103
131
|
The database-row lease has no expiry or heartbeat. A process crash can leave
|
|
104
132
|
it held; ownership must be resolved before another runner can proceed. A lost
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Artifacts and approval policy
|
|
2
2
|
|
|
3
|
-
> Review
|
|
3
|
+
> Review migration files and approve the exact operations they will run.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
An artifact is a versioned migration file. Qubu supports two kinds:
|
|
6
|
+
|
|
7
|
+
- An **executable migration** contains a reviewed plan and the program to run.
|
|
8
|
+
- A **verified baseline** records the observed schema as a starting point. It
|
|
9
|
+
does not claim that historical SQL ran through Qubu.
|
|
8
10
|
|
|
9
11
|
## Published formats
|
|
10
12
|
|
|
@@ -38,18 +40,30 @@ An executable artifact records:
|
|
|
38
40
|
- operation-scoped approvals and custom-program provenance;
|
|
39
41
|
- artifact provenance and `artifactDigest`.
|
|
40
42
|
|
|
41
|
-
The program
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
The executor runs the program stored in the artifact. The SQL preview from
|
|
44
|
+
`emitMigrationPlan(...).sql` is not an executable artifact.
|
|
45
|
+
|
|
46
|
+
Each phase declares:
|
|
47
|
+
|
|
48
|
+
- Its position and dependencies.
|
|
49
|
+
- Transaction and lock requirements.
|
|
50
|
+
- Preconditions and postconditions.
|
|
51
|
+
- Ordered statements.
|
|
52
|
+
|
|
53
|
+
Each statement declares its operation ID, dependencies, SQL, and tagged parameters.
|
|
46
54
|
|
|
47
55
|
### Baseline artifact schema
|
|
48
56
|
|
|
49
|
-
A baseline records
|
|
50
|
-
|
|
51
|
-
`
|
|
52
|
-
|
|
57
|
+
A baseline records:
|
|
58
|
+
|
|
59
|
+
- `id`, sequence, and parent lineage.
|
|
60
|
+
- Encoding descriptors.
|
|
61
|
+
- Dialect and optional constraints.
|
|
62
|
+
- One verified snapshot descriptor and `verifiedAt`.
|
|
63
|
+
- Provenance and optional operator metadata.
|
|
64
|
+
- `artifactDigest`.
|
|
65
|
+
|
|
66
|
+
It has no migration plan, program, or SQL digest.
|
|
53
67
|
|
|
54
68
|
Artifact IDs are stable identities, not repository order. Sequence and parent
|
|
55
69
|
digest establish the linear chain. Renumbering therefore changes lineage and
|
|
@@ -57,21 +71,36 @@ the artifact digest.
|
|
|
57
71
|
|
|
58
72
|
## Canonical bytes and digest domains
|
|
59
73
|
|
|
60
|
-
`encodeCanonical()`
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
74
|
+
`encodeCanonical()` produces a repeatable byte representation:
|
|
75
|
+
|
|
76
|
+
- Sort object keys by Unicode code-point order.
|
|
77
|
+
- Preserve array order.
|
|
78
|
+
- Emit compact UTF-8 JSON.
|
|
79
|
+
- Normalize `-0` to `0` and reject non-finite numbers.
|
|
80
|
+
- End the file with one line feed.
|
|
81
|
+
|
|
82
|
+
`digestCanonical()` prefixes those bytes with the UTF-8 bytes for:
|
|
64
83
|
|
|
65
84
|
```text
|
|
66
85
|
qubu:migrate:v1:<domain>\0
|
|
67
86
|
```
|
|
68
87
|
|
|
69
|
-
The
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
The digest identifies its purpose through one of five domains:
|
|
89
|
+
|
|
90
|
+
- `artifact`.
|
|
91
|
+
- `baseline`.
|
|
92
|
+
- `migration-plan`.
|
|
93
|
+
- `migration-program`.
|
|
94
|
+
- `schema-snapshot`.
|
|
95
|
+
|
|
96
|
+
The prefix ensures that identical JSON used for different purposes gets
|
|
97
|
+
different digests.
|
|
98
|
+
|
|
72
99
|
Operational digests have the form `sha256:` plus 64 lowercase hexadecimal
|
|
73
100
|
digits and are recomputed while sealing or decoding.
|
|
74
101
|
|
|
102
|
+
### Fingerprints and integrity digests
|
|
103
|
+
|
|
75
104
|
Snapshot and plan `fingerprint` APIs are deterministic FNV-1a64 change
|
|
76
105
|
detectors. They remain useful for caches and fixture assertions, but they are
|
|
77
106
|
not cryptographic integrity evidence and are never valid journal heads,
|
package/docs/migrations/index.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Migration operations
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Find the packages and guides for planning, running, and recovering migrations.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
These packages handle different parts of a migration:
|
|
6
6
|
|
|
7
7
|
| Owner | Imports | Responsibility |
|
|
8
8
|
| --------------- | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -21,6 +21,8 @@ import { emitMigrationPlan } from "@qubu/migrate/ddl"
|
|
|
21
21
|
import { compileMigrationProgram, sealExecutableArtifact } from "@qubu/migrate/artifact"
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Choose an import
|
|
25
|
+
|
|
24
26
|
The `@qubu/migrate` root intentionally exports only format/version constants
|
|
25
27
|
and the central plan and artifact types. Import behavior from its focused
|
|
26
28
|
entrypoint:
|
|
@@ -46,12 +48,17 @@ entrypoint:
|
|
|
46
48
|
| `@qubu/migrate/bootstrap/sqlite` | Plan a fresh SQLite schema through the normal compiler |
|
|
47
49
|
| `@qubu/migrate/testing` | Test adapter capabilities and deterministic failure boundaries |
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
## Choose a guide
|
|
52
|
+
|
|
53
|
+
- [Artifacts and approval policy](artifacts-and-policy.md): review migration
|
|
54
|
+
files and approve operations.
|
|
55
|
+
- [Adapter capability profiles](adapters.md): choose a supported driver.
|
|
56
|
+
- [Command line operations](operations.md): configure and use the CLI.
|
|
57
|
+
- [Recovery and reconciliation](recovery.md): handle interrupted migrations.
|
|
58
|
+
- [Lotta Games adoption](lotta-adoption.md): review the downstream cutover
|
|
59
|
+
plan and combo-matrix release blocker.
|
|
60
|
+
|
|
61
|
+
## Select a built-in dialect
|
|
55
62
|
|
|
56
63
|
Choose the dialect-specific bootstrap entrypoint when using a built-in dialect:
|
|
57
64
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Lotta Games adoption
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Move Lotta to Qubu migrations while keeping deployment decisions in Lotta.
|
|
4
4
|
|
|
5
5
|
Adopt the released `@qubu/migrate`, `@qubu/cli`, and libSQL migration entrypoint
|
|
6
6
|
as a hard cutover. Do not add an upstream decoder for Lotta's provisional JSON,
|
|
7
7
|
FNV artifact digests, journal, or broad unsafe flags.
|
|
8
8
|
|
|
9
|
+
## Establish the starting state
|
|
10
|
+
|
|
9
11
|
Before changing downstream state, inspect every environment for a provisional
|
|
10
12
|
journal or baseline row. Regenerate unreleased migrations in the Qubu artifact
|
|
11
13
|
format. For an existing database, create one standard baseline only after strict
|
|
@@ -13,6 +15,8 @@ live introspection matches the intended Qubu snapshot. That baseline records a
|
|
|
13
15
|
verified starting state; it does not claim that old migrations ran through
|
|
14
16
|
Qubu.
|
|
15
17
|
|
|
18
|
+
## Keep deployment policy in Lotta
|
|
19
|
+
|
|
16
20
|
Keep these concerns in Lotta:
|
|
17
21
|
|
|
18
22
|
- Turso credentials and environment selection;
|
|
@@ -30,10 +34,17 @@ databases with `schema bootstrap`; keep connection PRAGMAs in the test harness.
|
|
|
30
34
|
> Drizzle history. A verified baseline is the handoff from historical state to
|
|
31
35
|
> Qubu lineage.
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
## Verify the cutover
|
|
38
|
+
|
|
39
|
+
Cover these scenarios downstream:
|
|
40
|
+
|
|
41
|
+
- A fresh bootstrap.
|
|
42
|
+
- An already baselined database.
|
|
43
|
+
- A deploy with no pending migrations.
|
|
44
|
+
- Pending migrations in both deployment timing modes.
|
|
45
|
+
- Refusal when the schema has drifted.
|
|
46
|
+
- Concurrent migration attempts.
|
|
47
|
+
- Rollback and explicit recovery.
|
|
37
48
|
|
|
38
49
|
## Combo-matrix release blocker
|
|
39
50
|
|