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.
- package/dist/{canonical-BbnqavJm.mjs → canonical-BXUguqfo.mjs} +23 -23
- package/dist/codegen.d.mts +25 -33
- package/dist/codegen.mjs +38 -45
- package/dist/column-hqKr7-1I.mjs +620 -0
- package/dist/{complete-D5Djh-zo.mjs → complete-WYyVozgK.mjs} +50 -50
- package/dist/{complete-types-BavBtv8J.d.mts → complete-types-IjEn5VPN.d.mts} +56 -56
- package/dist/core.d.mts +2 -2
- package/dist/core.mjs +4 -4
- package/dist/ddl.d.mts +12 -12
- package/dist/ddl.mjs +13 -14
- package/dist/{dialect-b2-Z6uBF.mjs → dialect-wUKrnPMB.mjs} +2 -2
- package/dist/diff.d.mts +1 -1
- package/dist/diff.mjs +6 -7
- package/dist/{index-DH0qV6aS.d.mts → index-1DpA3mUh.d.mts} +20 -20
- package/dist/{index-D3ZOwPT-.d.mts → index-CPvfEheG.d.mts} +13 -15
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +94 -95
- package/dist/introspection.d.mts +8 -8
- package/dist/introspection.mjs +29 -30
- package/dist/{json-CUZlv4HT.mjs → json-Db7XRD91.mjs} +2 -2
- package/dist/migration.d.mts +20 -21
- package/dist/migration.mjs +5 -6
- package/dist/{mysql-CKEKGnj4.mjs → mysql-B_cYzzX2.mjs} +237 -7
- package/dist/mysql.d.mts +2 -2
- package/dist/mysql.mjs +3 -3
- package/dist/{on-conflict-4MOBl51J.mjs → on-conflict-hfPW0KmQ.mjs} +3 -4
- package/dist/postgres.d.mts +5 -5
- package/dist/postgres.mjs +6 -6
- package/dist/{registry-CXV8u7Pt.mjs → registry-BRMLYwDp.mjs} +26 -29
- package/dist/{relational-DuQ9IHSb.mjs → relational-BZ3WDPzC.mjs} +2 -2
- package/dist/schema.d.mts +1 -1
- package/dist/schema.mjs +5 -6
- package/dist/{snapshot-DJpfmxhQ.mjs → snapshot-C-W65HEd.mjs} +5 -5
- package/dist/snapshot.d.mts +3 -3
- package/dist/snapshot.mjs +5 -7
- package/dist/{source-DGO3DRgg.mjs → source-BcS2AsIg.mjs} +6 -8
- package/dist/{serialize-CFtYYAdk.mjs → sqlite-Cg0nwYEH.mjs} +326 -12
- package/dist/sqlite.d.mts +1 -1
- package/dist/sqlite.mjs +2 -2
- package/dist/{standard-BTVYKh_F.mjs → standard-DfcZEVOj.mjs} +1 -1
- package/dist/{table-D6rcs8SB.mjs → table-Bp5irMSj.mjs} +2 -3
- package/dist/{types-Deo_q43Y.d.mts → types-BK1COGZe.d.mts} +1113 -1128
- package/dist/{types-g-vVvj1B.mjs → types-JM3FcAnX.mjs} +7 -8
- package/dist/{types-CSNJTYaM.d.mts → types-JSZHpUEj.d.mts} +83 -84
- package/dist/{value-b6OFZXVS.mjs → value-Bi71Agyf.mjs} +1 -1
- package/dist/vite/ambient.d.ts +309 -340
- package/dist/vite.d.mts +5 -6
- package/dist/vite.mjs +3 -4
- package/docs/dialects-and-execution.md +45 -55
- package/docs/getting-started.md +4 -4
- package/docs/guides/better-auth.md +57 -0
- package/docs/guides/compose-queries.md +24 -67
- package/docs/guides/drizzle.md +23 -23
- package/docs/guides/extensions/dialects.md +4 -4
- package/docs/guides/extensions/sources-and-clauses.md +15 -15
- package/docs/guides/extensions/typed-expressions.md +13 -17
- package/docs/guides/extensions/unsafe-syntax.md +3 -3
- package/docs/guides/json.md +7 -7
- package/docs/guides/mutations.md +14 -21
- package/docs/guides/select/conditions.md +6 -8
- package/docs/guides/select/grouping-and-windows.md +4 -15
- package/docs/guides/select/ordering-and-pagination.md +6 -19
- package/docs/guides/select/overview.md +12 -26
- package/docs/guides/sql-templates.md +20 -24
- package/docs/guides/vite-plugin.md +9 -13
- package/docs/index.md +5 -7
- package/docs/query-model/fragments.md +4 -15
- package/docs/query-model/result-shapes.md +11 -14
- package/docs/query-model/source-scope.md +31 -49
- package/docs/reference/mysql-snapshot.md +2 -5
- package/docs/reference/postgres-snapshot.md +3 -3
- package/docs/reference/sqlite-snapshot.md +2 -5
- package/docs/reference/supported-surface.md +26 -26
- package/docs/schema/catalog-model.md +2 -5
- package/docs/schema/code-generation.md +18 -18
- package/docs/schema/columns-and-writes.md +17 -25
- package/docs/schema/constraints-and-indexes.md +36 -52
- package/docs/schema/ddl-emission.md +6 -6
- package/docs/schema/diff.md +5 -5
- package/docs/schema/introspection.md +7 -7
- package/docs/schema/migration-plans.md +9 -9
- package/docs/schema/snapshots.md +3 -3
- package/docs/schema/storage-and-schema-sql.md +11 -11
- package/docs/schema/tables-and-names.md +11 -14
- package/docs/sql-semantic-types.md +10 -10
- package/docs/troubleshooting.md +10 -10
- package/package.json +21 -33
- package/skills/qubu/agents/openai.yaml +3 -3
- package/dist/column-D-8OqGuV.mjs +0 -328
- package/dist/column-LV7oGQde.mjs +0 -296
- package/dist/drizzle-mysql.d.mts +0 -24
- package/dist/drizzle-mysql.mjs +0 -72
- package/dist/drizzle-postgres.d.mts +0 -24
- package/dist/drizzle-postgres.mjs +0 -73
- package/dist/drizzle-sqlite.d.mts +0 -57
- package/dist/drizzle-sqlite.mjs +0 -108
- package/dist/drizzle.d.mts +0 -13
- package/dist/drizzle.mjs +0 -2
- package/dist/errors-BGCoLe_r.mjs +0 -14
- package/dist/postgres-BK2APkKP.mjs +0 -236
- package/dist/runtime-Cn_Xgzta.mjs +0 -193
- package/dist/sqlite-CrsK0Fza.mjs +0 -320
- package/dist/types-DZsueVoI.d.mts +0 -45
|
@@ -54,20 +54,9 @@ Parameter values are not fragment metadata. A renderer calls
|
|
|
54
54
|
`context.parameter(value)`, and `render()` collects values in placeholder order:
|
|
55
55
|
|
|
56
56
|
```ts
|
|
57
|
-
import {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
from,
|
|
61
|
-
integer,
|
|
62
|
-
like,
|
|
63
|
-
render,
|
|
64
|
-
select,
|
|
65
|
-
table,
|
|
66
|
-
text,
|
|
67
|
-
where,
|
|
68
|
-
} from 'qubu'
|
|
69
|
-
|
|
70
|
-
const users = table('users', {
|
|
57
|
+
import { and, eq, from, integer, like, render, select, table, text, where } from "qubu"
|
|
58
|
+
|
|
59
|
+
const users = table("users", {
|
|
71
60
|
id: integer(),
|
|
72
61
|
name: text(),
|
|
73
62
|
})
|
|
@@ -75,7 +64,7 @@ const users = table('users', {
|
|
|
75
64
|
const query = select(
|
|
76
65
|
{ id: users.id },
|
|
77
66
|
from(users),
|
|
78
|
-
where(and(eq(users.id, 7), like(users.name,
|
|
67
|
+
where(and(eq(users.id, 7), like(users.name, "%Ada%"))),
|
|
79
68
|
)
|
|
80
69
|
|
|
81
70
|
render(query)
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
An object projection uses its keys as result names:
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import { from, integer, select, table, text, upper } from
|
|
10
|
+
import { from, integer, select, table, text, upper } from "qubu"
|
|
11
11
|
|
|
12
|
-
const users = table(
|
|
12
|
+
const users = table("users", {
|
|
13
13
|
id: integer(),
|
|
14
14
|
name: text(),
|
|
15
15
|
})
|
|
@@ -19,7 +19,7 @@ const query = select(
|
|
|
19
19
|
id: users.id,
|
|
20
20
|
displayName: upper(users.name),
|
|
21
21
|
},
|
|
22
|
-
from(users)
|
|
22
|
+
from(users),
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
type Row = typeof query.row
|
|
@@ -31,12 +31,9 @@ shaped result. Reserve `all(source)` for a whole-source result contract. It
|
|
|
31
31
|
expands to named columns, so the SQL columns and inferred row keys stay aligned:
|
|
32
32
|
|
|
33
33
|
```ts
|
|
34
|
-
import { all, from, select, upper } from
|
|
34
|
+
import { all, from, select, upper } from "qubu"
|
|
35
35
|
|
|
36
|
-
const query = select(
|
|
37
|
-
{ ...all(users), normalizedName: upper(users.name) },
|
|
38
|
-
from(users)
|
|
39
|
-
)
|
|
36
|
+
const query = select({ ...all(users), normalizedName: upper(users.name) }, from(users))
|
|
40
37
|
```
|
|
41
38
|
|
|
42
39
|
When a query becomes a CTE or derived table, its row shape becomes the columns
|
|
@@ -53,13 +50,13 @@ source widens with `null`, while an expression with its own non-null result
|
|
|
53
50
|
contract can stay non-null:
|
|
54
51
|
|
|
55
52
|
```ts
|
|
56
|
-
import { count, eq, from, integer, leftJoin, select, table, text } from
|
|
53
|
+
import { count, eq, from, integer, leftJoin, select, table, text } from "qubu"
|
|
57
54
|
|
|
58
|
-
const users = table(
|
|
55
|
+
const users = table("users", {
|
|
59
56
|
id: integer(),
|
|
60
57
|
name: text(),
|
|
61
58
|
})
|
|
62
|
-
const posts = table(
|
|
59
|
+
const posts = table("posts", {
|
|
63
60
|
id: integer(),
|
|
64
61
|
authorId: integer(),
|
|
65
62
|
title: text(),
|
|
@@ -72,7 +69,7 @@ const query = select(
|
|
|
72
69
|
postCount: count(posts.id),
|
|
73
70
|
},
|
|
74
71
|
from(users),
|
|
75
|
-
leftJoin(posts, eq(users.id, posts.authorId))
|
|
72
|
+
leftJoin(posts, eq(users.id, posts.authorId)),
|
|
76
73
|
)
|
|
77
74
|
|
|
78
75
|
type Row = typeof query.row
|
|
@@ -89,9 +86,9 @@ expression with non-null branches can return a non-null result.
|
|
|
89
86
|
result includes `null` when the query may return no rows:
|
|
90
87
|
|
|
91
88
|
```ts
|
|
92
|
-
import { fetchFirst, from, scalar, select, table, value } from
|
|
89
|
+
import { fetchFirst, from, scalar, select, table, value } from "qubu"
|
|
93
90
|
|
|
94
|
-
const users = table(
|
|
91
|
+
const users = table("users", { id: integer() })
|
|
95
92
|
const firstUser = select({ id: users.id }, from(users), fetchFirst(1))
|
|
96
93
|
|
|
97
94
|
const firstId = scalar(firstUser)
|
|
@@ -13,12 +13,12 @@ Qubu reports a missing source when a query selects a column from a table that
|
|
|
13
13
|
does not appear in the query:
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
|
-
import { from, integer, select, table, text } from
|
|
16
|
+
import { from, integer, select, table, text } from "qubu"
|
|
17
17
|
|
|
18
|
-
const users = table(
|
|
18
|
+
const users = table("users", {
|
|
19
19
|
id: integer(),
|
|
20
20
|
})
|
|
21
|
-
const posts = table(
|
|
21
|
+
const posts = table("posts", {
|
|
22
22
|
id: integer(),
|
|
23
23
|
title: text(),
|
|
24
24
|
})
|
|
@@ -31,12 +31,12 @@ Add the source that owns the column, or join it with a condition that refers to
|
|
|
31
31
|
both sources:
|
|
32
32
|
|
|
33
33
|
```ts
|
|
34
|
-
import { eq, from, innerJoin, integer, select, table } from
|
|
34
|
+
import { eq, from, innerJoin, integer, select, table } from "qubu"
|
|
35
35
|
|
|
36
|
-
const users = table(
|
|
36
|
+
const users = table("users", {
|
|
37
37
|
id: integer(),
|
|
38
38
|
})
|
|
39
|
-
const posts = table(
|
|
39
|
+
const posts = table("posts", {
|
|
40
40
|
id: integer(),
|
|
41
41
|
authorId: integer(),
|
|
42
42
|
})
|
|
@@ -44,7 +44,7 @@ const posts = table('posts', {
|
|
|
44
44
|
const query = select(
|
|
45
45
|
{ userId: users.id, postId: posts.id },
|
|
46
46
|
from(users),
|
|
47
|
-
innerJoin(posts, eq(users.id, posts.authorId))
|
|
47
|
+
innerJoin(posts, eq(users.id, posts.authorId)),
|
|
48
48
|
)
|
|
49
49
|
```
|
|
50
50
|
|
|
@@ -54,14 +54,14 @@ Aliases, CTEs, derived queries, and custom sources expose new source identities.
|
|
|
54
54
|
Use their columns after wrapping the original source:
|
|
55
55
|
|
|
56
56
|
```ts
|
|
57
|
-
import { alias, from, integer, select, table, text } from
|
|
57
|
+
import { alias, from, integer, select, table, text } from "qubu"
|
|
58
58
|
|
|
59
|
-
const users = table(
|
|
59
|
+
const users = table("users", {
|
|
60
60
|
id: integer(),
|
|
61
61
|
name: text(),
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
const author = alias(users,
|
|
64
|
+
const author = alias(users, "author")
|
|
65
65
|
const query = select({ name: author.name }, from(author))
|
|
66
66
|
```
|
|
67
67
|
|
|
@@ -72,10 +72,10 @@ The same rule applies to a CTE or derived query. A query's selected row becomes
|
|
|
72
72
|
the set of columns exposed by its new source:
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
-
import { alias, from, lower, select } from
|
|
75
|
+
import { alias, from, lower, select } from "qubu"
|
|
76
76
|
|
|
77
77
|
const names = select({ name: lower(users.name) }, from(users))
|
|
78
|
-
const namesSource = alias(names,
|
|
78
|
+
const namesSource = alias(names, "names")
|
|
79
79
|
|
|
80
80
|
const query = select({ name: namesSource.name }, from(namesSource))
|
|
81
81
|
```
|
|
@@ -90,35 +90,31 @@ Use `customSource()` for a table-valued function or another relation that
|
|
|
90
90
|
definitions, and complete relation renderer:
|
|
91
91
|
|
|
92
92
|
```ts
|
|
93
|
-
import { eq, from, integer, select, text, where } from
|
|
94
|
-
import { identifier } from
|
|
95
|
-
import { customSource } from
|
|
93
|
+
import { eq, from, integer, select, text, where } from "qubu"
|
|
94
|
+
import { identifier } from "qubu/core"
|
|
95
|
+
import { customSource } from "qubu/schema"
|
|
96
96
|
|
|
97
97
|
const entries = customSource({
|
|
98
98
|
identity: {
|
|
99
|
-
sourceKind:
|
|
100
|
-
name:
|
|
101
|
-
alias:
|
|
99
|
+
sourceKind: "table-function",
|
|
100
|
+
name: "json_each",
|
|
101
|
+
alias: "entry",
|
|
102
102
|
},
|
|
103
|
-
sourceKind:
|
|
104
|
-
reference: identifier(
|
|
103
|
+
sourceKind: "table-function",
|
|
104
|
+
reference: identifier("entry"),
|
|
105
105
|
columns: {
|
|
106
106
|
key: integer(),
|
|
107
107
|
value: text({ nullable: true }),
|
|
108
108
|
},
|
|
109
109
|
render(context) {
|
|
110
|
-
context.append(
|
|
110
|
+
context.append("json_each(")
|
|
111
111
|
context.parameter('{"a":1}')
|
|
112
|
-
context.append(
|
|
113
|
-
context.render(identifier(
|
|
112
|
+
context.append(") AS ")
|
|
113
|
+
context.render(identifier("entry"))
|
|
114
114
|
},
|
|
115
115
|
})
|
|
116
116
|
|
|
117
|
-
const query = select(
|
|
118
|
-
{ value: entries.value },
|
|
119
|
-
from(entries),
|
|
120
|
-
where(eq(entries.key, 7))
|
|
121
|
-
)
|
|
117
|
+
const query = select({ value: entries.value }, from(entries), where(eq(entries.key, 7)))
|
|
122
118
|
```
|
|
123
119
|
|
|
124
120
|
`identity` is the type-level source key. `reference` is the SQL qualifier used
|
|
@@ -135,20 +131,10 @@ Use `correlate()` when an inner query intentionally reads a source from its
|
|
|
135
131
|
enclosing query. The provision changes type checking but emits no SQL:
|
|
136
132
|
|
|
137
133
|
```ts
|
|
138
|
-
import {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
from,
|
|
143
|
-
integer,
|
|
144
|
-
lateral,
|
|
145
|
-
select,
|
|
146
|
-
table,
|
|
147
|
-
where,
|
|
148
|
-
} from 'qubu'
|
|
149
|
-
|
|
150
|
-
const users = table('users', { id: integer() })
|
|
151
|
-
const posts = table('posts', {
|
|
134
|
+
import { correlate, crossJoin, eq, from, integer, lateral, select, table, where } from "qubu"
|
|
135
|
+
|
|
136
|
+
const users = table("users", { id: integer() })
|
|
137
|
+
const posts = table("posts", {
|
|
152
138
|
id: integer(),
|
|
153
139
|
authorId: integer(),
|
|
154
140
|
})
|
|
@@ -157,15 +143,11 @@ const recentPost = select(
|
|
|
157
143
|
{ id: posts.id },
|
|
158
144
|
from(posts),
|
|
159
145
|
correlate(users),
|
|
160
|
-
where(eq(posts.authorId, users.id))
|
|
146
|
+
where(eq(posts.authorId, users.id)),
|
|
161
147
|
)
|
|
162
148
|
|
|
163
|
-
const recent = lateral(recentPost,
|
|
164
|
-
const query = select(
|
|
165
|
-
{ userId: users.id, postId: recent.id },
|
|
166
|
-
from(users),
|
|
167
|
-
crossJoin(recent)
|
|
168
|
-
)
|
|
149
|
+
const recent = lateral(recentPost, "recent_post")
|
|
150
|
+
const query = select({ userId: users.id, postId: recent.id }, from(users), crossJoin(recent))
|
|
169
151
|
```
|
|
170
152
|
|
|
171
153
|
The inner query consumes `posts` locally. The enclosing `users` source satisfies
|
|
@@ -7,10 +7,7 @@
|
|
|
7
7
|
Import the adapter from the optional snapshot entrypoint:
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import {
|
|
11
|
-
createMysqlSchemaSnapshot,
|
|
12
|
-
tryCreateMysqlSchemaSnapshot,
|
|
13
|
-
} from 'qubu/snapshot'
|
|
10
|
+
import { createMysqlSchemaSnapshot, tryCreateMysqlSchemaSnapshot } from "qubu/snapshot"
|
|
14
11
|
|
|
15
12
|
const snapshot = createMysqlSchemaSnapshot(appSchema)
|
|
16
13
|
const result = tryCreateMysqlSchemaSnapshot(appSchema)
|
|
@@ -44,7 +41,7 @@ a schema may include a MySQL engine or version-specific feature:
|
|
|
44
41
|
const result = tryCreateMysqlSchemaSnapshot(appSchema)
|
|
45
42
|
if (!result.ok) {
|
|
46
43
|
for (const issue of result.diagnostics) {
|
|
47
|
-
console.error(issue.path.join(
|
|
44
|
+
console.error(issue.path.join("."), issue.code, issue.message)
|
|
48
45
|
}
|
|
49
46
|
}
|
|
50
47
|
```
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
createSchemaSnapshot,
|
|
12
12
|
createPostgresSchemaSnapshot,
|
|
13
13
|
postgresSnapshotAdapter,
|
|
14
|
-
} from
|
|
14
|
+
} from "qubu/snapshot"
|
|
15
15
|
|
|
16
16
|
const snapshot = createPostgresSchemaSnapshot(appSchema)
|
|
17
17
|
// Equivalent: createSchemaSnapshot(appSchema, { adapter: postgresSnapshotAdapter })
|
|
@@ -46,12 +46,12 @@ schema and application boundaries.
|
|
|
46
46
|
Use the non-throwing form when a schema may contain a server-specific feature:
|
|
47
47
|
|
|
48
48
|
```ts
|
|
49
|
-
import { tryCreatePostgresSchemaSnapshot } from
|
|
49
|
+
import { tryCreatePostgresSchemaSnapshot } from "qubu/snapshot"
|
|
50
50
|
|
|
51
51
|
const result = tryCreatePostgresSchemaSnapshot(appSchema)
|
|
52
52
|
if (!result.ok) {
|
|
53
53
|
for (const issue of result.diagnostics) {
|
|
54
|
-
console.error(issue.path.join(
|
|
54
|
+
console.error(issue.path.join("."), issue.code, issue.message)
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
```
|
|
@@ -5,10 +5,7 @@
|
|
|
5
5
|
Import the adapter from the optional snapshot entrypoint:
|
|
6
6
|
|
|
7
7
|
```ts
|
|
8
|
-
import {
|
|
9
|
-
createSqliteSchemaSnapshot,
|
|
10
|
-
tryCreateSqliteSchemaSnapshot,
|
|
11
|
-
} from 'qubu/snapshot'
|
|
8
|
+
import { createSqliteSchemaSnapshot, tryCreateSqliteSchemaSnapshot } from "qubu/snapshot"
|
|
12
9
|
|
|
13
10
|
const snapshot = createSqliteSchemaSnapshot(appSchema)
|
|
14
11
|
const result = tryCreateSqliteSchemaSnapshot(appSchema)
|
|
@@ -42,7 +39,7 @@ schema may include a feature that depends on a SQLite version or table shape:
|
|
|
42
39
|
const result = tryCreateSqliteSchemaSnapshot(appSchema)
|
|
43
40
|
if (!result.ok) {
|
|
44
41
|
for (const issue of result.diagnostics) {
|
|
45
|
-
console.error(issue.path.join(
|
|
42
|
+
console.error(issue.path.join("."), issue.code, issue.message)
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
```
|
|
@@ -4,32 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
## Package entrypoints
|
|
6
6
|
|
|
7
|
-
| Import
|
|
8
|
-
|
|
|
9
|
-
| `qubu`
|
|
10
|
-
| `qubu/core`
|
|
11
|
-
| `qubu/codegen`
|
|
12
|
-
| `qubu/ddl`
|
|
13
|
-
| `qubu/diff`
|
|
14
|
-
| `qubu/
|
|
15
|
-
| `qubu/
|
|
16
|
-
| `qubu/
|
|
17
|
-
| `qubu/
|
|
18
|
-
| `qubu/
|
|
19
|
-
| `qubu/
|
|
20
|
-
| `qubu/
|
|
21
|
-
| `qubu/
|
|
22
|
-
| `qubu/
|
|
23
|
-
|
|
|
24
|
-
|
|
|
25
|
-
|
|
|
26
|
-
|
|
|
27
|
-
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
constructors live on their database subpaths. The
|
|
32
|
-
standard SQL policy by default.
|
|
7
|
+
| Import | Kind | Use it for |
|
|
8
|
+
| ------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| `qubu` | Runtime | Ordinary query and schema definitions, reads, writes, SQL templates, rendering, EXPLAIN, and execution contracts |
|
|
10
|
+
| `qubu/core` | Runtime | Fragment and rendering primitives, dialect construction, SQL types, and extension constructors |
|
|
11
|
+
| `qubu/codegen` | Runtime | Deterministic machine-owned TypeScript schemas from complete, non-lossy introspection |
|
|
12
|
+
| `qubu/ddl` | Runtime | DDL preflight and deterministic PostgreSQL, SQLite, or MySQL emission from a migration plan |
|
|
13
|
+
| `qubu/diff` | Runtime | Canonical Snapshot v1 or v2 comparison, rename hints, suggestions, and safety diagnostics |
|
|
14
|
+
| `qubu/introspection` | Runtime | Catalog readers, normalized catalogs, and mapping to Snapshot v1 or v2 |
|
|
15
|
+
| `qubu/migration` | Runtime | Pure migration planning with dependencies, decisions, preconditions, and explicit custom SQL |
|
|
16
|
+
| `qubu/mysql` | Runtime | The MySQL query dialect policy |
|
|
17
|
+
| `qubu/postgres` | Runtime | PostgreSQL query dialect helpers such as `postgresDialect()` and `ilike()` |
|
|
18
|
+
| `qubu/schema` | Runtime | Advanced schema metadata, storage and constraint models, source models, and schema-expression extensions |
|
|
19
|
+
| `qubu/snapshot` | Runtime | Canonical Snapshot v1 and v2 traversal, encoding, decoding, diagnostics, and digests |
|
|
20
|
+
| `qubu/sqlite` | Runtime | The SQLite query dialect policy |
|
|
21
|
+
| `qubu/vite` | Runtime | The optional `qubu()` Vite compiler hint |
|
|
22
|
+
| `qubu/package.json` | JSON | The published package manifest |
|
|
23
|
+
| `@qubu/drizzle` | Runtime | Shared Drizzle conversion errors and dialect types |
|
|
24
|
+
| `@qubu/drizzle/mysql` | Runtime | Runtime conversion from Qubu schemas to MySQL Drizzle tables |
|
|
25
|
+
| `@qubu/drizzle/postgres` | Runtime | Runtime conversion from Qubu schemas to PostgreSQL Drizzle tables |
|
|
26
|
+
| `@qubu/drizzle/sqlite` | Runtime | Runtime conversion from Qubu schemas to SQLite Drizzle tables |
|
|
27
|
+
| `@qubu/better-auth` | Runtime | Better Auth schema derivation and native PostgreSQL, MySQL, and SQLite adapter behavior |
|
|
28
|
+
| `qubu/globals` | TypeScript types | Opt-in ambient declarations for directive-bearing modules |
|
|
29
|
+
|
|
30
|
+
The package validator checks every declared entrypoint in each packed workspace
|
|
31
|
+
package. Concrete dialect constructors live on their database subpaths. The
|
|
32
|
+
root renderer uses Qubu's standard SQL policy by default.
|
|
33
33
|
|
|
34
34
|
Snapshot dialect behavior is documented in the [PostgreSQL](postgres-snapshot.md),
|
|
35
35
|
[SQLite](sqlite-snapshot.md), and [MySQL](mysql-snapshot.md) support matrices.
|
|
@@ -12,7 +12,7 @@ families and an immutable materializer:
|
|
|
12
12
|
import {
|
|
13
13
|
createCompleteIntrospectionCatalog,
|
|
14
14
|
mapCatalogToCompleteSnapshot,
|
|
15
|
-
} from
|
|
15
|
+
} from "qubu/introspection"
|
|
16
16
|
|
|
17
17
|
const completeCatalog = createCompleteIntrospectionCatalog(catalog)
|
|
18
18
|
const result = mapCatalogToCompleteSnapshot(completeCatalog)
|
|
@@ -36,10 +36,7 @@ references and are not used as logical IDs.
|
|
|
36
36
|
`qubu/snapshot` provides the strict complete format as a separate API:
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
|
-
import {
|
|
40
|
-
decodeCompleteSchemaSnapshot,
|
|
41
|
-
encodeCompleteSchemaSnapshot,
|
|
42
|
-
} from 'qubu/snapshot'
|
|
39
|
+
import { decodeCompleteSchemaSnapshot, encodeCompleteSchemaSnapshot } from "qubu/snapshot"
|
|
43
40
|
|
|
44
41
|
const encoded = encodeCompleteSchemaSnapshot(snapshotV2)
|
|
45
42
|
const decoded = decodeCompleteSchemaSnapshot(encoded)
|
|
@@ -12,19 +12,19 @@ Read and map one namespace in strict mode, then pass that exact result to the
|
|
|
12
12
|
generator:
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
|
-
import { writeFile } from
|
|
16
|
-
import { generateSchemaSource } from
|
|
17
|
-
import { mapCatalogToSnapshot, readSqliteCatalog } from
|
|
15
|
+
import { writeFile } from "node:fs/promises"
|
|
16
|
+
import { generateSchemaSource } from "qubu/codegen"
|
|
17
|
+
import { mapCatalogToSnapshot, readSqliteCatalog } from "qubu/introspection"
|
|
18
18
|
|
|
19
|
-
const catalog = await readSqliteCatalog(connection, { namespace:
|
|
20
|
-
const introspection = mapCatalogToSnapshot(catalog, { namespace:
|
|
19
|
+
const catalog = await readSqliteCatalog(connection, { namespace: "main" })
|
|
20
|
+
const introspection = mapCatalogToSnapshot(catalog, { namespace: "main" })
|
|
21
21
|
const generated = generateSchemaSource(introspection)
|
|
22
22
|
|
|
23
23
|
if (!generated.ok) {
|
|
24
|
-
throw new Error(generated.diagnostics.map(issue => issue.message).join(
|
|
24
|
+
throw new Error(generated.diagnostics.map((issue) => issue.message).join("\n"))
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
await writeFile(
|
|
27
|
+
await writeFile("src/schema.generated.ts", generated.source, "utf8")
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
`writeFile()` belongs to the application; `generateSchemaSource()` only
|
|
@@ -48,13 +48,13 @@ the generated module is accepted, its serialized snapshot becomes the identity
|
|
|
48
48
|
baseline for the next catalog read:
|
|
49
49
|
|
|
50
50
|
```ts
|
|
51
|
-
import { mapCatalogToSnapshot } from
|
|
52
|
-
import { createSqliteSchemaSnapshot } from
|
|
53
|
-
import { mainSchema } from
|
|
51
|
+
import { mapCatalogToSnapshot } from "qubu/introspection"
|
|
52
|
+
import { createSqliteSchemaSnapshot } from "qubu/snapshot"
|
|
53
|
+
import { mainSchema } from "./schema.generated.ts"
|
|
54
54
|
|
|
55
55
|
const previousSnapshot = createSqliteSchemaSnapshot(mainSchema)
|
|
56
56
|
const next = mapCatalogToSnapshot(nextCatalog, {
|
|
57
|
-
namespace:
|
|
57
|
+
namespace: "main",
|
|
58
58
|
previousSnapshot,
|
|
59
59
|
})
|
|
60
60
|
```
|
|
@@ -75,17 +75,17 @@ Use the controlled callbacks to adopt trusted names or application mappings:
|
|
|
75
75
|
```ts
|
|
76
76
|
const generated = generateSchemaSource(introspection, {
|
|
77
77
|
naming(context) {
|
|
78
|
-
if (context.kind ===
|
|
79
|
-
return
|
|
78
|
+
if (context.kind === "table" && context.physicalName === "user_records") {
|
|
79
|
+
return "users"
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
mapColumn(context) {
|
|
83
|
-
if (context.columnPhysicalName ===
|
|
83
|
+
if (context.columnPhysicalName === "account_id") {
|
|
84
84
|
return {
|
|
85
|
-
output:
|
|
86
|
-
insert:
|
|
87
|
-
update:
|
|
88
|
-
sqlDomain:
|
|
85
|
+
output: "string",
|
|
86
|
+
insert: "string",
|
|
87
|
+
update: "string",
|
|
88
|
+
sqlDomain: "uuid",
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
},
|
|
@@ -17,9 +17,9 @@ Use `column<Output, Insert, Update>()` when the driver returns a different type
|
|
|
17
17
|
from the type the application writes:
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
|
-
import { column, integer, table, text } from
|
|
20
|
+
import { column, integer, table, text } from "qubu"
|
|
21
21
|
|
|
22
|
-
const accounts = table(
|
|
22
|
+
const accounts = table("accounts", {
|
|
23
23
|
id: integer({ generated: true }),
|
|
24
24
|
email: text(),
|
|
25
25
|
nickname: text({ nullable: true, hasDefault: true }),
|
|
@@ -36,27 +36,19 @@ The legacy hasDefault and generated flags describe the write contract. Use
|
|
|
36
36
|
complete metadata when schema tooling also needs the database fact:
|
|
37
37
|
|
|
38
38
|
```ts
|
|
39
|
-
import {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
table,
|
|
45
|
-
text,
|
|
46
|
-
value,
|
|
47
|
-
} from 'qubu'
|
|
48
|
-
import { defineSchemaExpression } from 'qubu/schema'
|
|
49
|
-
|
|
50
|
-
const currentTimestamp = defineSchemaExpression('function', context => {
|
|
51
|
-
context.append('CURRENT_TIMESTAMP')
|
|
39
|
+
import { boolean, generatedColumn, identityColumn, integer, table, text, value } from "qubu"
|
|
40
|
+
import { defineSchemaExpression } from "qubu/schema"
|
|
41
|
+
|
|
42
|
+
const currentTimestamp = defineSchemaExpression("function", (context) => {
|
|
43
|
+
context.append("CURRENT_TIMESTAMP")
|
|
52
44
|
})
|
|
53
45
|
|
|
54
|
-
const accounts = table(
|
|
55
|
-
id: integer({ identity: identityColumn(
|
|
56
|
-
status: text({ default:
|
|
46
|
+
const accounts = table("accounts", {
|
|
47
|
+
id: integer({ identity: identityColumn("always") }),
|
|
48
|
+
status: text({ default: "pending" }),
|
|
57
49
|
active: boolean({ default: true }),
|
|
58
50
|
score: integer({
|
|
59
|
-
generatedColumn: generatedColumn(value(1),
|
|
51
|
+
generatedColumn: generatedColumn(value(1), "stored"),
|
|
60
52
|
}),
|
|
61
53
|
createdAt: text({
|
|
62
54
|
default: currentTimestamp,
|
|
@@ -90,10 +82,10 @@ Use `$type<T>()` to narrow a helper's TypeScript type without changing its
|
|
|
90
82
|
runtime column definition:
|
|
91
83
|
|
|
92
84
|
```ts
|
|
93
|
-
import { table, text } from
|
|
85
|
+
import { table, text } from "qubu"
|
|
94
86
|
|
|
95
|
-
const users = table(
|
|
96
|
-
status: text().$type<
|
|
87
|
+
const users = table("users", {
|
|
88
|
+
status: text().$type<"active" | "disabled">(),
|
|
97
89
|
})
|
|
98
90
|
```
|
|
99
91
|
|
|
@@ -106,14 +98,14 @@ does not validate values at runtime or add a database constraint.
|
|
|
106
98
|
code. The following example uses the accounts table from the earlier example:
|
|
107
99
|
|
|
108
100
|
```ts
|
|
109
|
-
import type { TableInsertInput, TableUpdateInput } from
|
|
101
|
+
import type { TableInsertInput, TableUpdateInput } from "qubu"
|
|
110
102
|
|
|
111
103
|
type AccountInsert = TableInsertInput<typeof accounts.definitions>
|
|
112
104
|
type AccountUpdate = TableUpdateInput<typeof accounts.definitions>
|
|
113
105
|
|
|
114
106
|
const insert: AccountInsert = {
|
|
115
|
-
email:
|
|
116
|
-
externalScore:
|
|
107
|
+
email: "ada@example.com",
|
|
108
|
+
externalScore: "10",
|
|
117
109
|
}
|
|
118
110
|
|
|
119
111
|
const update: AccountUpdate = {
|