@webda/core 4.0.0-beta.7 → 4.0.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/lib/application/application.d.ts +19 -0
  2. package/lib/application/application.d.ts.map +1 -1
  3. package/lib/application/application.js +52 -9
  4. package/lib/application/application.js.map +1 -1
  5. package/lib/application/model-types.d.ts +63 -0
  6. package/lib/application/model-types.d.ts.map +1 -0
  7. package/lib/application/model-types.js +59 -0
  8. package/lib/application/model-types.js.map +1 -0
  9. package/lib/application/unpackedapplication.d.ts.map +1 -1
  10. package/lib/application/unpackedapplication.js +5 -4
  11. package/lib/application/unpackedapplication.js.map +1 -1
  12. package/lib/bin/cli.d.ts +18 -0
  13. package/lib/bin/cli.d.ts.map +1 -1
  14. package/lib/bin/cli.js +38 -3
  15. package/lib/bin/cli.js.map +1 -1
  16. package/lib/core/operations.d.ts +17 -0
  17. package/lib/core/operations.d.ts.map +1 -1
  18. package/lib/core/operations.js +1 -1
  19. package/lib/core/operations.js.map +1 -1
  20. package/lib/index.d.ts +5 -2
  21. package/lib/index.d.ts.map +1 -1
  22. package/lib/index.js +4 -1
  23. package/lib/index.js.map +1 -1
  24. package/lib/models/decorator.d.ts +21 -0
  25. package/lib/models/decorator.d.ts.map +1 -1
  26. package/lib/models/decorator.js +18 -0
  27. package/lib/models/decorator.js.map +1 -1
  28. package/lib/rest/restoperationstransport.service.d.ts +6 -0
  29. package/lib/rest/restoperationstransport.service.d.ts.map +1 -1
  30. package/lib/rest/restoperationstransport.service.js +31 -2
  31. package/lib/rest/restoperationstransport.service.js.map +1 -1
  32. package/lib/rest/router.service.d.ts.map +1 -1
  33. package/lib/rest/router.service.js +5 -2
  34. package/lib/rest/router.service.js.map +1 -1
  35. package/lib/services/binary.service.d.ts +1 -1
  36. package/lib/services/binary.service.d.ts.map +1 -1
  37. package/lib/services/binary.service.js.map +1 -1
  38. package/lib/services/httpserver.service.d.ts.map +1 -1
  39. package/lib/services/httpserver.service.js +5 -0
  40. package/lib/services/httpserver.service.js.map +1 -1
  41. package/lib/services/service.d.ts.map +1 -1
  42. package/lib/services/service.js +4 -1
  43. package/lib/services/service.js.map +1 -1
  44. package/lib/services/servicecommands.d.ts.map +1 -1
  45. package/lib/services/servicecommands.js +14 -1
  46. package/lib/services/servicecommands.js.map +1 -1
  47. package/lib/stores/capability.d.ts +16 -0
  48. package/lib/stores/capability.d.ts.map +1 -0
  49. package/lib/stores/capability.js +5 -0
  50. package/lib/stores/capability.js.map +1 -0
  51. package/lib/stores/memory.service.d.ts +30 -1
  52. package/lib/stores/memory.service.d.ts.map +1 -1
  53. package/lib/stores/memory.service.js +47 -1
  54. package/lib/stores/memory.service.js.map +1 -1
  55. package/lib/stores/migration.d.ts +306 -0
  56. package/lib/stores/migration.d.ts.map +1 -0
  57. package/lib/stores/migration.js +280 -0
  58. package/lib/stores/migration.js.map +1 -0
  59. package/lib/stores/store.d.ts +151 -17
  60. package/lib/stores/store.d.ts.map +1 -1
  61. package/lib/stores/store.js +421 -21
  62. package/lib/stores/store.js.map +1 -1
  63. package/lib/test/index.d.ts +2 -0
  64. package/lib/test/index.d.ts.map +1 -1
  65. package/lib/test/index.js +3 -0
  66. package/lib/test/index.js.map +1 -1
  67. package/lib/test/legacy-types.d.ts +146 -0
  68. package/lib/test/legacy-types.d.ts.map +1 -0
  69. package/lib/test/legacy-types.fixture.model.d.ts +38 -0
  70. package/lib/test/legacy-types.fixture.model.d.ts.map +1 -0
  71. package/lib/test/legacy-types.fixture.model.js +38 -0
  72. package/lib/test/legacy-types.fixture.model.js.map +1 -0
  73. package/lib/test/legacy-types.js +481 -0
  74. package/lib/test/legacy-types.js.map +1 -0
  75. package/package.json +11 -11
  76. package/webda.module.json +48 -22
@@ -0,0 +1,306 @@
1
+ import { type ModelClass, type ModelTypeResolver } from "@webda/models";
2
+ import * as WebdaError from "../errors/errors.js";
3
+ /**
4
+ * A row as the backend stores it, read without type filter nor hydration
5
+ */
6
+ export interface RawRow {
7
+ /**
8
+ * Table (collection) holding the row: the store name for single-storage stores (Memory, File)
9
+ */
10
+ table: string;
11
+ /**
12
+ * Storage key of the row
13
+ */
14
+ key: string;
15
+ /**
16
+ * Stored data, `__type` as stored. Rows written by Webda 4 Memory and File stores are serializer envelopes
17
+ * `{ $serializer, value, __type }`; Webda 3 rows are plain objects.
18
+ */
19
+ data: Record<string, any>;
20
+ /**
21
+ * Set when the stored value is not a JSON object: `data` is then empty and the row cannot be patched
22
+ */
23
+ unreadable?: boolean;
24
+ }
25
+ /**
26
+ * Top-level fields to set on a raw row
27
+ */
28
+ export type RawPatch = Record<string, any>;
29
+ /**
30
+ * A page of raw rows
31
+ */
32
+ export interface RawPage {
33
+ /**
34
+ * Rows of the page
35
+ */
36
+ rows: RawRow[];
37
+ /**
38
+ * Token of the next page, undefined on the last one
39
+ */
40
+ continuationToken?: string;
41
+ }
42
+ /**
43
+ * A table managed by a store
44
+ */
45
+ export interface RawTable {
46
+ /**
47
+ * Table name, as used in reports
48
+ */
49
+ name: string;
50
+ /**
51
+ * Model owning the untyped rows of the table (the first model of the store or of the table)
52
+ */
53
+ root?: ModelClass;
54
+ }
55
+ /**
56
+ * The store has no raw access yet: it cannot run migrations
57
+ */
58
+ export declare class MigrationUnsupported extends WebdaError.CodeError {
59
+ /**
60
+ * @param store - the store name
61
+ */
62
+ constructor(store: string);
63
+ }
64
+ /**
65
+ * Parse a value of a key/value storage as a raw row
66
+ * @param table - table name
67
+ * @param key - storage key
68
+ * @param value - stored JSON string (or object, for old persistence files)
69
+ * @returns the row, flagged unreadable when the value is not a JSON object
70
+ */
71
+ export declare function parseRawValue(table: string, key: string, value: unknown): RawRow;
72
+ /**
73
+ * Read a page of a key/value storage, in key order
74
+ *
75
+ * The token is the last key of the page, so rows added or removed meanwhile do not shift the next page.
76
+ * @param map - the storage
77
+ * @param table - table name of the rows
78
+ * @param batchSize - rows per page
79
+ * @param token - token of the previous page
80
+ * @returns the page
81
+ */
82
+ export declare function mapRawPage(map: Map<string, any>, table: string, batchSize: number, token?: string): RawPage;
83
+ /**
84
+ * Set top-level fields of a row of a key/value storage
85
+ * @param map - the storage
86
+ * @param key - storage key
87
+ * @param patch - fields to set
88
+ */
89
+ export declare function mapRawPatch(map: Map<string, any>, key: string, patch: RawPatch): void;
90
+ /**
91
+ * Counters a patcher fills for the report
92
+ */
93
+ export interface MigrationContext {
94
+ /**
95
+ * Count a rewritten value under `"<from> → <to>"`
96
+ * @param from - the stored value
97
+ * @param to - the new value
98
+ */
99
+ change(from: string, to: string): void;
100
+ /**
101
+ * Count a row left untouched because its value is unknown or ambiguous
102
+ * @param type - the stored value
103
+ */
104
+ unknown(type: string): void;
105
+ }
106
+ /**
107
+ * Compute the patch of a raw row: undefined when the row is already migrated
108
+ */
109
+ export type MigrationPatcher = (row: RawRow, context: MigrationContext) => Promise<RawPatch | undefined> | RawPatch | undefined;
110
+ /**
111
+ * Options of a migration run
112
+ */
113
+ export interface MigrationOptions {
114
+ /**
115
+ * Rows per page
116
+ *
117
+ * @default 500
118
+ */
119
+ batchSize?: number;
120
+ /**
121
+ * Run the patchers and count, write nothing: no row, no progress, no lease
122
+ */
123
+ dryRun?: boolean;
124
+ /**
125
+ * Lease duration in ms, renewed every page
126
+ *
127
+ * @default 300000
128
+ */
129
+ leaseDuration?: number;
130
+ }
131
+ /**
132
+ * Report of one table
133
+ */
134
+ export interface MigrationTableReport {
135
+ /** Rows read */
136
+ scanned: number;
137
+ /** Rows patched (to patch, in a dry run) */
138
+ updated: number;
139
+ /** Count by `"<from> → <to>"` */
140
+ byChange: Record<string, number>;
141
+ /** Untouched rows by stored value */
142
+ unknown: Record<string, number>;
143
+ }
144
+ /**
145
+ * Report of a migration run
146
+ */
147
+ export interface MigrationReport {
148
+ /** Store name */
149
+ store: string;
150
+ /** Migration name */
151
+ name: string;
152
+ /** Report by table */
153
+ tables: Record<string, MigrationTableReport>;
154
+ /** The run continued an interrupted one */
155
+ resumed: boolean;
156
+ /** Nothing was written */
157
+ dryRun: boolean;
158
+ }
159
+ /**
160
+ * Progress of a migration, stored in the Registry entry `storeMigration.<store>.<name>`
161
+ */
162
+ export interface MigrationProgress {
163
+ /** Token of the next page of `table` */
164
+ continuationToken?: string;
165
+ /** Table of the last saved page */
166
+ table?: string;
167
+ /** Rows read */
168
+ scanned: number;
169
+ /** Rows patched */
170
+ updated: number;
171
+ /** Rows left untouched (unknown or ambiguous) */
172
+ unknown: number;
173
+ /** The last run finished */
174
+ done: boolean;
175
+ /** Start of the run, epoch ms */
176
+ startedAt: number;
177
+ /** Last save, epoch ms */
178
+ updatedAt: number;
179
+ /** End of the lease, epoch ms; 0 when free */
180
+ leaseUntil: number;
181
+ /** Runner holding the lease */
182
+ owner?: string;
183
+ /** Report so far by table, so a resumed run ends with the same totals */
184
+ tables: Record<string, MigrationTableReport>;
185
+ }
186
+ /**
187
+ * A lease held by a runner
188
+ */
189
+ export interface MigrationLease {
190
+ /** Registry entry */
191
+ id: string;
192
+ /** Runner id */
193
+ owner: string;
194
+ /** End of the lease, epoch ms, as stored */
195
+ leaseUntil: number;
196
+ /** Lease duration, ms */
197
+ leaseDuration: number;
198
+ /** Progress as stored */
199
+ progress: MigrationProgress;
200
+ }
201
+ /**
202
+ * Default rows per page
203
+ */
204
+ export declare const DEFAULT_MIGRATION_BATCH = 500;
205
+ /**
206
+ * Default lease duration: 5 minutes
207
+ */
208
+ export declare const DEFAULT_MIGRATION_LEASE: number;
209
+ /**
210
+ * Another runner holds the lease of the migration
211
+ */
212
+ export declare class MigrationAlreadyRunning extends WebdaError.CodeError {
213
+ /**
214
+ * @param id - registry entry
215
+ * @param owner - runner holding the lease
216
+ * @param until - end of its lease, epoch ms
217
+ */
218
+ constructor(id: string, owner: string | undefined, until: number);
219
+ }
220
+ /**
221
+ * Increment a counter
222
+ * @param counts - the counters
223
+ * @param key - the counter
224
+ * @param n - the increment
225
+ */
226
+ export declare function incrementCount(counts: Record<string, number>, key: string, n?: number): void;
227
+ /**
228
+ * @returns an empty table report
229
+ */
230
+ export declare function emptyTableReport(): MigrationTableReport;
231
+ /**
232
+ * @returns the progress of a fresh run (the keys set to undefined clear a previous run when saved)
233
+ */
234
+ export declare function emptyProgress(): MigrationProgress;
235
+ /**
236
+ * Read a Registry entry as a progress
237
+ * @param entry - the entry
238
+ * @returns the progress
239
+ */
240
+ export declare function toMigrationProgress(entry: any): MigrationProgress;
241
+ /**
242
+ * Totals of a report, for the progress entry
243
+ * @param report - the report
244
+ * @returns the totals and the tables
245
+ */
246
+ export declare function migrationTotals(report: MigrationReport): {
247
+ scanned: number;
248
+ updated: number;
249
+ unknown: number;
250
+ tables: Record<string, MigrationTableReport>;
251
+ };
252
+ /**
253
+ * Human-readable report, one line per table and per change
254
+ * @param report - the report
255
+ * @param resolver - resolver telling unknown from ambiguous types
256
+ * @returns the text
257
+ */
258
+ export declare function formatMigrationReport(report: MigrationReport, resolver?: ModelTypeResolver): string;
259
+ /**
260
+ * Read the rows of raw tables page by page, in table order, stopping after `maxRows` rows
261
+ * @param pages - reads a page of a table (a store's `rawPages`)
262
+ * @param tables - the tables to read
263
+ * @param maxRows - the row limit
264
+ * @param onRow - called for each row
265
+ * @returns true when rows were left unread because of the limit
266
+ */
267
+ export declare function scanRawRows(pages: (table: string, batchSize: number, token?: string) => Promise<RawPage>, tables: RawTable[], maxRows: number, onRow: (row: RawRow) => void): Promise<boolean>;
268
+ /**
269
+ * Default rows scanned by the startup type check of stores without a native count
270
+ */
271
+ export declare const DEFAULT_TYPE_CHECK_ROWS = 10000;
272
+ /**
273
+ * Count of rows by stored type, by table
274
+ */
275
+ export interface StoredTypeCounts {
276
+ /** Count by stored `__type` (`UNTYPED`, `UNREADABLE` included), by table */
277
+ tables: Record<string, Record<string, number>>;
278
+ /** The scan stopped at its row limit: counts are "at least" */
279
+ truncated: boolean;
280
+ }
281
+ /**
282
+ * Outcome of the startup type check
283
+ */
284
+ export interface TypeCheckSummary {
285
+ /** Rows with a legacy type */
286
+ legacy: number;
287
+ /** Untyped rows that would be stamped */
288
+ untyped: number;
289
+ /** Rows with an unknown, ambiguous or unreadable type */
290
+ unknown: number;
291
+ /** Counts are "at least" */
292
+ truncated: boolean;
293
+ /** WARN message, undefined when every row is current */
294
+ message?: string;
295
+ }
296
+ /**
297
+ * Summarize stored type counts into the startup WARN
298
+ * @param store - store name
299
+ * @param counts - the counts
300
+ * @param roots - root model of each table
301
+ * @param maxRows - the scan limit, for the message
302
+ * @param resolver - the resolver
303
+ * @returns the summary
304
+ */
305
+ export declare function summarizeStoredTypes(store: string, counts: StoredTypeCounts, roots: Map<string, ModelClass | undefined>, maxRows: number, resolver?: ModelTypeResolver): TypeCheckSummary;
306
+ //# sourceMappingURL=migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/stores/migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,280 @@
1
+ import { getTypeResolver } from "@webda/models";
2
+ import * as WebdaError from "../errors/errors.js";
3
+ import { classifyStoredType, UNTYPED } from "../application/model-types.js";
4
+ /**
5
+ * The store has no raw access yet: it cannot run migrations
6
+ */
7
+ export class MigrationUnsupported extends WebdaError.CodeError {
8
+ /**
9
+ * @param store - the store name
10
+ */
11
+ constructor(store) {
12
+ super("MIGRATION_UNSUPPORTED", `Store ${store} has no raw access: it cannot run migrations`);
13
+ }
14
+ }
15
+ /**
16
+ * Parse a value of a key/value storage as a raw row
17
+ * @param table - table name
18
+ * @param key - storage key
19
+ * @param value - stored JSON string (or object, for old persistence files)
20
+ * @returns the row, flagged unreadable when the value is not a JSON object
21
+ */
22
+ export function parseRawValue(table, key, value) {
23
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
24
+ return { table, key, data: { ...value } };
25
+ }
26
+ if (typeof value === "string") {
27
+ try {
28
+ const data = JSON.parse(value);
29
+ if (data !== null && typeof data === "object" && !Array.isArray(data)) {
30
+ return { table, key, data };
31
+ }
32
+ }
33
+ catch {
34
+ // Not JSON: reported as unreadable below
35
+ }
36
+ }
37
+ return { table, key, data: {}, unreadable: true };
38
+ }
39
+ /**
40
+ * Read a page of a key/value storage, in key order
41
+ *
42
+ * The token is the last key of the page, so rows added or removed meanwhile do not shift the next page.
43
+ * @param map - the storage
44
+ * @param table - table name of the rows
45
+ * @param batchSize - rows per page
46
+ * @param token - token of the previous page
47
+ * @returns the page
48
+ */
49
+ export function mapRawPage(map, table, batchSize, token) {
50
+ const keys = [...map.keys()].sort();
51
+ let start = 0;
52
+ if (token !== undefined) {
53
+ start = keys.findIndex(key => key > token);
54
+ if (start < 0)
55
+ start = keys.length;
56
+ }
57
+ const slice = keys.slice(start, start + batchSize);
58
+ const rows = [];
59
+ for (const key of slice) {
60
+ const value = map.get(key);
61
+ if (value !== undefined)
62
+ rows.push(parseRawValue(table, key, value));
63
+ }
64
+ return {
65
+ rows,
66
+ continuationToken: start + batchSize < keys.length ? slice[slice.length - 1] : undefined
67
+ };
68
+ }
69
+ /**
70
+ * Set top-level fields of a row of a key/value storage
71
+ * @param map - the storage
72
+ * @param key - storage key
73
+ * @param patch - fields to set
74
+ */
75
+ export function mapRawPatch(map, key, patch) {
76
+ const value = map.get(key);
77
+ if (value === undefined) {
78
+ throw new Error(`Raw row not found: ${key}`);
79
+ }
80
+ const row = parseRawValue("", key, value);
81
+ if (row.unreadable) {
82
+ throw new Error(`Raw row ${key} is not a JSON object: it cannot be patched`);
83
+ }
84
+ map.set(key, JSON.stringify({ ...row.data, ...patch }));
85
+ }
86
+ /**
87
+ * Default rows per page
88
+ */
89
+ export const DEFAULT_MIGRATION_BATCH = 500;
90
+ /**
91
+ * Default lease duration: 5 minutes
92
+ */
93
+ export const DEFAULT_MIGRATION_LEASE = 5 * 60 * 1000;
94
+ /**
95
+ * Another runner holds the lease of the migration
96
+ */
97
+ export class MigrationAlreadyRunning extends WebdaError.CodeError {
98
+ /**
99
+ * @param id - registry entry
100
+ * @param owner - runner holding the lease
101
+ * @param until - end of its lease, epoch ms
102
+ */
103
+ constructor(id, owner, until) {
104
+ super("MIGRATION_ALREADY_RUNNING", `Migration ${id} is already running (runner ${owner ?? "unknown"}, lease until ${new Date(until).toISOString()})`);
105
+ }
106
+ }
107
+ /**
108
+ * Increment a counter
109
+ * @param counts - the counters
110
+ * @param key - the counter
111
+ * @param n - the increment
112
+ */
113
+ export function incrementCount(counts, key, n = 1) {
114
+ counts[key] = (counts[key] ?? 0) + n;
115
+ }
116
+ /**
117
+ * @returns an empty table report
118
+ */
119
+ export function emptyTableReport() {
120
+ return { scanned: 0, updated: 0, byChange: {}, unknown: {} };
121
+ }
122
+ /**
123
+ * @returns the progress of a fresh run (the keys set to undefined clear a previous run when saved)
124
+ */
125
+ export function emptyProgress() {
126
+ const now = Date.now();
127
+ return {
128
+ table: undefined,
129
+ continuationToken: undefined,
130
+ scanned: 0,
131
+ updated: 0,
132
+ unknown: 0,
133
+ done: false,
134
+ startedAt: now,
135
+ updatedAt: now,
136
+ leaseUntil: 0,
137
+ owner: undefined,
138
+ tables: {}
139
+ };
140
+ }
141
+ /**
142
+ * Read a Registry entry as a progress
143
+ * @param entry - the entry
144
+ * @returns the progress
145
+ */
146
+ export function toMigrationProgress(entry) {
147
+ return {
148
+ continuationToken: entry?.continuationToken,
149
+ table: entry?.table,
150
+ scanned: entry?.scanned ?? 0,
151
+ updated: entry?.updated ?? 0,
152
+ unknown: entry?.unknown ?? 0,
153
+ done: !!entry?.done,
154
+ startedAt: entry?.startedAt ?? 0,
155
+ updatedAt: entry?.updatedAt ?? 0,
156
+ leaseUntil: Number(entry?.leaseUntil ?? 0),
157
+ owner: entry?.owner,
158
+ tables: entry?.tables ?? {}
159
+ };
160
+ }
161
+ /**
162
+ * Totals of a report, for the progress entry
163
+ * @param report - the report
164
+ * @returns the totals and the tables
165
+ */
166
+ export function migrationTotals(report) {
167
+ let scanned = 0;
168
+ let updated = 0;
169
+ let unknown = 0;
170
+ for (const table of Object.values(report.tables)) {
171
+ scanned += table.scanned;
172
+ updated += table.updated;
173
+ unknown += Object.values(table.unknown).reduce((sum, n) => sum + n, 0);
174
+ }
175
+ return { scanned, updated, unknown, tables: report.tables };
176
+ }
177
+ /**
178
+ * Entries of a record sorted by key, by UTF-16 code unit (the default sort order)
179
+ * @param record - the record
180
+ * @returns the entries
181
+ */
182
+ function sortedEntries(record) {
183
+ return Object.keys(record)
184
+ .sort()
185
+ .map(key => [key, record[key]]);
186
+ }
187
+ /**
188
+ * Human-readable report, one line per table and per change
189
+ * @param report - the report
190
+ * @param resolver - resolver telling unknown from ambiguous types
191
+ * @returns the text
192
+ */
193
+ export function formatMigrationReport(report, resolver = getTypeResolver()) {
194
+ const flags = [report.dryRun ? "dry run" : undefined, report.resumed ? "resumed" : undefined].filter(Boolean);
195
+ const lines = [`Store ${report.store}: migration ${report.name}${flags.length ? ` (${flags.join(", ")})` : ""}`];
196
+ for (const [table, tableReport] of Object.entries(report.tables)) {
197
+ lines.push(` ${table}: ${tableReport.scanned} scanned, ${tableReport.updated} ${report.dryRun ? "to update" : "updated"}`);
198
+ for (const [change, n] of sortedEntries(tableReport.byChange)) {
199
+ lines.push(` ${change}: ${n}`);
200
+ }
201
+ for (const [type, n] of sortedEntries(tableReport.unknown)) {
202
+ lines.push(` ${resolver.resolve(type).status === "ambiguous" ? "ambiguous" : "unknown"} ${type}: ${n}`);
203
+ }
204
+ }
205
+ return lines.join("\n");
206
+ }
207
+ /**
208
+ * Read the rows of raw tables page by page, in table order, stopping after `maxRows` rows
209
+ * @param pages - reads a page of a table (a store's `rawPages`)
210
+ * @param tables - the tables to read
211
+ * @param maxRows - the row limit
212
+ * @param onRow - called for each row
213
+ * @returns true when rows were left unread because of the limit
214
+ */
215
+ export async function scanRawRows(pages, tables, maxRows, onRow) {
216
+ let seen = 0;
217
+ for (const [index, table] of tables.entries()) {
218
+ let token;
219
+ do {
220
+ if (seen >= maxRows)
221
+ return true;
222
+ const page = await pages(table.name, Math.min(1000, maxRows - seen), token);
223
+ for (const row of page.rows) {
224
+ onRow(row);
225
+ seen++;
226
+ }
227
+ token = page.continuationToken;
228
+ } while (token);
229
+ if (seen >= maxRows && index < tables.length - 1)
230
+ return true;
231
+ }
232
+ return false;
233
+ }
234
+ /**
235
+ * Default rows scanned by the startup type check of stores without a native count
236
+ */
237
+ export const DEFAULT_TYPE_CHECK_ROWS = 10000;
238
+ /**
239
+ * Summarize stored type counts into the startup WARN
240
+ * @param store - store name
241
+ * @param counts - the counts
242
+ * @param roots - root model of each table
243
+ * @param maxRows - the scan limit, for the message
244
+ * @param resolver - the resolver
245
+ * @returns the summary
246
+ */
247
+ export function summarizeStoredTypes(store, counts, roots, maxRows, resolver = getTypeResolver()) {
248
+ const summary = { legacy: 0, untyped: 0, unknown: 0, truncated: counts.truncated };
249
+ const parts = [];
250
+ for (const [table, types] of Object.entries(counts.tables)) {
251
+ const entries = [];
252
+ for (const [type, n] of sortedEntries(types)) {
253
+ const kind = classifyStoredType(type === UNTYPED ? undefined : type, roots.get(table), resolver);
254
+ if (kind.kind === "current" || (kind.kind === "untyped" && !kind.to))
255
+ continue;
256
+ if (kind.kind === "legacy") {
257
+ summary.legacy += n;
258
+ entries.push(`'${type}' → ${kind.to}: ${n}`);
259
+ }
260
+ else if (kind.kind === "untyped") {
261
+ summary.untyped += n;
262
+ entries.push(`untyped → ${kind.to}: ${n}`);
263
+ }
264
+ else {
265
+ summary.unknown += n;
266
+ entries.push(`${kind.kind} '${type}': ${n}`);
267
+ }
268
+ }
269
+ if (entries.length)
270
+ parts.push(`${table} (${entries.join(", ")})`);
271
+ }
272
+ if (parts.length) {
273
+ summary.message =
274
+ `Store ${store} holds rows with legacy, untyped or unknown types: ${parts.join("; ")}` +
275
+ `${counts.truncated ? ` — at least: the check stopped after ${maxRows} rows` : ""}. ` +
276
+ "Run `webda migrate` to rewrite them.";
277
+ }
278
+ return summary;
279
+ }
280
+ //# sourceMappingURL=migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/stores/migration.ts"],"names":[],"mappings":"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"}