qubu 0.6.0 → 0.6.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.
- package/README.md +112 -0
- package/dist/{complete-DP7pliuY.mjs → canonical-B5_ouh-c.mjs} +466 -241
- package/dist/codegen.d.mts +2 -2
- package/dist/codegen.mjs +180 -90
- package/dist/column-Cyc2CMnG.mjs +116 -0
- package/dist/column-DDRvD7SF.mjs +721 -0
- package/dist/{constraints-YGyNPQ_z.mjs → constraints-CAmi18Uk.mjs} +8 -3
- package/dist/core.d.mts +3 -3
- package/dist/core.mjs +4 -5
- package/dist/diagnostics-I9vVtXkc.mjs +40 -0
- package/dist/diff.d.mts +9 -9
- package/dist/diff.mjs +152 -102
- package/dist/{explain-CkIK13L_.mjs → explain-BIqEmZha.mjs} +1 -1
- package/dist/expressions-_6JF_J77.mjs +130 -0
- package/dist/index-CaxrMD1A.d.mts +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +414 -77
- package/dist/introspection/mysql.d.mts +26 -0
- package/dist/introspection/mysql.mjs +1278 -0
- package/dist/introspection/postgres.d.mts +43 -0
- package/dist/introspection/postgres.mjs +1889 -0
- package/dist/introspection/sqlite.d.mts +15 -0
- package/dist/introspection/sqlite.mjs +1172 -0
- package/dist/introspection.d.mts +26 -87
- package/dist/introspection.mjs +3 -4351
- package/dist/mysql.d.mts +3 -3
- package/dist/mysql.mjs +8 -7
- package/dist/{errors-Dxv73YJu.mjs → omit-VEr9Ydux.mjs} +5 -1
- package/dist/{on-conflict-DZQ85f1t.mjs → on-conflict-B2rFyHGF.mjs} +78 -8
- package/dist/on-duplicate-key-update-Czsw1Yq-.mjs +95 -0
- package/dist/postgres-hFhd0I9n.mjs +68 -0
- package/dist/postgres.d.mts +3 -3
- package/dist/postgres.mjs +3 -52
- package/dist/registry-BXE_4M9P.mjs +127 -0
- package/dist/{relational-CxnLCqZQ.mjs → relational-CoPBETjI.mjs} +3 -3
- package/dist/schema.d.mts +2 -2
- package/dist/schema.mjs +8 -7
- package/dist/{serialize-BN07IK0v.mjs → serialize-CyobNEx-.mjs} +174 -30
- package/dist/serialize-Du2UPZMt.d.mts +92 -0
- package/dist/snapshot/mysql.d.mts +5 -5
- package/dist/snapshot/mysql.mjs +32 -32
- package/dist/snapshot/postgres.d.mts +5 -5
- package/dist/snapshot/postgres.mjs +25 -25
- package/dist/snapshot/sqlite.d.mts +5 -5
- package/dist/snapshot/sqlite.mjs +30 -30
- package/dist/snapshot-mIb-Zzb5.mjs +1489 -0
- package/dist/snapshot.d.mts +4 -5
- package/dist/snapshot.mjs +3 -4
- package/dist/{source-SqrKWjFJ.mjs → source-DYSUqzvb.mjs} +2 -2
- package/dist/sqlite.d.mts +2 -2
- package/dist/sqlite.mjs +10 -10
- package/dist/{table-BwflqeAj.mjs → table-B8zEq0az.mjs} +4 -4
- package/dist/{types-BIJsj2fJ.mjs → types-CYHpSPwj.mjs} +10 -7
- package/dist/{types-CTCqtFlS.d.mts → types-CiMvKi5V.d.mts} +14 -4
- package/dist/{types-C0VkiwpR.d.mts → types-Dqr4o2I1.d.mts} +640 -189
- package/dist/value-CpaUFtjw.mjs +45 -0
- package/dist/vite/ambient.d.ts +2 -0
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +2 -0
- package/docs/dialects-and-execution.md +61 -11
- package/docs/getting-started.md +1 -1
- package/docs/guides/compose-queries.md +22 -0
- package/docs/guides/drizzle.md +11 -11
- package/docs/guides/extensions/typed-expressions.md +5 -3
- package/docs/guides/json.md +95 -2
- package/docs/guides/mutations.md +125 -0
- package/docs/guides/valtio-sync.md +113 -0
- package/docs/index.md +1 -1
- package/docs/migrations/adapters.md +58 -21
- package/docs/migrations/index.md +50 -12
- package/docs/migrations/operations.md +20 -6
- package/docs/migrations/recovery.md +7 -1
- package/docs/query-model/fragments.md +21 -1
- package/docs/reference/introspection-support.md +16 -18
- package/docs/reference/supported-surface.md +23 -11
- package/docs/schema/catalog-model.md +20 -7
- package/docs/schema/code-generation.md +4 -3
- package/docs/schema/diff.md +2 -2
- package/docs/schema/introspection.md +24 -16
- package/docs/schema/snapshots.md +18 -8
- package/docs/schema/storage-and-schema-sql.md +7 -2
- package/docs/sql-semantic-types.md +8 -0
- package/package.json +14 -1
- package/dist/canonical-DMvR9yBe.mjs +0 -972
- package/dist/column-Da37jYSD.mjs +0 -309
- package/dist/column-r1Y4ivwt.mjs +0 -327
- package/dist/complete-types-CY0KbzNw.d.mts +0 -371
- package/dist/index-B2rZf3-2.d.mts +0 -32
- package/dist/json-Db7XRD91.mjs +0 -169
- package/dist/omit-OxV58AwX.mjs +0 -5
- package/dist/registry-BRcUuazJ.mjs +0 -256
- package/dist/serialize-CEIIlWhC.d.mts +0 -66
- package/dist/snapshot-Xam8-q0j.mjs +0 -392
- package/dist/standard-DfcZEVOj.mjs +0 -12
- package/dist/value-D14I_XgL.mjs +0 -29
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Database introspection
|
|
2
2
|
|
|
3
|
-
> Read one existing database namespace into explainable catalog data and
|
|
3
|
+
> Read one existing database namespace into explainable catalog data and a canonical Snapshot v1 without giving Qubu ownership of the connection.
|
|
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
|
|
@@ -59,9 +59,10 @@ catalog can later support inspection, source generation, or another snapshot
|
|
|
59
59
|
format:
|
|
60
60
|
|
|
61
61
|
```ts
|
|
62
|
-
import { mapCatalogToSnapshot
|
|
62
|
+
import { mapCatalogToSnapshot } from "qubu/introspection"
|
|
63
|
+
import { readCatalog } from "qubu/introspection/sqlite"
|
|
63
64
|
|
|
64
|
-
const catalog = await
|
|
65
|
+
const catalog = await readCatalog(connection, { namespace: "main" })
|
|
65
66
|
const result = mapCatalogToSnapshot(catalog, {
|
|
66
67
|
namespace: "main",
|
|
67
68
|
mode: "strict",
|
|
@@ -84,8 +85,8 @@ catalog. Use `createCompleteIntrospectionCatalog()` to materialize and freeze
|
|
|
84
85
|
all optional collections, then `mapCatalogToCompleteSnapshot()` when an
|
|
85
86
|
adapter-supported family such as views, routines, triggers, partitions,
|
|
86
87
|
collations, comments, or retained opaque and deferred objects must cross the
|
|
87
|
-
strict Snapshot
|
|
88
|
-
|
|
88
|
+
strict Snapshot v1 boundary. `mapCatalogToSnapshot()` delegates to the complete
|
|
89
|
+
mapper, so the canonical result is always Snapshot v1.
|
|
89
90
|
|
|
90
91
|
The result is successful only when Snapshot v1 validation succeeds. A failed
|
|
91
92
|
result may retain the partial catalog and structured diagnostics, but it has no
|
|
@@ -107,9 +108,9 @@ rename. Pass the previous snapshot or an identity hint when a later diff must
|
|
|
107
108
|
preserve identity across a rename. See [snapshot diffing](diff.md) for the
|
|
108
109
|
comparison and hint boundary.
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
or SQLite database such as `main`. It does not combine attached
|
|
112
|
-
multiple PostgreSQL schemas into one
|
|
111
|
+
Each Snapshot v1 result selects one namespace: a PostgreSQL schema, MySQL
|
|
112
|
+
database, or SQLite database such as `main`. It does not combine attached
|
|
113
|
+
databases or multiple PostgreSQL schemas into one value.
|
|
113
114
|
|
|
114
115
|
## Strict and lossy output
|
|
115
116
|
|
|
@@ -126,12 +127,20 @@ generated expressions, checks, predicates, and expression index terms remain
|
|
|
126
127
|
dialect-tagged SQL. Falsy values such as `0`, `false`, `NULL`, and empty
|
|
127
128
|
strings are preserved.
|
|
128
129
|
|
|
130
|
+
References to nested columns, constraints, and indexes include their owning
|
|
131
|
+
table, view, or domain in the complete Snapshot v1 output. References to
|
|
132
|
+
top-level objects remain unscoped, and table-local backing relationships must
|
|
133
|
+
resolve within the table that contains them. Dialect provenance, extensions,
|
|
134
|
+
native storage, and typed expressions are checked against the selected
|
|
135
|
+
snapshot dialect; arbitrary catalog `data` and `configuration` JSON remains
|
|
136
|
+
opaque.
|
|
137
|
+
|
|
129
138
|
PostgreSQL readers expose views, materialized views, sequences, enums, domains,
|
|
130
139
|
collations, routines, triggers, policies, partitions, extensions, comments,
|
|
131
140
|
and ownership as typed complete catalog records. `mapCatalogToCompleteSnapshot`
|
|
132
|
-
retains those records in Snapshot
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
135
144
|
safe normalization, the reader retains a deferred or opaque record and emits a
|
|
136
145
|
diagnostic.
|
|
137
146
|
|
|
@@ -154,13 +163,13 @@ collations used by the selected tables or columns, and comments.
|
|
|
154
163
|
|
|
155
164
|
View definitions come from `INFORMATION_SCHEMA.VIEWS`. The reader cross-
|
|
156
165
|
references each view with its `INFORMATION_SCHEMA.COLUMNS` rows by physical
|
|
157
|
-
table name, so view columns remain attached to the view and Snapshot
|
|
166
|
+
table name, so view columns remain attached to the view and Snapshot v1 can
|
|
158
167
|
validate their own column IDs. A missing definition or an unresolved
|
|
159
168
|
cross-object reference becomes a deferred record with a diagnostic.
|
|
160
169
|
|
|
161
170
|
MySQL scheduled events are kept as `CatalogOpaqueObject` records with their
|
|
162
171
|
metadata and definition tagged as opaque SQL. The reader emits an
|
|
163
|
-
`unmodeled-object` warning, and Snapshot
|
|
172
|
+
`unmodeled-object` warning, and Snapshot v1 retains the record in
|
|
164
173
|
`opaqueObjects` without treating it as a typed routine, trigger, or migration
|
|
165
174
|
operation.
|
|
166
175
|
|
|
@@ -177,9 +186,8 @@ The reader keeps that metadata as normalized typed data and never evaluates
|
|
|
177
186
|
database-provided SQL. Optional source generation remains a later, pure step
|
|
178
187
|
with a controlled literal printer.
|
|
179
188
|
|
|
180
|
-
Use `mapCatalogToCompleteSnapshot()` for the typed
|
|
181
|
-
opaque or deferred boundaries.
|
|
182
|
-
needs the table-only Snapshot v1.
|
|
189
|
+
Use `mapCatalogToSnapshot()` or `mapCatalogToCompleteSnapshot()` for the typed
|
|
190
|
+
MySQL families and their opaque or deferred boundaries.
|
|
183
191
|
|
|
184
192
|
## Diagnostics and safety
|
|
185
193
|
|
package/docs/schema/snapshots.md
CHANGED
|
@@ -14,10 +14,11 @@ const snapshot = createSchemaSnapshot(appSchema)
|
|
|
14
14
|
const json = encodeSchemaSnapshot(snapshot)
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
The v1 envelope contains a format version, an independently versioned
|
|
18
|
-
extension, a versioned naming-policy description,
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
21
|
+
names are values in the snapshot, not identities:
|
|
21
22
|
changing a physical name does not change the TypeScript field or metadata key.
|
|
22
23
|
|
|
23
24
|
Snapshot data is deliberately not executable Qubu state. Expressions are
|
|
@@ -45,6 +46,15 @@ dialect metadata, and broken foreign-key or column references as structured
|
|
|
45
46
|
diagnostics. It does not call `process.exit()` and has no runtime validation
|
|
46
47
|
library dependency.
|
|
47
48
|
|
|
49
|
+
References to nested columns, constraints, and indexes carry an explicit
|
|
50
|
+
`owner: { kind, id }` scope. Table columns, constraints, and indexes are owned
|
|
51
|
+
by their table; view columns are owned by their view; and domain constraints
|
|
52
|
+
are owned by their domain. References to top-level objects remain ownerless,
|
|
53
|
+
and the decoder validates each nested scope independently. Dialect metadata is
|
|
54
|
+
checked only in typed snapshot fields. Extension `data`, `configuration`, and
|
|
55
|
+
other opaque JSON payloads are retained as data and are not interpreted as
|
|
56
|
+
typed metadata.
|
|
57
|
+
|
|
48
58
|
`schemaSnapshotFingerprint()` computes a deterministic content fingerprint from canonical
|
|
49
59
|
JSON. The fingerprint is useful for cache keys and fixture assertions only. It is not
|
|
50
60
|
an entity identity, a rename marker, or migration lineage.
|
|
@@ -91,15 +101,15 @@ Snapshot serialization remains separate from database introspection,
|
|
|
91
101
|
comparison, rename resolution, migration planning, and DDL emission. The
|
|
92
102
|
optional `qubu/introspection` entrypoint can produce the same canonical
|
|
93
103
|
Snapshot v1 data from a user-owned catalog connection. The complete normalized
|
|
94
|
-
catalog can also be encoded
|
|
95
|
-
|
|
104
|
+
catalog can also be encoded with the explicit complete-snapshot APIs described
|
|
105
|
+
in [the catalog model](catalog-model.md).
|
|
96
106
|
Readers and connection lifecycle do not belong to this pure serialization
|
|
97
|
-
layer. Diffing
|
|
107
|
+
layer. Diffing consumes Snapshot v1. Resolved diffs feed
|
|
98
108
|
migration plans, and approved plans feed DDL emission. The package-wide
|
|
99
109
|
[ownership map](../reference/supported-surface.md#ownership-boundary) keeps
|
|
100
110
|
those pure steps separate from application-owned database execution.
|
|
101
111
|
|
|
102
112
|
The optional [schema source generator](code-generation.md) consumes a complete,
|
|
103
113
|
non-lossy introspection result and makes its generated schema the next identity
|
|
104
|
-
baseline. It does not replace snapshot serialization or
|
|
114
|
+
baseline. It does not replace snapshot serialization or populate non-table
|
|
105
115
|
object families.
|
|
@@ -36,14 +36,19 @@ declaration:
|
|
|
36
36
|
import { nativeColumn, nativeStorage, table } from "qubu"
|
|
37
37
|
|
|
38
38
|
const accounts = table("accounts", {
|
|
39
|
-
handle: nativeColumn(nativeStorage("postgresql", 'citext COLLATE "C"')
|
|
39
|
+
handle: nativeColumn(nativeStorage("postgresql", 'citext COLLATE "C"'), {
|
|
40
|
+
sqlType: "postgres.citext",
|
|
41
|
+
}),
|
|
40
42
|
})
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
`nativeStorage()` preserves the declaration text and freezes the descriptor. The
|
|
44
46
|
`ColumnStorageOf`, `ColumnStorageTypeOf`, `ColumnStorageDialectOf`, and
|
|
45
47
|
`ColumnStorageDeclarationOf` helpers read its metadata. Native storage is
|
|
46
|
-
descriptive.
|
|
48
|
+
descriptive. The optional `sqlType` field is the runtime semantic domain passed
|
|
49
|
+
to adapters; provide it for custom domains because the compile-time SQL type is
|
|
50
|
+
not available at runtime. It does not change selection, mutation, or query
|
|
51
|
+
rendering.
|
|
47
52
|
|
|
48
53
|
## Render deterministic schema expressions
|
|
49
54
|
|
|
@@ -89,6 +89,14 @@ operation. This contextual typing does not relabel an expression: comparing a
|
|
|
89
89
|
`SqlUuid` expression with a `SqlText` expression is still rejected. Cast when
|
|
90
90
|
the database operation intentionally changes domains:
|
|
91
91
|
|
|
92
|
+
Scalar text functions bind primitive operands automatically, and `coalesce()`
|
|
93
|
+
uses its first expression to type primitive fallbacks:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
upper("Ada") // UPPER(?)
|
|
97
|
+
coalesce(metrics.label, "Anonymous") // COALESCE("metrics"."label", ?)
|
|
98
|
+
```
|
|
99
|
+
|
|
92
100
|
```ts
|
|
93
101
|
import { cast, like, text } from "qubu"
|
|
94
102
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qubu",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/aleclarson/qubu"
|
|
@@ -32,6 +32,18 @@
|
|
|
32
32
|
"types": "./dist/introspection.d.mts",
|
|
33
33
|
"import": "./dist/introspection.mjs"
|
|
34
34
|
},
|
|
35
|
+
"./introspection/mysql": {
|
|
36
|
+
"types": "./dist/introspection/mysql.d.mts",
|
|
37
|
+
"import": "./dist/introspection/mysql.mjs"
|
|
38
|
+
},
|
|
39
|
+
"./introspection/postgres": {
|
|
40
|
+
"types": "./dist/introspection/postgres.d.mts",
|
|
41
|
+
"import": "./dist/introspection/postgres.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./introspection/sqlite": {
|
|
44
|
+
"types": "./dist/introspection/sqlite.d.mts",
|
|
45
|
+
"import": "./dist/introspection/sqlite.mjs"
|
|
46
|
+
},
|
|
35
47
|
"./mysql": {
|
|
36
48
|
"types": "./dist/mysql.d.mts",
|
|
37
49
|
"import": "./dist/mysql.mjs"
|
|
@@ -112,6 +124,7 @@
|
|
|
112
124
|
"test:type-performance": "node ./scripts/test-type-performance.mjs",
|
|
113
125
|
"diff-check": "vitest --run test/diff.test.ts && pnpm --filter @qubu/migrate test -- plan.test.ts",
|
|
114
126
|
"test:bun": "node ./scripts/test-package.mjs --runtime=bun",
|
|
127
|
+
"test:bun-sql": "bun test adapters/bun-sql/test/bun-sql.test.ts",
|
|
115
128
|
"test:package": "node ./scripts/test-package.mjs",
|
|
116
129
|
"test:workspace-children": "pnpm run build:workspace-packages && node ./scripts/test-workspace-packages.mjs",
|
|
117
130
|
"test:workspace-packages": "pnpm run test:package && pnpm run test:workspace-children",
|