@xixixao/convex-migrations 0.3.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/LICENSE +201 -0
- package/README.md +523 -0
- package/dist/client/index.d.ts +383 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +528 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/log.d.ts +8 -0
- package/dist/client/log.d.ts.map +1 -0
- package/dist/client/log.js +74 -0
- package/dist/client/log.js.map +1 -0
- package/dist/component/_generated/api.d.ts +34 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +95 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +3 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/lib.d.ts +74 -0
- package/dist/component/lib.d.ts.map +1 -0
- package/dist/component/lib.js +290 -0
- package/dist/component/lib.js.map +1 -0
- package/dist/component/schema.d.ts +28 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +20 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/shared.d.ts +40 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +22 -0
- package/dist/shared.js.map +1 -0
- package/package.json +95 -0
- package/src/client/index.test.ts +16 -0
- package/src/client/index.ts +748 -0
- package/src/client/log.ts +76 -0
- package/src/component/_generated/api.ts +50 -0
- package/src/component/_generated/component.ts +116 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +161 -0
- package/src/component/convex.config.ts +3 -0
- package/src/component/lib.test.ts +110 -0
- package/src/component/lib.ts +356 -0
- package/src/component/schema.ts +20 -0
- package/src/component/setup.test.ts +5 -0
- package/src/shared.ts +37 -0
- package/src/test.ts +18 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import { createFunctionHandle, getFunctionAddress, getFunctionName, internalMutationGeneric, makeFunctionReference, } from "convex/server";
|
|
2
|
+
import { migrationArgs, } from "../shared.js";
|
|
3
|
+
import { ConvexError, v, } from "convex/values";
|
|
4
|
+
import { logStatusAndInstructions } from "./log.js";
|
|
5
|
+
// Note: this value is hard-coded in the docstring below. Please keep in sync.
|
|
6
|
+
export const DEFAULT_BATCH_SIZE = 100;
|
|
7
|
+
/**
|
|
8
|
+
* When args are provided, append a deterministic serialization to the migration
|
|
9
|
+
* name so that each unique set of args is tracked as a separate migration run.
|
|
10
|
+
*/
|
|
11
|
+
function migrationNameWithArgs(baseName, args) {
|
|
12
|
+
if (args === undefined || args === null)
|
|
13
|
+
return baseName;
|
|
14
|
+
const serialized = JSON.stringify(args, Object.keys(args).sort());
|
|
15
|
+
return `${baseName}(${serialized})`;
|
|
16
|
+
}
|
|
17
|
+
export class Migrations {
|
|
18
|
+
component;
|
|
19
|
+
options;
|
|
20
|
+
/**
|
|
21
|
+
* Makes the migration wrapper, with types for your own tables.
|
|
22
|
+
*
|
|
23
|
+
* It will keep track of migration state.
|
|
24
|
+
* Add in convex/migrations.ts for example:
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { Migrations } from "@convex-dev/migrations";
|
|
27
|
+
* import { components } from "./_generated/api.js";
|
|
28
|
+
* import { internalMutation } from "./_generated/server";
|
|
29
|
+
*
|
|
30
|
+
* export const migrations = new Migrations(components.migrations, { internalMutation });
|
|
31
|
+
* // the private mutation to run migrations.
|
|
32
|
+
* export const run = migrations.runner();
|
|
33
|
+
*
|
|
34
|
+
* export const myMigration = migrations.define({
|
|
35
|
+
* table: "users",
|
|
36
|
+
* migrateOne: async (ctx, doc) => {
|
|
37
|
+
* await ctx.db.patch(doc._id, { someField: "value" });
|
|
38
|
+
* }
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
* You can then run it from the CLI or dashboard:
|
|
42
|
+
* ```sh
|
|
43
|
+
* npx convex run migrations:run '{"fn": "migrations:myMigration"}'
|
|
44
|
+
* ```
|
|
45
|
+
* For starting a migration from code, see {@link runOne}/{@link runSerially}.
|
|
46
|
+
* @param component - The migrations component. It will be on components.migrations
|
|
47
|
+
* after being configured in in convex.config.js.
|
|
48
|
+
* @param options - Configure options and set the internalMutation to use.
|
|
49
|
+
*/
|
|
50
|
+
constructor(component, options) {
|
|
51
|
+
this.component = component;
|
|
52
|
+
this.options = options;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Creates a migration runner that can be called from the CLI or dashboard.
|
|
56
|
+
*
|
|
57
|
+
* For starting a migration from code, see {@link runOne}/{@link runSerially}.
|
|
58
|
+
*
|
|
59
|
+
* It can be created for a specific migration:
|
|
60
|
+
* ```ts
|
|
61
|
+
* export const runMyMigration = runner(internal.migrations.myMigration);
|
|
62
|
+
* ```
|
|
63
|
+
* CLI: `npx convex run migrations:runMyMigration`
|
|
64
|
+
*
|
|
65
|
+
* Or for any migration:
|
|
66
|
+
* ```ts
|
|
67
|
+
* export const run = runner();
|
|
68
|
+
* ```
|
|
69
|
+
* CLI: `npx convex run migrations:run '{"fn": "migrations:myMigration"}'`
|
|
70
|
+
*
|
|
71
|
+
* Where `myMigration` is the name of the migration function, defined in
|
|
72
|
+
* "convex/migrations.ts" along with the run function.
|
|
73
|
+
*
|
|
74
|
+
* @param specificMigration If you want a migration runner for one migration,
|
|
75
|
+
* pass in the migration function reference like `internal.migrations.foo`.
|
|
76
|
+
* Otherwise it will be a generic runner that requires the migration name.
|
|
77
|
+
* @returns An internal mutation,
|
|
78
|
+
*/
|
|
79
|
+
runner(specificMigrationOrSeries) {
|
|
80
|
+
return internalMutationGeneric({
|
|
81
|
+
args: migrationArgs,
|
|
82
|
+
handler: async (ctx, args) => {
|
|
83
|
+
const [specificMigration, next] = Array.isArray(specificMigrationOrSeries)
|
|
84
|
+
? [
|
|
85
|
+
specificMigrationOrSeries[0],
|
|
86
|
+
await Promise.all(specificMigrationOrSeries.slice(1).map(async (fnRef) => ({
|
|
87
|
+
name: getFunctionName(fnRef),
|
|
88
|
+
fnHandle: await createFunctionHandle(fnRef),
|
|
89
|
+
}))),
|
|
90
|
+
]
|
|
91
|
+
: [specificMigrationOrSeries, undefined];
|
|
92
|
+
if (args.fn && specificMigration) {
|
|
93
|
+
throw new Error("Specify only one of fn or specificMigration");
|
|
94
|
+
}
|
|
95
|
+
if (!args.fn && !specificMigration) {
|
|
96
|
+
throw new Error(`Specify the migration: '{"fn": "migrations:foo"}'\n` +
|
|
97
|
+
"Or initialize a `runner` runner specific to the migration like\n" +
|
|
98
|
+
"`export const runMyMigration = runner(internal.migrations.myMigration)`");
|
|
99
|
+
}
|
|
100
|
+
return await this._runInteractive(ctx, args, specificMigration, next);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
async _runInteractive(ctx, args, fnRef, next) {
|
|
105
|
+
const baseName = args.fn
|
|
106
|
+
? this.prefixedName(args.fn)
|
|
107
|
+
: getFunctionName(fnRef);
|
|
108
|
+
const name = migrationNameWithArgs(baseName, args.args);
|
|
109
|
+
async function makeFn(fn) {
|
|
110
|
+
try {
|
|
111
|
+
return await createFunctionHandle(makeFunctionReference(fn));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
throw new Error(`Can't find function ${fn}\n` +
|
|
115
|
+
"The name should match the folder/file:method\n" +
|
|
116
|
+
"See https://docs.convex.dev/functions/query-functions#query-names");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const fnHandle = args.fn
|
|
120
|
+
? await makeFn(name)
|
|
121
|
+
: await createFunctionHandle(fnRef);
|
|
122
|
+
if (args.next) {
|
|
123
|
+
next = (next ?? []).concat(await Promise.all(args.next.map(async (nextFn) => ({
|
|
124
|
+
name: this.prefixedName(nextFn),
|
|
125
|
+
fnHandle: await makeFn(this.prefixedName(nextFn)),
|
|
126
|
+
}))));
|
|
127
|
+
}
|
|
128
|
+
let status;
|
|
129
|
+
try {
|
|
130
|
+
status = await ctx.runMutation(this.component.lib.migrate, {
|
|
131
|
+
name,
|
|
132
|
+
fnHandle,
|
|
133
|
+
cursor: args.cursor,
|
|
134
|
+
batchSize: args.batchSize,
|
|
135
|
+
next,
|
|
136
|
+
dryRun: args.dryRun ?? false,
|
|
137
|
+
args: args.args,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
if (args.dryRun &&
|
|
142
|
+
e instanceof ConvexError &&
|
|
143
|
+
e.data.kind === "DRY RUN") {
|
|
144
|
+
status = e.data.status;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
throw e;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return logStatusAndInstructions(name, status, args);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Use this to wrap a mutation that will be run over all documents in a table.
|
|
154
|
+
* Your mutation only needs to handle changing one document at a time,
|
|
155
|
+
* passed into migrateOne.
|
|
156
|
+
* Optionally specify a custom batch size to override the default (100).
|
|
157
|
+
*
|
|
158
|
+
* In convex/migrations.ts for example:
|
|
159
|
+
* ```ts
|
|
160
|
+
* export const foo = migrations.define({
|
|
161
|
+
* table: "users",
|
|
162
|
+
* migrateOne: async (ctx, doc) => {
|
|
163
|
+
* await ctx.db.patch(doc._id, { someField: "value" });
|
|
164
|
+
* },
|
|
165
|
+
* });
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* You can run this manually from the CLI or dashboard:
|
|
169
|
+
* ```sh
|
|
170
|
+
* # Start or resume a migration. No-ops if it's already done:
|
|
171
|
+
* npx convex run migrations:run '{"fn": "migrations:foo"}'
|
|
172
|
+
*
|
|
173
|
+
* # Restart a migration from a cursor (null is from the beginning):
|
|
174
|
+
* npx convex run migrations:run '{"fn": "migrations:foo", "cursor": null }'
|
|
175
|
+
*
|
|
176
|
+
* # Dry run - runs one batch but doesn't schedule or commit changes.
|
|
177
|
+
* # so you can see what it would do without committing the transaction.
|
|
178
|
+
* npx convex run migrations:run '{"fn": "migrations:foo", "dryRun": true}'
|
|
179
|
+
* # or
|
|
180
|
+
* npx convex run migrations:myMigration '{"dryRun": true}'
|
|
181
|
+
*
|
|
182
|
+
* # Run many migrations serially:
|
|
183
|
+
* npx convex run migrations:run '{"fn": "migrations:foo", "next": ["migrations:bar", "migrations:baz"] }'
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
186
|
+
* The fn is the string form of the function reference. See:
|
|
187
|
+
* https://docs.convex.dev/functions/query-functions#query-names
|
|
188
|
+
*
|
|
189
|
+
* See {@link runOne} and {@link runSerially} for programmatic use.
|
|
190
|
+
*
|
|
191
|
+
* @param table - The table to run the migration over.
|
|
192
|
+
* @param migrateOne - The function to run on each document.
|
|
193
|
+
* @param batchSize - The number of documents to process in a batch.
|
|
194
|
+
* If not set, defaults to the value passed to makeMigration,
|
|
195
|
+
* or {@link DEFAULT_BATCH_SIZE}. Overriden by arg at runtime if supplied.
|
|
196
|
+
* @param parallelize - If true, each migration batch will be run in parallel.
|
|
197
|
+
* @returns An internal mutation that runs the migration.
|
|
198
|
+
*/
|
|
199
|
+
define({ table, migrateOne, customRange, batchSize: functionDefaultBatchSize, parallelize, args: defineArgs, }) {
|
|
200
|
+
const defaultBatchSize = functionDefaultBatchSize ??
|
|
201
|
+
this.options?.defaultBatchSize ??
|
|
202
|
+
DEFAULT_BATCH_SIZE;
|
|
203
|
+
// Under the hood it's an internal mutation that calls the migrateOne
|
|
204
|
+
// function for every document in a page, recursively scheduling batches.
|
|
205
|
+
return (this.options?.internalMutation ?? internalMutationGeneric)({
|
|
206
|
+
args: {
|
|
207
|
+
...migrationArgs,
|
|
208
|
+
args: v.optional((defineArgs ?? v.any())),
|
|
209
|
+
},
|
|
210
|
+
handler: async (ctx, args) => {
|
|
211
|
+
if (args.fn) {
|
|
212
|
+
// This is a one-off execution from the CLI or dashboard.
|
|
213
|
+
// While not the recommended appproach, it's helpful for one-offs and
|
|
214
|
+
// compatibility with the old way of running migrations.
|
|
215
|
+
return (await this._runInteractive(ctx, args));
|
|
216
|
+
}
|
|
217
|
+
else if (args.next?.length) {
|
|
218
|
+
throw new Error("You can only pass next if you also provide fn");
|
|
219
|
+
}
|
|
220
|
+
else if (args.cursor === undefined ||
|
|
221
|
+
args.cursor === "" ||
|
|
222
|
+
args.dryRun === undefined ||
|
|
223
|
+
args.batchSize === 0) {
|
|
224
|
+
console.warn("Running this from the CLI or dashboard? Here's some args to use:");
|
|
225
|
+
console.warn({
|
|
226
|
+
"Dry run": '{ "dryRun": true, "cursor": null }',
|
|
227
|
+
"For real": '{ "fn": "path/to/migrations:yourFnName" }',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
const numItems = args.batchSize || defaultBatchSize;
|
|
231
|
+
if (args.cursor === undefined || args.cursor === "") {
|
|
232
|
+
if (args.dryRun === undefined) {
|
|
233
|
+
console.warn("No cursor or dryRun specified - doing a dry run on the next batch.");
|
|
234
|
+
args.cursor = null;
|
|
235
|
+
args.dryRun = true;
|
|
236
|
+
}
|
|
237
|
+
else if (args.dryRun) {
|
|
238
|
+
console.warn("Setting cursor to null for dry run");
|
|
239
|
+
args.cursor = null;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
throw new Error(`Cursor must be specified for a one-off execution.
|
|
243
|
+
Use null to start from the beginning.
|
|
244
|
+
Use the value in the migrations database to pick up from where it left off.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const q = ctx.db.query(table);
|
|
248
|
+
const range = customRange ? customRange(q, args.args) : q;
|
|
249
|
+
let continueCursor;
|
|
250
|
+
let page;
|
|
251
|
+
let isDone;
|
|
252
|
+
try {
|
|
253
|
+
({ continueCursor, page, isDone } = await range.paginate({
|
|
254
|
+
cursor: args.cursor,
|
|
255
|
+
numItems,
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
console.error("Error paginating. This can happen if the migration " +
|
|
260
|
+
"was initially run on a different table, different custom range, " +
|
|
261
|
+
"or you upgraded convex-helpers with in-progress migrations. " +
|
|
262
|
+
"This creates an invalid pagination cursor. " +
|
|
263
|
+
"Run all migrations to completion on the old cursor, or re-run " +
|
|
264
|
+
"them explicitly with the cursor set to null. " +
|
|
265
|
+
"If the problem persists, contact support@convex.dev");
|
|
266
|
+
throw e;
|
|
267
|
+
}
|
|
268
|
+
async function doOne(doc) {
|
|
269
|
+
try {
|
|
270
|
+
const next = await migrateOne(ctx, doc, args.args);
|
|
271
|
+
if (next && Object.keys(next).length > 0) {
|
|
272
|
+
await ctx.db.patch(doc._id, next);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
console.error(`Document failed: ${doc._id}`);
|
|
277
|
+
throw error;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
if (parallelize) {
|
|
281
|
+
await Promise.all(page.map(doOne));
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
for (const doc of page) {
|
|
285
|
+
await doOne(doc);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const result = {
|
|
289
|
+
continueCursor,
|
|
290
|
+
isDone,
|
|
291
|
+
processed: page.length,
|
|
292
|
+
};
|
|
293
|
+
if (args.dryRun) {
|
|
294
|
+
// Throwing an error rolls back the transaction
|
|
295
|
+
let anyChanges = false;
|
|
296
|
+
let printedChanges = 0;
|
|
297
|
+
for (const before of page) {
|
|
298
|
+
const after = await ctx.db.get(before._id);
|
|
299
|
+
if (JSON.stringify(after) !== JSON.stringify(before)) {
|
|
300
|
+
anyChanges = true;
|
|
301
|
+
printedChanges++;
|
|
302
|
+
if (printedChanges > 10) {
|
|
303
|
+
console.debug("DRY RUN: More than 10 changes were found in the first page. Skipping the rest.");
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
console.debug("DRY RUN: Example change", {
|
|
307
|
+
before,
|
|
308
|
+
after,
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
if (!anyChanges) {
|
|
313
|
+
console.debug("DRY RUN: No changes were found in the first page. " +
|
|
314
|
+
`Try {"dryRun": true, "cursor": "${continueCursor}"}`);
|
|
315
|
+
}
|
|
316
|
+
throw new ConvexError({
|
|
317
|
+
kind: "DRY RUN",
|
|
318
|
+
result,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
if (args.dryRun === undefined) {
|
|
322
|
+
// We are running it in a one-off mode.
|
|
323
|
+
// The component will always provide dryRun.
|
|
324
|
+
// A bit of a hack / implicit, but non-critical logging.
|
|
325
|
+
console.debug(`Next cursor: ${continueCursor}`);
|
|
326
|
+
}
|
|
327
|
+
return result;
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Start a migration from a server function via a function reference.
|
|
333
|
+
*
|
|
334
|
+
* ```ts
|
|
335
|
+
* const migrations = new Migrations(components.migrations, { internalMutation });
|
|
336
|
+
*
|
|
337
|
+
* // in a mutation or action:
|
|
338
|
+
* await migrations.runOne(ctx, internal.migrations.myMigration, {
|
|
339
|
+
* cursor: null, // optional override
|
|
340
|
+
* batchSize: 10, // optional override
|
|
341
|
+
* });
|
|
342
|
+
* ```
|
|
343
|
+
*
|
|
344
|
+
* Overrides any options you passed in, such as resetting the cursor.
|
|
345
|
+
* If it's already in progress, it will no-op.
|
|
346
|
+
* If you run a migration that had previously failed which was part of a series,
|
|
347
|
+
* it will not resume the series.
|
|
348
|
+
* To resume a series, call the series again: {@link Migrations.runSerially}.
|
|
349
|
+
*
|
|
350
|
+
* Note: It's up to you to determine if it's safe to run a migration while
|
|
351
|
+
* others are in progress. It won't run multiple instance of the same migration
|
|
352
|
+
* but it currently allows running multiple migrations on the same table.
|
|
353
|
+
*
|
|
354
|
+
* @param ctx Context from a mutation or action. Needs `runMutation`.
|
|
355
|
+
* @param fnRef The migration function to run. Like `internal.migrations.foo`.
|
|
356
|
+
* @param opts Options to start the migration.
|
|
357
|
+
* @param opts.cursor The cursor to start from.
|
|
358
|
+
* null: start from the beginning.
|
|
359
|
+
* undefined: start or resume from where it failed. If done, it won't restart.
|
|
360
|
+
* @param opts.batchSize The number of documents to process in a batch.
|
|
361
|
+
* @param opts.dryRun If true, it will run a batch and then throw an error.
|
|
362
|
+
* It's helpful to see what it would do without committing the transaction.
|
|
363
|
+
*/
|
|
364
|
+
async runOne(ctx, fnRef, opts) {
|
|
365
|
+
const baseName = getFunctionName(fnRef);
|
|
366
|
+
return ctx.runMutation(this.component.lib.migrate, {
|
|
367
|
+
name: migrationNameWithArgs(baseName, opts?.args),
|
|
368
|
+
fnHandle: await createFunctionHandle(fnRef),
|
|
369
|
+
cursor: opts?.cursor,
|
|
370
|
+
batchSize: opts?.batchSize,
|
|
371
|
+
dryRun: opts?.dryRun ?? false,
|
|
372
|
+
args: opts?.args,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Start a series of migrations, running one a time. Each call starts a series.
|
|
377
|
+
*
|
|
378
|
+
* ```ts
|
|
379
|
+
* const migrations = new Migrations(components.migrations, { internalMutation });
|
|
380
|
+
*
|
|
381
|
+
* // in a mutation or action:
|
|
382
|
+
* await migrations.runSerially(ctx, [
|
|
383
|
+
* internal.migrations.myMigration,
|
|
384
|
+
* internal.migrations.myOtherMigration,
|
|
385
|
+
* ]);
|
|
386
|
+
* ```
|
|
387
|
+
*
|
|
388
|
+
* It runs one batch at a time currently.
|
|
389
|
+
* If a migration has previously completed it will skip it.
|
|
390
|
+
* If a migration had partial progress, it will resume from where it left off.
|
|
391
|
+
* If a migration is already in progress when attempted, it will no-op.
|
|
392
|
+
* If a migration fails or is canceled, it will stop executing and NOT execute
|
|
393
|
+
* any subsequent migrations in the series. Call the series again to retry.
|
|
394
|
+
*
|
|
395
|
+
* This is useful to run as an post-deploy script where you specify all the
|
|
396
|
+
* live migrations that should be run.
|
|
397
|
+
*
|
|
398
|
+
* Note: if you start multiple serial migrations, the behavior is:
|
|
399
|
+
* - If they don't overlap on functions, they will happily run in parallel.
|
|
400
|
+
* - If they have a function in common and one completes before the other
|
|
401
|
+
* attempts it, the second will just skip it.
|
|
402
|
+
* - If they have a function in common and one is in progress, the second will
|
|
403
|
+
* no-op and not run any further migrations in its series.
|
|
404
|
+
*
|
|
405
|
+
* To stop a migration in progress, see {@link cancelMigration}.
|
|
406
|
+
*
|
|
407
|
+
* @param ctx Context from a mutation or action. Needs `runMutation`.
|
|
408
|
+
* @param fnRefs The migrations to run in order. Like [internal.migrations.foo].
|
|
409
|
+
*/
|
|
410
|
+
async runSerially(ctx, fnRefs) {
|
|
411
|
+
if (fnRefs.length === 0)
|
|
412
|
+
return;
|
|
413
|
+
const [fnRef, ...rest] = fnRefs;
|
|
414
|
+
const next = await Promise.all(rest.map(async (fnRef) => ({
|
|
415
|
+
name: getFunctionName(fnRef),
|
|
416
|
+
fnHandle: await createFunctionHandle(fnRef),
|
|
417
|
+
})));
|
|
418
|
+
return ctx.runMutation(this.component.lib.migrate, {
|
|
419
|
+
name: getFunctionName(fnRef),
|
|
420
|
+
fnHandle: await createFunctionHandle(fnRef),
|
|
421
|
+
next,
|
|
422
|
+
dryRun: false,
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get the status of a migration or all migrations.
|
|
427
|
+
* @param ctx Context from a query, mutation or action. Needs `runQuery`.
|
|
428
|
+
* @param migrations The migrations to get the status of. Defaults to all.
|
|
429
|
+
* @param limit How many migrations to fetch, if not specified by name.
|
|
430
|
+
* @returns The status of the migrations, in the order of the input.
|
|
431
|
+
*/
|
|
432
|
+
async getStatus(ctx, { migrations, limit, }) {
|
|
433
|
+
const names = migrations?.map((m) => typeof m === "string" ? this.prefixedName(m) : getFunctionName(m));
|
|
434
|
+
return ctx.runQuery(this.component.lib.getStatus, {
|
|
435
|
+
names,
|
|
436
|
+
limit,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Cancels a migration if it's in progress.
|
|
441
|
+
* You can resume it later by calling the migration without an explicit cursor.
|
|
442
|
+
* If the migration had "next" migrations, e.g. from {@link runSerially},
|
|
443
|
+
* they will not run. To resume, call the series again or manually pass "next".
|
|
444
|
+
* @param ctx Context from a mutation or action. Needs `runMutation`.
|
|
445
|
+
* @param migration Migration to cancel. Either the name like "migrations:foo"
|
|
446
|
+
* or the function reference like `internal.migrations.foo`.
|
|
447
|
+
* @returns The status of the migration after attempting to cancel it.
|
|
448
|
+
*/
|
|
449
|
+
async cancel(ctx, migration) {
|
|
450
|
+
const name = typeof migration === "string"
|
|
451
|
+
? this.prefixedName(migration)
|
|
452
|
+
: getFunctionName(migration);
|
|
453
|
+
return ctx.runMutation(this.component.lib.cancel, { name });
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Cancels all migrations that are in progress.
|
|
457
|
+
* You can resume it later by calling the migration without an explicit cursor.
|
|
458
|
+
* If the migration had "next" migrations, e.g. from {@link runSerially},
|
|
459
|
+
* they will not run. To resume, call the series again or manually pass "next".
|
|
460
|
+
* @param ctx Context from a mutation or action. Needs `runMutation`.
|
|
461
|
+
* @returns The status of up to 100 of the canceled migrations.
|
|
462
|
+
*/
|
|
463
|
+
async cancelAll(ctx) {
|
|
464
|
+
return ctx.runMutation(this.component.lib.cancelAll, {});
|
|
465
|
+
}
|
|
466
|
+
// Helper to prefix the name with the location.
|
|
467
|
+
// migrationsLocationPrefix of "bar/baz:" and name "foo" => "bar/baz:foo"
|
|
468
|
+
prefixedName(name) {
|
|
469
|
+
return this.options?.migrationsLocationPrefix && !name.includes(":")
|
|
470
|
+
? `${this.options.migrationsLocationPrefix}${name}`
|
|
471
|
+
: name;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Start a migration and run it synchronously until it's done.
|
|
476
|
+
* If this function crashes, the migration will not continue.
|
|
477
|
+
*
|
|
478
|
+
* ```ts
|
|
479
|
+
* // In an action
|
|
480
|
+
* const toRun = internal.migrations.myMigration;
|
|
481
|
+
* await runToCompletion(ctx, components.migrations, toRun);
|
|
482
|
+
* ```
|
|
483
|
+
*
|
|
484
|
+
* If it's already in progress, it will no-op.
|
|
485
|
+
* If you run a migration that had previously failed which was part of a series,
|
|
486
|
+
* it will not resume the series.
|
|
487
|
+
* To resume a series, call the series again: {@link Migrations.runSerially}.
|
|
488
|
+
*
|
|
489
|
+
* Note: It's up to you to determine if it's safe to run a migration while
|
|
490
|
+
* others are in progress. It won't run multiple instances of the same migration
|
|
491
|
+
* but it currently allows running multiple migrations on the same table.
|
|
492
|
+
*
|
|
493
|
+
* @param ctx Context from an action.
|
|
494
|
+
* @param component The migrations component, usually `components.migrations`.
|
|
495
|
+
* @param fnRef The migration function to run. Like `internal.migrations.foo`.
|
|
496
|
+
* @param opts Options to start the migration.
|
|
497
|
+
* It's helpful to see what it would do without committing the transaction.
|
|
498
|
+
*/
|
|
499
|
+
export async function runToCompletion(ctx, component, fnRef, opts) {
|
|
500
|
+
let cursor = opts?.cursor;
|
|
501
|
+
const { name: nameOverride, batchSize, dryRun = false, args, } = opts ?? {};
|
|
502
|
+
const name = nameOverride ?? migrationNameWithArgs(getFunctionName(fnRef), args);
|
|
503
|
+
const address = getFunctionAddress(fnRef);
|
|
504
|
+
const fnHandle = address.functionHandle ?? (await createFunctionHandle(fnRef));
|
|
505
|
+
while (true) {
|
|
506
|
+
const status = await ctx.runMutation(component.lib.migrate, {
|
|
507
|
+
name,
|
|
508
|
+
fnHandle,
|
|
509
|
+
cursor,
|
|
510
|
+
batchSize,
|
|
511
|
+
dryRun,
|
|
512
|
+
args,
|
|
513
|
+
oneBatchOnly: true,
|
|
514
|
+
});
|
|
515
|
+
if (status.isDone) {
|
|
516
|
+
return status;
|
|
517
|
+
}
|
|
518
|
+
if (status.error) {
|
|
519
|
+
throw new Error(status.error);
|
|
520
|
+
}
|
|
521
|
+
if (!status.cursor || status.cursor === cursor) {
|
|
522
|
+
throw new Error("Invariant violation: Migration did not make progress." +
|
|
523
|
+
`\nStatus: ${JSON.stringify(status)}`);
|
|
524
|
+
}
|
|
525
|
+
cursor = status.cursor;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MigrationStatus } from "../shared.js";
|
|
2
|
+
export declare function logStatusAndInstructions(name: string, status: MigrationStatus, args: {
|
|
3
|
+
fn?: string;
|
|
4
|
+
cursor?: string | null;
|
|
5
|
+
batchSize?: number;
|
|
6
|
+
dryRun?: boolean;
|
|
7
|
+
}): Record<string, unknown>;
|
|
8
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/client/log.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE;IACJ,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,2BAiEF"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export function logStatusAndInstructions(name, status, args) {
|
|
2
|
+
const output = {};
|
|
3
|
+
if (status.isDone) {
|
|
4
|
+
if (status.latestEnd < Date.now()) {
|
|
5
|
+
output["Status"] = "Migration already done.";
|
|
6
|
+
}
|
|
7
|
+
else if (status.latestStart === status.latestEnd) {
|
|
8
|
+
output["Status"] = "Migration was started and finished in one batch.";
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
output["Status"] = "Migration completed with this batch.";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
if (status.state === "failed") {
|
|
16
|
+
output["Status"] = `Migration failed: ${status.error}`;
|
|
17
|
+
}
|
|
18
|
+
else if (status.state === "canceled") {
|
|
19
|
+
output["Status"] = "Migration canceled.";
|
|
20
|
+
}
|
|
21
|
+
else if (status.latestStart >= Date.now()) {
|
|
22
|
+
output["Status"] = "Migration started.";
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
output["Status"] = "Migration running.";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (args.dryRun) {
|
|
29
|
+
output["DryRun"] = "No changes were committed.";
|
|
30
|
+
output["Status"] = "DRY RUN: " + output["Status"];
|
|
31
|
+
}
|
|
32
|
+
output["Name"] = name;
|
|
33
|
+
output["lastStarted"] = new Date(status.latestStart).toISOString();
|
|
34
|
+
if (status.latestEnd) {
|
|
35
|
+
output["lastFinished"] = new Date(status.latestEnd).toISOString();
|
|
36
|
+
}
|
|
37
|
+
output["processed"] = status.processed;
|
|
38
|
+
if (status.next?.length) {
|
|
39
|
+
if (status.isDone) {
|
|
40
|
+
output["nowUp"] = status.next;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
output["nextUp"] = status.next;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const nextArgs = (status.next || []).map((n) => `"${n}"`).join(", ");
|
|
47
|
+
const run = `npx convex run --component migrations`;
|
|
48
|
+
if (!args.dryRun) {
|
|
49
|
+
if (status.state === "inProgress") {
|
|
50
|
+
output["toCancel"] = {
|
|
51
|
+
cmd: `${run} lib:cancel`,
|
|
52
|
+
args: `{"name": "${name}"}`,
|
|
53
|
+
prod: `--prod`,
|
|
54
|
+
};
|
|
55
|
+
output["toMonitorStatus"] = {
|
|
56
|
+
cmd: `${run} --watch lib:getStatus`,
|
|
57
|
+
args: `{"names": ["${name}"${status.next?.length ? ", " + nextArgs : ""}]}`,
|
|
58
|
+
prod: `--prod`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
output["toStartOver"] = JSON.stringify({ ...args, cursor: null });
|
|
63
|
+
if (status.next?.length) {
|
|
64
|
+
output["toMonitorStatus"] = {
|
|
65
|
+
cmd: `${run} --watch lib:getStatus`,
|
|
66
|
+
args: `{"names": [${nextArgs}]}`,
|
|
67
|
+
prod: `--prod`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return output;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/client/log.ts"],"names":[],"mappings":"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"}
|