@workerstack/database 0.22.0 → 0.22.1
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 +46 -7
- package/package.json +3 -2
- package/src/cli/args.ts +4 -2
- package/src/cli/codegen.ts +2 -2
- package/src/cli/comb-config.ts +8 -3
- package/src/cli/file-path.ts +25 -0
- package/src/cli/migrate-apply.ts +5 -21
- package/src/cli/migrate-d1.ts +5 -1
- package/src/cli/migrate-json.ts +48 -0
- package/src/cli/migrate.ts +26 -4
- package/src/migrate/core/apply.ts +63 -22
- package/src/migrate/core/atlas-apply-runs.ts +15 -26
- package/src/migrate/core/cleanup.ts +22 -10
- package/src/migrate/core/d1-engine-child.mjs +27 -11
- package/src/migrate/core/d1-history.ts +23 -26
- package/src/migrate/core/d1-wrangler-error.ts +24 -1
- package/src/migrate/core/pg-replay-commit.ts +41 -38
- package/src/migrate/core/pg-replay-drops.ts +17 -32
- package/src/migrate/core/pg-replay-hidden.ts +75 -0
- package/src/migrate/core/pg-replay-roles.ts +2 -4
- package/src/migrate/core/pg-replay.ts +21 -19
- package/src/migrate/core/pg-server-snapshot.ts +4 -24
- package/src/migrate/core/proof-readers.ts +80 -0
- package/src/migrate/core/proof-run.ts +19 -5
- package/src/migrate/core/proof-scope.ts +27 -14
- package/src/migrate/core/sql-code.ts +36 -5
- package/src/migrate/core/sql-scan.ts +7 -1
- package/src/migrate/core/sqlite-keywords.ts +70 -0
- package/src/migrate/core/stopped.ts +70 -0
- package/src/migrate/core/trigger-write.d.mts +7 -0
- package/src/migrate/core/trigger-write.mjs +42 -0
- package/src/query/cursor-mint.ts +11 -18
- package/src/query/cursor-refusals.ts +22 -11
- package/src/query/descriptions.ts +4 -9
- package/src/query/filter-parse.ts +80 -22
- package/src/query/filter-validate.ts +10 -13
- package/src/query/filter.ts +40 -18
- package/src/query/list-extras.ts +7 -10
- package/src/query/list-schema.ts +0 -2
- package/src/query/merged.ts +3 -2
- package/src/query/pagination.ts +30 -6
- package/src/query/rounded-key.ts +5 -8
- package/src/query/schema-params.ts +12 -5
- package/src/query/select-validate.ts +7 -4
- package/src/query/sqlite/cursor-fit.ts +10 -2
- package/src/query/trusted.ts +7 -2
- package/types/cli/args.d.ts.map +1 -1
- package/types/cli/comb-config.d.ts +5 -2
- package/types/cli/comb-config.d.ts.map +1 -1
- package/types/cli/file-path.d.ts +11 -0
- package/types/cli/file-path.d.ts.map +1 -0
- package/types/cli/migrate-apply.d.ts +1 -0
- package/types/cli/migrate-apply.d.ts.map +1 -1
- package/types/cli/migrate-d1.d.ts.map +1 -1
- package/types/cli/migrate-json.d.ts +4 -0
- package/types/cli/migrate-json.d.ts.map +1 -0
- package/types/cli/migrate.d.ts.map +1 -1
- package/types/migrate/core/apply.d.ts +3 -2
- package/types/migrate/core/apply.d.ts.map +1 -1
- package/types/migrate/core/atlas-apply-runs.d.ts +6 -0
- package/types/migrate/core/atlas-apply-runs.d.ts.map +1 -1
- package/types/migrate/core/cleanup.d.ts +16 -4
- package/types/migrate/core/cleanup.d.ts.map +1 -1
- package/types/migrate/core/d1-history.d.ts.map +1 -1
- package/types/migrate/core/d1-wrangler-error.d.ts +11 -0
- package/types/migrate/core/d1-wrangler-error.d.ts.map +1 -1
- package/types/migrate/core/pg-replay-commit.d.ts +14 -9
- package/types/migrate/core/pg-replay-commit.d.ts.map +1 -1
- package/types/migrate/core/pg-replay-drops.d.ts +7 -12
- package/types/migrate/core/pg-replay-drops.d.ts.map +1 -1
- package/types/migrate/core/pg-replay-hidden.d.ts +36 -0
- package/types/migrate/core/pg-replay-hidden.d.ts.map +1 -0
- package/types/migrate/core/pg-replay-roles.d.ts +2 -4
- package/types/migrate/core/pg-replay-roles.d.ts.map +1 -1
- package/types/migrate/core/pg-replay.d.ts.map +1 -1
- package/types/migrate/core/pg-server-snapshot.d.ts +4 -11
- package/types/migrate/core/pg-server-snapshot.d.ts.map +1 -1
- package/types/migrate/core/proof-readers.d.ts +19 -0
- package/types/migrate/core/proof-readers.d.ts.map +1 -0
- package/types/migrate/core/proof-run.d.ts.map +1 -1
- package/types/migrate/core/proof-scope.d.ts +15 -7
- package/types/migrate/core/proof-scope.d.ts.map +1 -1
- package/types/migrate/core/sql-code.d.ts +7 -3
- package/types/migrate/core/sql-code.d.ts.map +1 -1
- package/types/migrate/core/sql-scan.d.ts.map +1 -1
- package/types/migrate/core/sqlite-keywords.d.ts +11 -0
- package/types/migrate/core/sqlite-keywords.d.ts.map +1 -0
- package/types/migrate/core/stopped.d.ts +23 -0
- package/types/migrate/core/stopped.d.ts.map +1 -0
- package/types/query/cursor-mint.d.ts.map +1 -1
- package/types/query/cursor-refusals.d.ts +17 -1
- package/types/query/cursor-refusals.d.ts.map +1 -1
- package/types/query/descriptions.d.ts +1 -1
- package/types/query/descriptions.d.ts.map +1 -1
- package/types/query/filter-parse.d.ts +15 -4
- package/types/query/filter-parse.d.ts.map +1 -1
- package/types/query/filter-validate.d.ts +1 -1
- package/types/query/filter-validate.d.ts.map +1 -1
- package/types/query/filter.d.ts +9 -1
- package/types/query/filter.d.ts.map +1 -1
- package/types/query/list-extras.d.ts.map +1 -1
- package/types/query/list-schema.d.ts.map +1 -1
- package/types/query/merged.d.ts.map +1 -1
- package/types/query/pagination.d.ts +13 -1
- package/types/query/pagination.d.ts.map +1 -1
- package/types/query/rounded-key.d.ts +2 -11
- package/types/query/rounded-key.d.ts.map +1 -1
- package/types/query/schema-params.d.ts.map +1 -1
- package/types/query/select-validate.d.ts.map +1 -1
- package/types/query/sqlite/cursor-fit.d.ts.map +1 -1
- package/types/query/trusted.d.ts +1 -1
- package/types/query/trusted.d.ts.map +1 -1
package/src/query/filter.ts
CHANGED
|
@@ -16,6 +16,43 @@ import {
|
|
|
16
16
|
} from "./filter-validate.ts"
|
|
17
17
|
import type { SortDirection, SortField } from "./types.ts"
|
|
18
18
|
|
|
19
|
+
/** The direction suffix an `order` entry may end in, before any nulls suffix, and what it reads as */
|
|
20
|
+
const SORT_DIRECTIONS = { asc: "asc", desc: "desc" } as const satisfies Record<string, SortDirection>
|
|
21
|
+
/** The nulls suffix an `order` entry may end in, and what it reads as */
|
|
22
|
+
const SORT_NULLS = { nullsfirst: "first", nullslast: "last" } as const
|
|
23
|
+
|
|
24
|
+
/** The value `suffixes` reads the last of `tokens` as, popping it, or undefined when it is none of them */
|
|
25
|
+
function suffixOf<T extends string>(tokens: string[], suffixes: Readonly<Record<string, T>>): T | undefined {
|
|
26
|
+
for (const [suffix, value] of Object.entries(suffixes))
|
|
27
|
+
if (tokens.at(-1) === suffix) {
|
|
28
|
+
tokens.pop()
|
|
29
|
+
return value
|
|
30
|
+
}
|
|
31
|
+
return undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function escapeRegExp(value: string): string {
|
|
35
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A regular expression taking any one of `names`, each literally */
|
|
39
|
+
function anyOf(names: readonly string[]): string {
|
|
40
|
+
return `(?:${names.map(escapeRegExp).join("|")})`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A regular expression taking every `order` parseOrder reads over the fields in `sort`, up to
|
|
45
|
+
* `maxSortKeys` entries: the empty value, which reads as the default order, and each entry the field
|
|
46
|
+
* and the suffixes orderEntries reads off it. A field named twice is refused, so no order holds more
|
|
47
|
+
* entries than `sort` has fields; which field repeats needs a lookahead, which RE2 lacks, so the
|
|
48
|
+
* pattern leaves that to the description
|
|
49
|
+
*/
|
|
50
|
+
function orderPattern(sort: readonly string[], maxSortKeys: number): string {
|
|
51
|
+
const entry = `${anyOf(sort)}(?:\\.${anyOf(Object.keys(SORT_DIRECTIONS))})?(?:\\.${anyOf(Object.keys(SORT_NULLS))})?`
|
|
52
|
+
const keys = Math.min(maxSortKeys, sort.length)
|
|
53
|
+
return `^(?:${entry}(?:,${entry}){0,${Math.max(0, keys - 1)}})?$`
|
|
54
|
+
}
|
|
55
|
+
|
|
19
56
|
/**
|
|
20
57
|
* Parse PostgREST-style `order` string into SortField array.
|
|
21
58
|
*
|
|
@@ -67,24 +104,8 @@ function orderEntries(input: string | null | undefined): Array<SortField | strin
|
|
|
67
104
|
|
|
68
105
|
const tokens = trimmed.split(".")
|
|
69
106
|
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
if (last === "nullsfirst") {
|
|
73
|
-
nulls = "first"
|
|
74
|
-
tokens.pop()
|
|
75
|
-
} else if (last === "nullslast") {
|
|
76
|
-
nulls = "last"
|
|
77
|
-
tokens.pop()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
let direction: SortDirection = "asc"
|
|
81
|
-
const newLast = tokens[tokens.length - 1]
|
|
82
|
-
if (newLast === "asc") {
|
|
83
|
-
tokens.pop()
|
|
84
|
-
} else if (newLast === "desc") {
|
|
85
|
-
direction = "desc"
|
|
86
|
-
tokens.pop()
|
|
87
|
-
}
|
|
107
|
+
const nulls = suffixOf(tokens, SORT_NULLS)
|
|
108
|
+
const direction: SortDirection = suffixOf(tokens, SORT_DIRECTIONS) ?? "asc"
|
|
88
109
|
|
|
89
110
|
const field = tokens.join(".")
|
|
90
111
|
if (!field || part !== trimmed) {
|
|
@@ -108,6 +129,7 @@ export {
|
|
|
108
129
|
parseFilterNumber,
|
|
109
130
|
namedTwice,
|
|
110
131
|
orderEntries,
|
|
132
|
+
orderPattern,
|
|
111
133
|
parseOrder,
|
|
112
134
|
validateFilter,
|
|
113
135
|
type FilterField,
|
package/src/query/list-extras.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
unprintedNumber,
|
|
17
17
|
} from "./held-keys.ts"
|
|
18
18
|
import type { SortField } from "./types.ts"
|
|
19
|
+
import { UnmintableRow } from "./cursor-refusals.ts"
|
|
19
20
|
|
|
20
21
|
/** The column every built list selects its tiebreak as, which the next cursor's id is minted from */
|
|
21
22
|
const COMB_ID = "_combId" as const
|
|
@@ -140,19 +141,15 @@ const FLOAT_MARK = "!f"
|
|
|
140
141
|
* which the read places nowhere a cursor resumes after
|
|
141
142
|
*/
|
|
142
143
|
const storesUnread = (field: string, stored: string): CombError =>
|
|
143
|
-
new
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
status: "internal_server_error",
|
|
147
|
-
})
|
|
144
|
+
new UnmintableRow(
|
|
145
|
+
`${field} stores a ${stored.toUpperCase()} value its column's drizzle mode reads as another, which no cursor of a list that binds the key as read resumes after: store what the mode reads back (a timestamp's epoch number, a boolean's 0 or 1, a finite number), or sort by a column of the list's own table`,
|
|
146
|
+
)
|
|
148
147
|
|
|
149
148
|
/** The 500 for a SQLite number key no text SQLite prints of reads back as it, which no cursor binds exactly */
|
|
150
149
|
const printsUnread = (field: string): CombError =>
|
|
151
|
-
new
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
status: "internal_server_error",
|
|
155
|
-
})
|
|
150
|
+
new UnmintableRow(
|
|
151
|
+
`${field} holds a REAL no text SQLite prints of it reads back as (D1 misprints some past about 1e100 and below 1e-100), which no cursor resumes after: store a number of fewer significant digits, or sort by another column`,
|
|
152
|
+
)
|
|
156
153
|
|
|
157
154
|
/** The 500 for a Postgres float key read under extra_float_digits 0 or below: its read is rounded */
|
|
158
155
|
const printsRounded = (field: string): CombError =>
|
package/src/query/list-schema.ts
CHANGED
|
@@ -24,7 +24,6 @@ import {
|
|
|
24
24
|
selectQueryFieldFor,
|
|
25
25
|
sortDirectionEnum,
|
|
26
26
|
} from "./schema-params.ts"
|
|
27
|
-
import { pageTooDeep } from "./trusted.ts"
|
|
28
27
|
import type { ListQueryConfig, ListQueryLimits, ListQueryOutput, OutputStableShape } from "./schema-types.ts"
|
|
29
28
|
import { validateSelectWithConfig } from "./select-validate.ts"
|
|
30
29
|
import type { FieldType } from "./types.ts"
|
|
@@ -178,7 +177,6 @@ function createListQuerySchema<
|
|
|
178
177
|
|
|
179
178
|
const { maxLimit = PAGINATION_DEFAULTS.maxLimit, maxPage = PAGINATION_DEFAULTS.maxPage } = config.pagination ?? {}
|
|
180
179
|
const piped = schema.transform((data, ctx): ExtendedOutput => {
|
|
181
|
-
if (data.page !== undefined && data.page > maxPage) throw pageTooDeep(data.page, maxPage)
|
|
182
180
|
/* Optional params exist on `data` only when advertised above. */
|
|
183
181
|
const optional = data as {
|
|
184
182
|
filter?: string | undefined
|
package/src/query/merged.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
COMB_ID,
|
|
19
19
|
type ListPagination,
|
|
20
20
|
type ListRow,
|
|
21
|
+
nextCursorOf,
|
|
21
22
|
type PaginationResponse,
|
|
22
23
|
totalOf,
|
|
23
24
|
} from "./pagination.ts"
|
|
@@ -238,8 +239,8 @@ function paginateMerged<T extends object>(
|
|
|
238
239
|
const window = rows.slice(start, start + limit + 1)
|
|
239
240
|
const hasMore = full || window.length > limit
|
|
240
241
|
const page = hasMore ? window.slice(0, limit) : window
|
|
241
|
-
/*
|
|
242
|
-
const last = page
|
|
242
|
+
/* the rows a cursor may be minted from are fitted; the last one's is sealed */
|
|
243
|
+
const last = nextCursorOf(page, { byCursor: cursor !== undefined, hasMore }, (row) => pagination.fit(row))
|
|
243
244
|
const meta: PaginationResponse = {
|
|
244
245
|
count: countOf(rowsPerShard, cursor),
|
|
245
246
|
hasMore,
|
package/src/query/pagination.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { paginationIn, refuseGoneAnchor, refuseOverRead, refuseUnwired } from ".
|
|
|
16
16
|
import type { paginationResponseSchema } from "./schema.ts"
|
|
17
17
|
import type { ListQueryInput, ParsedFields, SortField } from "./types.ts"
|
|
18
18
|
import type * as z from "zod"
|
|
19
|
+
import { UnmintableRow } from "./cursor-refusals.ts"
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* The name of one column a builder selects for `paginate` to read, which no row it returns keeps: the
|
|
@@ -187,6 +188,28 @@ function fitFrom(
|
|
|
187
188
|
})
|
|
188
189
|
}
|
|
189
190
|
|
|
191
|
+
/**
|
|
192
|
+
* What seals a served page's next cursor, or undefined for none, `check` measuring a row's cursor. On
|
|
193
|
+
* a page by cursor it runs on every row: its client walks the list one cursor at a time, so a row no
|
|
194
|
+
* cursor resumes after is refused on the page that serves it, whatever the page size. On a page by
|
|
195
|
+
* number it runs only on the last row of a page with more, the one the cursor is minted from, as
|
|
196
|
+
* 0.20.1 did; a row whose own value no cursor holds (UnmintableRow) mints none, and the page serves it,
|
|
197
|
+
* its `hasMore` still saying a next page by number exists. A refusal of the list's wiring throws on both
|
|
198
|
+
*/
|
|
199
|
+
function nextCursorOf<T>(
|
|
200
|
+
page: readonly T[],
|
|
201
|
+
{ byCursor, hasMore }: { byCursor: boolean; hasMore: boolean },
|
|
202
|
+
check: (row: T) => (() => string) | undefined,
|
|
203
|
+
): (() => string) | undefined {
|
|
204
|
+
if (byCursor) return page.map(check).at(-1)
|
|
205
|
+
try {
|
|
206
|
+
return (hasMore ? page.slice(-1) : []).map(check).at(-1)
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (error instanceof UnmintableRow) return undefined
|
|
209
|
+
throw error
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
190
213
|
/**
|
|
191
214
|
* The page of `items`, read with `built`, and its pagination: count, whether there is more, and
|
|
192
215
|
* the next cursor, sealed under the builder's options; none for a list no cursor can resume
|
|
@@ -207,12 +230,12 @@ function paginate<T extends object>(
|
|
|
207
230
|
refuseGoneAnchor(items)
|
|
208
231
|
const hasMore = items.length > pagination.limit
|
|
209
232
|
const sliced = hasMore ? items.slice(0, pagination.limit) : items
|
|
210
|
-
/* a key no cursor bound as read places is refused
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
233
|
+
/* a key no cursor bound as read places is refused as a mint is, checked from the fat row, under the
|
|
234
|
+
sort the builder ordered by, so the next request's signature matches; the last one's is sealed */
|
|
235
|
+
const last = nextCursorOf(sliced, { byCursor: pagination.cursor !== undefined, hasMore }, (item) => {
|
|
236
|
+
refuseUnheld(item as Record<string, unknown>, pagination.parsedSort)
|
|
237
|
+
return pagination.cursorable ? pagination.fit(item) : undefined
|
|
238
|
+
})
|
|
216
239
|
const meta: PaginationResponse = {
|
|
217
240
|
count: countOf(items, pagination),
|
|
218
241
|
hasMore,
|
|
@@ -229,6 +252,7 @@ function paginate<T extends object>(
|
|
|
229
252
|
export {
|
|
230
253
|
applySelect,
|
|
231
254
|
COMB_ID,
|
|
255
|
+
nextCursorOf,
|
|
232
256
|
type ListExtra,
|
|
233
257
|
type ListPagination,
|
|
234
258
|
type ListRow,
|
package/src/query/rounded-key.ts
CHANGED
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* selected does the value alone. A class is trusted only when it names a double, so one comb cannot
|
|
8
8
|
* place, such as a type no family covers, is refused as an integer is.
|
|
9
9
|
*/
|
|
10
|
-
import { CombError } from "../error.ts"
|
|
11
|
-
import { combErrorKeys } from "../types.ts"
|
|
12
10
|
import { storedClasses } from "./list-extras.ts"
|
|
13
11
|
import type { SortField } from "./types.ts"
|
|
12
|
+
import { UnmintableRow } from "./cursor-refusals.ts"
|
|
14
13
|
|
|
15
14
|
// lookup-table: why a list cannot page an integer sort key the driver rounded, by the list
|
|
16
15
|
const ROUNDED: Readonly<Record<"derived" | "merged" | "unread", string>> = {
|
|
@@ -45,7 +44,7 @@ function roundedKey(
|
|
|
45
44
|
row: Record<string, unknown>,
|
|
46
45
|
sort: readonly SortField[],
|
|
47
46
|
list: "derived" | "merged" | { unread: (field: string) => boolean },
|
|
48
|
-
):
|
|
47
|
+
): UnmintableRow | undefined {
|
|
49
48
|
const [kind, judged] = typeof list === "string" ? [list, () => true] : (["unread", list.unread] as const)
|
|
50
49
|
const stored = storedClasses(row)
|
|
51
50
|
const rounded = sort.find(({ field }, i) => {
|
|
@@ -60,13 +59,11 @@ function roundedKey(
|
|
|
60
59
|
})
|
|
61
60
|
if (rounded === undefined) return undefined
|
|
62
61
|
const value = row[rounded.field] as number
|
|
63
|
-
return new
|
|
64
|
-
|
|
62
|
+
return new UnmintableRow(
|
|
63
|
+
Number.isInteger(value)
|
|
65
64
|
? `${rounded.field} ${BigInt(value)} is past ±(2^53 − 1), where the driver rounded it: ${ROUNDED[kind]}`
|
|
66
65
|
: `${rounded.field} ${value} is a fraction under a type no driver reads exactly as a JS number, so the driver may have rounded it: ${FRACTION[kind]}: sort by a Postgres numeric, whose text comb carries, read the key as a string, or sort by a double precision or real`,
|
|
67
|
-
|
|
68
|
-
status: "internal_server_error",
|
|
69
|
-
})
|
|
66
|
+
)
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
export { roundedKey }
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { FILTER_OPERATORS } from "./filter-parse.ts"
|
|
15
15
|
import { PAGINATION_DEFAULTS } from "./schema-limits.ts"
|
|
16
16
|
import type { FieldsConfig, PaginationConfig } from "./schema-types.ts"
|
|
17
|
-
import { invalidPage } from "./trusted.ts"
|
|
17
|
+
import { invalidPage, pageTooDeep } from "./trusted.ts"
|
|
18
18
|
import type { FieldSelection, FilterAST, FilterGroup, ParsedFields } from "./types.ts"
|
|
19
19
|
|
|
20
20
|
/** The `select` param for an endpoint of these fields, its text and examples theirs */
|
|
@@ -88,10 +88,17 @@ function fromDigits(raw: unknown, max: number): unknown {
|
|
|
88
88
|
return DECIMAL_DIGITS.test(raw) && !padded ? Number(raw) : Number.NaN
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* `raw` as a page, a whole number from 1 to `maxPage`: past it, whatever its size, is `page_too_deep`,
|
|
93
|
+
* decided here on the digits before any number the schema could refuse exists; anything else is
|
|
94
|
+
* invalid_page, as the builders answer it. A digit string past 1e308 reads as Infinity: it is whole
|
|
95
|
+
*/
|
|
92
96
|
function pageFrom(raw: unknown, maxPage: number): unknown {
|
|
93
97
|
const page = fromDigits(raw, maxPage)
|
|
94
|
-
|
|
98
|
+
const isDigits = typeof raw === "string"
|
|
99
|
+
if (typeof page !== "number" || page < 1 || !(Number.isInteger(page) || (isDigits && page === Infinity)))
|
|
100
|
+
throw invalidPage(raw)
|
|
101
|
+
if (page > maxPage) throw pageTooDeep(isDigits ? raw.replace(/^0+/, "") : page, maxPage)
|
|
95
102
|
return page
|
|
96
103
|
}
|
|
97
104
|
|
|
@@ -147,8 +154,8 @@ function limitSchemaFor(pagination: PaginationConfig | undefined): z.ZodDefault<
|
|
|
147
154
|
/**
|
|
148
155
|
* The `page` param: decimal digits or a number, a whole number from 1. Neither bound is a field
|
|
149
156
|
* error, which would give one condition two contracts: a page that is no whole number from 1 is
|
|
150
|
-
* `invalid_page`, and maxPage
|
|
151
|
-
*
|
|
157
|
+
* `invalid_page`, and one past maxPage is `page_too_deep` at any size, each as an unbounded list
|
|
158
|
+
* answers it
|
|
152
159
|
*/
|
|
153
160
|
function pageSchema(maxPage: number): z.ZodOptional<CountParam> {
|
|
154
161
|
const page = z
|
|
@@ -13,10 +13,13 @@ type Report = (message: string) => void
|
|
|
13
13
|
/** A relation by name, and the config that declares its fields */
|
|
14
14
|
type Relation = { fieldsConfig: FieldsConfig; name: string }
|
|
15
15
|
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Report every name in `scalars` that `allowed` lacks; computed `@` fields are the handler's, and `*`
|
|
18
|
+
* is no name: it expands to `allowed` after this check, so a name beside it is held to `allowed` too
|
|
19
|
+
*/
|
|
17
20
|
function checkScalars(scalars: readonly string[], allowed: ReadonlySet<string>, report: Report): void {
|
|
18
21
|
for (const field of scalars) {
|
|
19
|
-
if (!allowed.has(field) && !field.startsWith("@")) report(field)
|
|
22
|
+
if (field !== "*" && !allowed.has(field) && !field.startsWith("@")) report(field)
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
|
|
@@ -30,9 +33,9 @@ function checkRelation(selection: FieldSelection, { fieldsConfig, name }: Relati
|
|
|
30
33
|
|
|
31
34
|
const relationFields = fieldsConfig.relationFields ?? {}
|
|
32
35
|
const allowed = new Set(Object.hasOwn(relationFields, name) ? relationFields[name] : [])
|
|
36
|
+
checkScalars(selection.scalars, allowed, (field) => report(`Unknown ${name} field: ${field}`))
|
|
33
37
|
/* expand nested wildcard to all allowed fields */
|
|
34
38
|
if (selection.scalars.includes("*")) selection.scalars = [...allowed]
|
|
35
|
-
checkScalars(selection.scalars, allowed, (field) => report(`Unknown ${name} field: ${field}`))
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
/** The parsed selection, checked against `fieldsConfig`; null when there is none or it does not parse */
|
|
@@ -54,9 +57,9 @@ function validateSelectWithConfig(
|
|
|
54
57
|
return null
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
checkScalars(parsed.root.scalars, new Set(fieldsConfig.scalars), (field) => report(`Unknown field: ${field}`))
|
|
57
61
|
/* Handle * wildcard at top level — expand to all scalars */
|
|
58
62
|
if (parsed.root.scalars.includes("*")) parsed.root.scalars = [...fieldsConfig.scalars]
|
|
59
|
-
checkScalars(parsed.root.scalars, new Set(fieldsConfig.scalars), (field) => report(`Unknown field: ${field}`))
|
|
60
63
|
|
|
61
64
|
const relations = new Set(fieldsConfig.relations ?? [])
|
|
62
65
|
/* parseSelect stores a selection for every embed, never null */
|
|
@@ -141,6 +141,14 @@ const NUMERIC_TEXT = /^(?:-?\d+(?:\.\d+)?|NaN|-?Infinity)$/
|
|
|
141
141
|
const carriesOpaque = (column: SQLWrapper | undefined): boolean =>
|
|
142
142
|
is(column, Column) && column.dataType === "custom" && !is(column, SQLiteColumn)
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* `cast` as an operand of no affinity, as a bound parameter is: a CAST has its type's affinity, which
|
|
146
|
+
* SQLite applies to a column of none or BLOB's before it compares, so `k > cast(? as real)` read a
|
|
147
|
+
* stored TEXT '10' as 10 and paged it out of the column's own order. The unary `+` drops the affinity
|
|
148
|
+
* and keeps the index search
|
|
149
|
+
*/
|
|
150
|
+
const affinityFree = (cast: SQL): SQL => sql`+${cast}`
|
|
151
|
+
|
|
144
152
|
/**
|
|
145
153
|
* A cursor value as its key binds it. Stored text the list carried (`carried`, the cursor's flag)
|
|
146
154
|
* binds as itself, past the column's mapper: cast to numeric on a key that reads rounded, and on a
|
|
@@ -150,12 +158,12 @@ const carriesOpaque = (column: SQLWrapper | undefined): boolean =>
|
|
|
150
158
|
*/
|
|
151
159
|
function boundCarried(column: SQLWrapper | undefined, value: unknown, carried: boolean): unknown {
|
|
152
160
|
/* one SQLite parse of the text the list checked reads back as the key, on every driver */
|
|
153
|
-
if (value instanceof RealText) return sql`cast(${value.text} as real)`
|
|
161
|
+
if (value instanceof RealText) return affinityFree(sql`cast(${value.text} as real)`)
|
|
154
162
|
if (carriedText(column, value, { asRead: false, carried })) return sql`${value}`
|
|
155
163
|
/* a mode's mapper binds the value as another (a boolean's as 0 or 1); D1 binds no bigint, so one past 2^53 goes as its digits */
|
|
156
164
|
if (carriedStored(column, value, { asRead: false, carried }))
|
|
157
165
|
return typeof value === "bigint" && !Number.isSafeInteger(Number(value))
|
|
158
|
-
? sql`cast(${String(value)} as integer)`
|
|
166
|
+
? affinityFree(sql`cast(${String(value)} as integer)`)
|
|
159
167
|
: sql`${bindable(value)}`
|
|
160
168
|
if (!carried || typeof value !== "string" || !NUMERIC_TEXT.test(value)) return value
|
|
161
169
|
if (readsRounded(column)) return sql`${value}::numeric`
|
package/src/query/trusted.ts
CHANGED
|
@@ -84,10 +84,15 @@ function invalidPage(page: unknown): CombError {
|
|
|
84
84
|
})
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/** The most digits of a page past `maxPage` its message names */
|
|
88
|
+
const PAGE_SHOWN = 24
|
|
89
|
+
|
|
87
90
|
/** The 400 for a page past `maxPage`, from a list schema or from a list no schema bounded */
|
|
88
|
-
function pageTooDeep(page: number, maxPage: number): CombError {
|
|
91
|
+
function pageTooDeep(page: number | string, maxPage: number): CombError {
|
|
92
|
+
/* a page of any size reaches here as digits, so the message keeps the front of it, not all */
|
|
93
|
+
const shown = String(page)
|
|
89
94
|
return new CombError({
|
|
90
|
-
cause: `page ${
|
|
95
|
+
cause: `page ${shown.length > PAGE_SHOWN ? `${shown.slice(0, PAGE_SHOWN)}…` : shown} is past ${maxPage}; page further by cursor`,
|
|
91
96
|
errorKey: combErrorKeys.PAGE_TOO_DEEP,
|
|
92
97
|
status: "bad_request",
|
|
93
98
|
})
|
package/types/cli/args.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,OAAO,GAChB,SAAS,GACT,eAAe,GACf,kBAAkB,GAClB,eAAe,GACf,cAAc,GACd,cAAc,GACd,gBAAgB,CAAA;AAEnB,MAAM,MAAM,UAAU,GAAG;IACxB,kFAAkF;IAClF,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;IACxB,gCAAgC;IAChC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,KAAK,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,IAAI,MAAM,EAAE,GAAG,SAAS,CAAA;IAChC,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,SAAS,UAAU,
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,OAAO,GAChB,SAAS,GACT,eAAe,GACf,kBAAkB,GAClB,eAAe,GACf,cAAc,GACd,cAAc,GACd,gBAAgB,CAAA;AAEnB,MAAM,MAAM,UAAU,GAAG;IACxB,kFAAkF;IAClF,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,CAAA;IACxB,gCAAgC;IAChC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,KAAK,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,IAAI,MAAM,EAAE,GAAG,SAAS,CAAA;IAChC,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1B,CAAA;AAED,eAAO,MAAM,OAAO,EAAE,SAAS,UAAU,EA0DxC,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACxB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAA;CACtC,CAAA;AA6CD,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,CAsB/E;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAE1E;AAqBD,0GAA0G;AAC1G,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAMtC;AAmBD,8FAA8F;AAC9F,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,CAIpE;AAED,6DAA6D;AAC7D,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAGpD"}
|
|
@@ -14,8 +14,11 @@ export declare function findCombConfig(cwd: string): Promise<CodegenConfig | und
|
|
|
14
14
|
export declare function loadCombConfig(cwd: string): Promise<CodegenConfig>;
|
|
15
15
|
/** The database `name` declares, or a CliError naming the ones it does, and `hint` when the caller has one */
|
|
16
16
|
export declare function databaseIn(config: CodegenConfig, name: string, hint?: string): DatabaseCodegen;
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The tables file `tables` names, resolved against `cwd`, as `what` gave it (--tables, or
|
|
19
|
+
* comb.config.ts `tables`); a CliError when it is missing or not a file
|
|
20
|
+
*/
|
|
21
|
+
export declare function tablesFile(cwd: string, tables: string, what: "--tables" | "tables"): string;
|
|
19
22
|
/** A database comb.config.ts declares FTS on: its tables file and the FTS of each table */
|
|
20
23
|
export type DeclaredFts = {
|
|
21
24
|
fts: Record<string, FtsTableConfig>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comb-config.d.ts","sourceRoot":"","sources":["../../src/cli/comb-config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"comb-config.d.ts","sourceRoot":"","sources":["../../src/cli/comb-config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAGtE,OAAO,EAAY,KAAK,KAAK,EAAE,MAAM,aAAa,CAAA;AAElD,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,CAAA;AAS9C;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAS7E;AAED,2EAA2E;AAC3E,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CASpF;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAIxE;AAED,8GAA8G;AAC9G,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,CAK9F;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,MAAM,CAK3F;AAED,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjF;;;;GAIG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,MAAM,EACX,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACrE,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAKlC;AAED,kGAAkG;AAClG,wBAAsB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAK3F"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refuse `file`, which `what` names (an option or a config field), when it exists as other than a
|
|
3
|
+
* file, saying what it is, then `fix`; a missing one is left to the caller, which refuses it its own way
|
|
4
|
+
*/
|
|
5
|
+
export declare function refuseNotFile(file: string, what: string, fix: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Refuse a name a file is made from, `what` naming it, when it would name a path: one holding a
|
|
8
|
+
* separator, or `.` or `..` alone; then `usage`
|
|
9
|
+
*/
|
|
10
|
+
export declare function refusePathName(name: string, what: string, usage: string): void;
|
|
11
|
+
//# sourceMappingURL=file-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-path.d.ts","sourceRoot":"","sources":["../../src/cli/file-path.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAI3E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAG9E"}
|
|
@@ -2,6 +2,7 @@ import { type Peers } from "../migrate/core/optional-peer.ts";
|
|
|
2
2
|
import type { Command, Provider } from "../migrate/core/peer-needs.ts";
|
|
3
3
|
import { type CliContext } from "./output.ts";
|
|
4
4
|
type Mode = "apply" | "baseline" | "check" | "status";
|
|
5
|
+
/** `migrate apply|baseline|check|status`, with --json as one JSON object (migrate-json.ts) */
|
|
5
6
|
export declare function migrateApply(mode: Mode, argv: readonly string[], io: CliContext): Promise<void>;
|
|
6
7
|
/**
|
|
7
8
|
* Every peer `command` on `provider` needs, Atlas's version read through `io` among them, refused
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-apply.d.ts","sourceRoot":"","sources":["../../src/cli/migrate-apply.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAS,KAAK,KAAK,EAAgB,MAAM,kCAAkC,CAAA;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAQtE,OAAO,EAAyB,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"migrate-apply.d.ts","sourceRoot":"","sources":["../../src/cli/migrate-apply.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAS,KAAK,KAAK,EAAgB,MAAM,kCAAkC,CAAA;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAA;AAQtE,OAAO,EAAyB,KAAK,UAAU,EAAuB,MAAM,aAAa,CAAA;AAEzF,KAAK,IAAI,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AA+LrD,8FAA8F;AAC9F,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAIrG;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC9B,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,OAAO,EAChB,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAClE,OAAO,CAAC,KAAK,CAAC,CAGhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-d1.d.ts","sourceRoot":"","sources":["../../src/cli/migrate-d1.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,4BAA4B,CAAA;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,KAAK,aAAa,EAAe,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"migrate-d1.d.ts","sourceRoot":"","sources":["../../src/cli/migrate-d1.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,UAAU,EAAqB,MAAM,4BAA4B,CAAA;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,KAAK,aAAa,EAAe,MAAM,qBAAqB,CAAA;AAErE,OAAO,EAAyB,KAAK,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AAEzF,KAAK,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEvD,8DAA8D;AAC9D,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/E,gGAAgG;AAChG,iBAAS,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,GAAG,SAAS,GAAG;IAAE,MAAM,EAAE,gBAAgB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAkBpH;AAED,qHAAqH;AACrH,OAAO,EAAE,QAAQ,EAAE,CAAA;AAEnB,wBAAsB,SAAS,CAC9B,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,QAAQ,EAAE,UAAU,GAClB,OAAO,CAAC,cAAc,CAAC,CAmDzB"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CliContext, type MigrateOutcome } from "./output.ts";
|
|
2
|
+
/** `run` on `db`, its human lines on stderr and its one JSON object on `io.out` */
|
|
3
|
+
export declare function asJson(db: string, io: CliContext, run: (io: CliContext) => Promise<MigrateOutcome>): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=migrate-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-json.d.ts","sourceRoot":"","sources":["../../src/cli/migrate-json.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,cAAc,EAAY,MAAM,aAAa,CAAA;AAK5E,mFAAmF;AACnF,wBAAsB,MAAM,CAC3B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,UAAU,EACd,GAAG,EAAE,CAAC,EAAE,EAAE,UAAU,KAAK,OAAO,CAAC,cAAc,CAAC,GAC9C,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/cli/migrate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/cli/migrate.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAY,KAAK,UAAU,EAAY,MAAM,aAAa,CAAA;AA+OjE,wBAAsB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BrG"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Connection } from "../types.ts";
|
|
2
2
|
import { type RetryOptions } from "./utils.ts";
|
|
3
3
|
/** Whether a unique index of comb's history holds its hash alone, as comb's table did before 0.13 */
|
|
4
|
-
export declare
|
|
4
|
+
export declare const hashUnique: (conn: Connection) => Promise<boolean>;
|
|
5
5
|
/**
|
|
6
6
|
* comb's history, made where it is missing, named from 0.11, and from a history before 0.13
|
|
7
7
|
* rebuilt in one batch: every row and id kept, each row `renamed` lists taking its new name,
|
|
@@ -46,7 +46,8 @@ type ApplyOptions = {
|
|
|
46
46
|
* record it wrote says it ran, so a retry reads the history first and runs nothing again.
|
|
47
47
|
* When no read of `history` answers after a batch that failed transiently, the failure is an Unconfirmed.
|
|
48
48
|
* The record goes first, so a batch whose file another run recorded while it waited for the lock
|
|
49
|
-
* fails on the name at once and runs nothing
|
|
49
|
+
* fails on the name's unique index at once and runs nothing (ensureMigrationsTable keeps one on every
|
|
50
|
+
* history, whoever made the table); the history then says so, and it is that run's.
|
|
50
51
|
* Returns who applied it.
|
|
51
52
|
*/
|
|
52
53
|
export declare function applyRecorded(conn: Pick<Connection, "batch">, migration: Recorded, { history, retry }: ApplyOptions): Promise<"this run" | "another run">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/apply.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/apply.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAM7C,OAAO,EAAE,KAAK,YAAY,EAAa,MAAM,YAAY,CAAA;AA4BzD,qGAAqG;AACrG,eAAO,MAAM,UAAU,SAAU,UAAU,KAAG,OAAO,CAAC,OAAO,CAA2B,CAAA;AAmBxF;;;;GAIG;AACH,wBAAsB,qBAAqB,CAC1C,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAM,GACvD,OAAO,CAAC,IAAI,CAAC,CAsDf;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAK/G;AAID;;;;GAIG;AACH,eAAO,MAAM,YAAY,+BAA+B,CAAA;AAExD,+GAA+G;AAC/G,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtG;AAED,8EAA8E;AAC9E,KAAK,QAAQ,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAA;AAEjF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,CAAA;AAEhE,mHAAmH;AACnH,KAAK,YAAY,GAAG;IAAE,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;CAAE,CAAA;AAS9F;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAClC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAC/B,SAAS,EAAE,QAAQ,EACnB,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,YAAY,GAC9B,OAAO,CAAC,UAAU,GAAG,aAAa,CAAC,CAkCrC;AAED;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,EACnC,UAAU,EAAE,SAAS,QAAQ,EAAE,EAC/B,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,YAAY,GAAG;IAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACzE,OAAO,CAAC,IAAI,CAAC,CAwCf"}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The apply itself, once comb approved the pending files: one Atlas call per file, so
|
|
3
|
+
* each file runs on a session of its own, as it would alone, as on SQLite and on D1. No
|
|
4
|
+
* reading of a file proves what it leaves on its session: a trigger, a default, a DO block's EXECUTE
|
|
5
|
+
* or code the target holds can each run a SET that outlives its COMMIT.
|
|
6
|
+
*/
|
|
1
7
|
import { type Foreign } from "./atlas-foreign.ts";
|
|
2
8
|
import { type AtlasStatus, checkHistory } from "./atlas-history.ts";
|
|
3
9
|
import { type AtlasCommand } from "./atlas-status.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atlas-apply-runs.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/atlas-apply-runs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"atlas-apply-runs.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/atlas-apply-runs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,OAAO,EAAc,MAAM,oBAAoB,CAAA;AAC7D,OAAO,EAAkB,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEnF,OAAO,EAAS,KAAK,YAAY,EAAe,MAAM,mBAAmB,CAAA;AAoCzE;;;;;;;GAOG;AACH,iBAAe,SAAS,CACvB,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,MAAM,EACZ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAChH,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB;AA+BD,OAAO,EAAE,SAAS,EAAE,CAAA"}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* A step a signal runs, told which signal came and what the steps that ran before it returned, in
|
|
3
|
+
* that order: a step held first runs last, and reads what the steps held after it found out
|
|
4
|
+
*/
|
|
5
|
+
type Step = (signal: NodeJS.Signals, earlier: readonly unknown[]) => unknown;
|
|
6
|
+
/**
|
|
7
|
+
* The signals a held step runs on: every one whose default action ends the process and that a
|
|
8
|
+
* terminal or a supervisor sends. A Ctrl-C (SIGINT), a Ctrl-\ (SIGQUIT), a container stop or a CI
|
|
9
|
+
* step timeout (SIGTERM), and a terminal's hangup, as an SSH drop sends it (SIGHUP): a child in a
|
|
10
|
+
* group of its own gets none of them from the terminal, so comb's forward is its only signal.
|
|
11
|
+
*/
|
|
12
|
+
export declare const STOP_SIGNALS: readonly ["SIGHUP", "SIGINT", "SIGQUIT", "SIGTERM"];
|
|
13
|
+
/** One of STOP_SIGNALS */
|
|
14
|
+
export type StopSignal = (typeof STOP_SIGNALS)[number];
|
|
3
15
|
/**
|
|
4
16
|
* Settles once every stop begun so far has ended: asked for the process's end, or let a host that
|
|
5
17
|
* listens keep it. A test that stubs process.kill around a signal restores it only past this, so
|
|
@@ -13,7 +25,7 @@ export declare function stopsEnded(): Promise<void>;
|
|
|
13
25
|
*/
|
|
14
26
|
export declare function pastStop(): Promise<void>;
|
|
15
27
|
/**
|
|
16
|
-
* Hold `step` until the release this returns, so
|
|
28
|
+
* Hold `step` until the release this returns, so a stop signal runs it before the process ends.
|
|
17
29
|
* The listener is read from the process, not remembered: a host that removed every listener gets it back.
|
|
18
30
|
*/
|
|
19
31
|
export declare function hold(step: Step): () => void;
|
|
@@ -49,7 +61,7 @@ export type Scratch = {
|
|
|
49
61
|
};
|
|
50
62
|
/**
|
|
51
63
|
* A new directory under the temp directory that only this user can open (0700), named `prefix`, this
|
|
52
|
-
* process's pid and host mark, and removed by `remove`, or by
|
|
64
|
+
* process's pid and host mark, and removed by `remove`, or by a stop signal before it. A
|
|
53
65
|
* process's first scratch of a prefix sweeps what killed runs left.
|
|
54
66
|
*/
|
|
55
67
|
export declare function scratchDir(prefix: string): Scratch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/cleanup.ts"],"names":[],"mappings":"AAaA
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/cleanup.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,OAAO,EAAE,KAAK,OAAO,CAAA;AAK5E;;;;;GAKG;AACH,eAAO,MAAM,YAAY,YAAI,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAE/E,0BAA0B;AAC1B,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAA;AAiEtD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAExC;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,IAAI,CAI3C;AAKD;;;GAGG;AACH,wBAAgB,WAAW,IAAI;IAAE,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;CAAE,CAUpG;AAED,gDAAgD;AAChD,wBAAsB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnG;AAED,mFAAmF;AACnF,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO5C;AAED,wHAAwH;AACxH,eAAO,MAAM,gBAAgB,EAAE,MAAwB,CAAA;AAEvD;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAQjC;AAKD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,MAAoB,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI,CAetG;AAKD,+DAA+D;AAC/D,MAAM,MAAM,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,IAAI,IAAI,CAAA;CAAE,CAAA;AAErD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAelD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"d1-history.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/d1-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAI7C,OAAO,EAAqB,KAAK,QAAQ,EAAgB,KAAK,UAAU,EAAkB,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"d1-history.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/d1-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAI7C,OAAO,EAAqB,KAAK,QAAQ,EAAgB,KAAK,UAAU,EAAkB,MAAM,iBAAiB,CAAA;AAqHjH,KAAK,OAAO,GAAG;IACd,OAAO,CAAC,SAAS,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACtD,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC/B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,IAAI,EAAE,UAAU,CAAA;CAChB,CAAA;AAqBD,wGAAwG;AACxG,iBAAe,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmD5E;AAED;;;;;;GAMG;AACH,iBAAe,UAAU,CACxB,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC3B,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAiCjD;AAED;;;;;;GAMG;AACH,iBAAe,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQjH;AAED,6GAA6G;AAC7G,iBAAe,QAAQ,CACtB,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAanD;AAED,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAA"}
|
|
@@ -10,5 +10,16 @@ export declare function wranglerError({ stderr, stdout }: Ran): string;
|
|
|
10
10
|
* never waited out, since comb cannot know the batch did nothing, and what the table holds says what is still pending.
|
|
11
11
|
*/
|
|
12
12
|
export declare function applyFailure(ran: Ran, locked: boolean): string;
|
|
13
|
+
/** Refuse a failed run, or one whose table gained (`added`) other than the `names` checked, naming a file never checked */
|
|
14
|
+
export declare function refuseUnlike(ran: {
|
|
15
|
+
code: number;
|
|
16
|
+
stderr: string;
|
|
17
|
+
stdout: string;
|
|
18
|
+
}, { added, locked, names, table }: {
|
|
19
|
+
added: string[];
|
|
20
|
+
locked: boolean;
|
|
21
|
+
names: string[];
|
|
22
|
+
table: string;
|
|
23
|
+
}): void;
|
|
13
24
|
export {};
|
|
14
25
|
//# sourceMappingURL=d1-wrangler-error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"d1-wrangler-error.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/d1-wrangler-error.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"d1-wrangler-error.d.ts","sourceRoot":"","sources":["../../../src/migrate/core/d1-wrangler-error.ts"],"names":[],"mappings":"AAOA,KAAK,GAAG,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE7C,2HAA2H;AAC3H,wBAAgB,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,GAAG,MAAM,CAK7D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAI9D;AAED,2HAA2H;AAC3H,wBAAgB,YAAY,CAC3B,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACrD,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnG,IAAI,CAeN"}
|