@prairielearn/migrations 1.1.0 → 1.2.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.
Files changed (85) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +145 -0
  4. package/dist/batched-migrations/batched-migration-job.d.ts +42 -0
  5. package/dist/batched-migrations/batched-migration-job.js +25 -0
  6. package/dist/batched-migrations/batched-migration-job.js.map +1 -0
  7. package/dist/batched-migrations/batched-migration-job.sql +12 -0
  8. package/dist/batched-migrations/batched-migration-runner.d.ts +29 -0
  9. package/dist/batched-migrations/batched-migration-runner.js +136 -0
  10. package/dist/batched-migrations/batched-migration-runner.js.map +1 -0
  11. package/dist/batched-migrations/batched-migration-runner.sql +93 -0
  12. package/dist/batched-migrations/batched-migration-runner.test.js +185 -0
  13. package/dist/batched-migrations/batched-migration-runner.test.js.map +1 -0
  14. package/dist/batched-migrations/batched-migration.d.ts +79 -0
  15. package/dist/batched-migrations/batched-migration.js +73 -0
  16. package/dist/batched-migrations/batched-migration.js.map +1 -0
  17. package/dist/batched-migrations/batched-migration.sql +95 -0
  18. package/dist/batched-migrations/batched-migrations-runner.d.ts +63 -0
  19. package/dist/batched-migrations/batched-migrations-runner.js +272 -0
  20. package/dist/batched-migrations/batched-migrations-runner.js.map +1 -0
  21. package/dist/batched-migrations/batched-migrations-runner.sql +35 -0
  22. package/dist/batched-migrations/batched-migrations-runner.test.js +116 -0
  23. package/dist/batched-migrations/batched-migrations-runner.test.js.map +1 -0
  24. package/dist/batched-migrations/fixtures/20230406184103_successful_migration.d.ts +9 -0
  25. package/dist/batched-migrations/fixtures/20230406184103_successful_migration.js +14 -0
  26. package/dist/batched-migrations/fixtures/20230406184103_successful_migration.js.map +1 -0
  27. package/dist/batched-migrations/fixtures/20230407230446_no_rows_migration.d.ts +8 -0
  28. package/dist/batched-migrations/fixtures/20230407230446_no_rows_migration.js +16 -0
  29. package/dist/batched-migrations/fixtures/20230407230446_no_rows_migration.js.map +1 -0
  30. package/dist/batched-migrations/index.d.ts +3 -0
  31. package/dist/batched-migrations/index.js +18 -0
  32. package/dist/batched-migrations/index.js.map +1 -0
  33. package/dist/index.d.ts +3 -12
  34. package/dist/index.js +15 -192
  35. package/dist/index.js.map +1 -1
  36. package/dist/load-migrations.d.ts +8 -0
  37. package/dist/load-migrations.js +60 -0
  38. package/dist/load-migrations.js.map +1 -0
  39. package/dist/load-migrations.test.d.ts +1 -0
  40. package/dist/{index.test.js → load-migrations.test.js} +12 -65
  41. package/dist/load-migrations.test.js.map +1 -0
  42. package/dist/migrations/fixtures/20230407210430_insert_user.d.ts +1 -0
  43. package/dist/migrations/fixtures/20230407210430_insert_user.js.map +1 -0
  44. package/dist/migrations/index.d.ts +1 -0
  45. package/dist/migrations/index.js +6 -0
  46. package/dist/migrations/index.js.map +1 -0
  47. package/dist/migrations/migrations.d.ts +6 -0
  48. package/dist/migrations/migrations.js +158 -0
  49. package/dist/migrations/migrations.js.map +1 -0
  50. package/dist/migrations/migrations.test.d.ts +1 -0
  51. package/dist/migrations/migrations.test.js +78 -0
  52. package/dist/migrations/migrations.test.js.map +1 -0
  53. package/package.json +15 -12
  54. package/schema-migrations/20230303193423_batched_migrations__create.sql +49 -0
  55. package/src/batched-migrations/batched-migration-job.sql +12 -0
  56. package/src/batched-migrations/batched-migration-job.ts +34 -0
  57. package/src/batched-migrations/batched-migration-runner.sql +93 -0
  58. package/src/batched-migrations/batched-migration-runner.test.ts +208 -0
  59. package/src/batched-migrations/batched-migration-runner.ts +215 -0
  60. package/src/batched-migrations/batched-migration.sql +95 -0
  61. package/src/batched-migrations/batched-migration.ts +129 -0
  62. package/src/batched-migrations/batched-migrations-runner.sql +35 -0
  63. package/src/batched-migrations/batched-migrations-runner.test.ts +111 -0
  64. package/src/batched-migrations/batched-migrations-runner.ts +327 -0
  65. package/src/batched-migrations/fixtures/20230406184103_successful_migration.ts +13 -0
  66. package/src/batched-migrations/fixtures/20230406184107_failing_migration.js +16 -0
  67. package/src/batched-migrations/fixtures/20230407230446_no_rows_migration.ts +15 -0
  68. package/src/batched-migrations/index.ts +21 -0
  69. package/src/index.ts +20 -201
  70. package/src/{index.test.ts → load-migrations.test.ts} +8 -73
  71. package/src/load-migrations.ts +76 -0
  72. package/src/migrations/index.ts +1 -0
  73. package/src/migrations/migrations.test.ts +80 -0
  74. package/src/migrations/migrations.ts +149 -0
  75. package/tsconfig.json +1 -1
  76. package/dist/fixtures/20230407210430_insert_user.js.map +0 -1
  77. package/dist/index.test.js.map +0 -1
  78. /package/dist/{fixtures/20230407210430_insert_user.d.ts → batched-migrations/batched-migration-runner.test.d.ts} +0 -0
  79. /package/dist/{index.test.d.ts → batched-migrations/batched-migrations-runner.test.d.ts} +0 -0
  80. /package/dist/{fixtures → migrations/fixtures}/20230407210409_create_users.sql +0 -0
  81. /package/dist/{fixtures → migrations/fixtures}/20230407210430_insert_user.js +0 -0
  82. /package/dist/{index.sql → migrations/migrations.sql} +0 -0
  83. /package/src/{fixtures → migrations/fixtures}/20230407210409_create_users.sql +0 -0
  84. /package/src/{fixtures → migrations/fixtures}/20230407210430_insert_user.ts +0 -0
  85. /package/src/{index.sql → migrations/migrations.sql} +0 -0
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const chai_1 = require("chai");
27
+ const postgres_1 = require("@prairielearn/postgres");
28
+ const namedLocks = __importStar(require("@prairielearn/named-locks"));
29
+ const error = __importStar(require("@prairielearn/error"));
30
+ const batched_migration_1 = require("./batched-migration");
31
+ const batched_migration_job_1 = require("./batched-migration-job");
32
+ const batched_migration_runner_1 = require("./batched-migration-runner");
33
+ const index_1 = require("../index");
34
+ const postgresTestUtils = (0, postgres_1.makePostgresTestUtils)({
35
+ database: 'prairielearn_migrations',
36
+ });
37
+ function makeTestBatchMigration() {
38
+ let executionCount = 0;
39
+ let failingIds = [];
40
+ return (0, batched_migration_1.makeBatchedMigration)({
41
+ async getParameters() {
42
+ return {
43
+ min: 1n,
44
+ max: 10000n,
45
+ batchSize: 1000,
46
+ };
47
+ },
48
+ async execute(start, end) {
49
+ executionCount += 1;
50
+ const shouldFail = failingIds.some((id) => id >= start && id <= end);
51
+ if (shouldFail) {
52
+ // Throw an error with some data to make sure it gets persisted. We
53
+ // specifically use BigInt values here to make sure that they are
54
+ // correctly serialized to strings.
55
+ throw error.makeWithData('Execution failure', { start, end });
56
+ }
57
+ },
58
+ setFailingIds(ids) {
59
+ failingIds = ids;
60
+ },
61
+ get executionCount() {
62
+ return executionCount;
63
+ },
64
+ });
65
+ }
66
+ async function getBatchedMigration(migrationId) {
67
+ return (0, postgres_1.queryValidatedOneRow)('SELECT * FROM batched_migrations WHERE id = $id;', { id: migrationId }, batched_migration_1.BatchedMigrationRowSchema);
68
+ }
69
+ async function getBatchedMigrationJobs(migrationId) {
70
+ return (0, postgres_1.queryValidatedRows)('SELECT * FROM batched_migration_jobs WHERE batched_migration_id = $batched_migration_id ORDER BY id ASC;', { batched_migration_id: migrationId }, batched_migration_job_1.BatchedMigrationJobRowSchema);
71
+ }
72
+ async function resetFailedBatchedMigrationJobs(migrationId) {
73
+ await (0, postgres_1.queryAsync)("UPDATE batched_migration_jobs SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE batched_migration_id = $batched_migration_id AND status = 'failed'", {
74
+ batched_migration_id: migrationId,
75
+ });
76
+ }
77
+ async function insertTestBatchedMigration() {
78
+ const migrationImplementation = makeTestBatchMigration();
79
+ const parameters = await migrationImplementation.getParameters();
80
+ const migration = await (0, batched_migration_1.insertBatchedMigration)({
81
+ project: 'test',
82
+ filename: '20230406184103_test_batch_migration.js',
83
+ timestamp: '20230406184103',
84
+ batch_size: parameters.batchSize,
85
+ min_value: parameters.min,
86
+ max_value: parameters.max,
87
+ status: 'running',
88
+ });
89
+ if (!migration)
90
+ throw new Error('Failed to insert batched migration');
91
+ return migration;
92
+ }
93
+ describe('BatchedMigrationExecutor', () => {
94
+ before(async () => {
95
+ await postgresTestUtils.createDatabase();
96
+ await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {
97
+ throw err;
98
+ });
99
+ await (0, index_1.init)([index_1.SCHEMA_MIGRATIONS_PATH], 'prairielearn_migrations');
100
+ });
101
+ beforeEach(async () => {
102
+ await postgresTestUtils.resetDatabase();
103
+ });
104
+ after(async () => {
105
+ await namedLocks.close();
106
+ await postgresTestUtils.dropDatabase();
107
+ });
108
+ it('runs one iteration of a batched migration', async () => {
109
+ const migration = await insertTestBatchedMigration();
110
+ const migrationImplementation = makeTestBatchMigration();
111
+ const executor = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
112
+ await executor.run({ iterations: 1 });
113
+ const jobs = await getBatchedMigrationJobs(migration.id);
114
+ chai_1.assert.lengthOf(jobs, 1);
115
+ const finalMigration = await getBatchedMigration(migration.id);
116
+ chai_1.assert.equal(finalMigration.status, 'running');
117
+ chai_1.assert.equal(migrationImplementation.executionCount, 1);
118
+ });
119
+ it('runs an entire batched migration', async () => {
120
+ const migration = await insertTestBatchedMigration();
121
+ const migrationImplementation = makeTestBatchMigration();
122
+ const runner = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
123
+ await runner.run();
124
+ const jobs = await getBatchedMigrationJobs(migration.id);
125
+ chai_1.assert.lengthOf(jobs, 10);
126
+ chai_1.assert.equal(jobs[0].min_value, 1n);
127
+ chai_1.assert.equal(jobs[0].max_value, 1000n);
128
+ chai_1.assert.equal(jobs.at(-1)?.min_value, 9001n);
129
+ chai_1.assert.equal(jobs.at(-1)?.max_value, 10000n);
130
+ chai_1.assert.isTrue(jobs.every((job) => job.started_at !== null));
131
+ chai_1.assert.isTrue(jobs.every((job) => job.finished_at !== null));
132
+ chai_1.assert.isTrue(jobs.every((job) => job.status === 'succeeded'));
133
+ chai_1.assert.isTrue(jobs.every((job) => job.attempts === 1));
134
+ const finalMigration = await getBatchedMigration(migration.id);
135
+ chai_1.assert.equal(finalMigration.status, 'succeeded');
136
+ });
137
+ it('handles failing execution', async () => {
138
+ let migration = await insertTestBatchedMigration();
139
+ const migrationImplementation = makeTestBatchMigration();
140
+ migrationImplementation.setFailingIds([1n, 5010n]);
141
+ const runner = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
142
+ await runner.run();
143
+ const jobs = await getBatchedMigrationJobs(migration.id);
144
+ const failedJobs = jobs.filter((job) => job.status === 'failed');
145
+ const successfulJobs = jobs.filter((job) => job.status === 'succeeded');
146
+ chai_1.assert.lengthOf(jobs, 10);
147
+ chai_1.assert.lengthOf(failedJobs, 2);
148
+ chai_1.assert.lengthOf(successfulJobs, 8);
149
+ chai_1.assert.equal(migrationImplementation.executionCount, 10);
150
+ chai_1.assert.isTrue(jobs.every((job) => job.attempts === 1));
151
+ failedJobs.forEach((job) => {
152
+ const jobData = job.data;
153
+ chai_1.assert.isObject(jobData);
154
+ chai_1.assert.isObject(jobData.error);
155
+ chai_1.assert.hasAllKeys(jobData.error, ['name', 'message', 'stack', 'data']);
156
+ chai_1.assert.equal(jobData.error.name, 'Error');
157
+ chai_1.assert.equal(jobData.error.message, 'Execution failure');
158
+ chai_1.assert.equal(jobData.error.data.start, job.min_value.toString());
159
+ chai_1.assert.equal(jobData.error.data.end, job.max_value.toString());
160
+ });
161
+ const failedMigration = await getBatchedMigration(migration.id);
162
+ chai_1.assert.equal(failedMigration.status, 'failed');
163
+ // Retry the failed jobs; ensure they succeed this time.
164
+ await resetFailedBatchedMigrationJobs(migration.id);
165
+ migration = await (0, batched_migration_1.updateBatchedMigrationStatus)(migration.id, 'running');
166
+ migrationImplementation.setFailingIds([]);
167
+ const retryRunner = new batched_migration_runner_1.BatchedMigrationRunner(migration, migrationImplementation);
168
+ await retryRunner.run();
169
+ const finalJobs = await getBatchedMigrationJobs(migration.id);
170
+ const finalFailedJobs = finalJobs.filter((job) => job.status === 'failed');
171
+ const finalSuccessfulJobs = finalJobs.filter((job) => job.status === 'succeeded');
172
+ const retriedJobs = finalJobs.filter((job) => job.attempts === 2);
173
+ chai_1.assert.lengthOf(finalJobs, 10);
174
+ chai_1.assert.lengthOf(finalFailedJobs, 0);
175
+ chai_1.assert.lengthOf(finalSuccessfulJobs, 10);
176
+ chai_1.assert.lengthOf(retriedJobs, 2);
177
+ chai_1.assert.isTrue(finalJobs.every((job) => job.data === null));
178
+ migration = await getBatchedMigration(migration.id);
179
+ chai_1.assert.equal(migration.status, 'succeeded');
180
+ // The runner should have run only the previously failed jobs, which
181
+ // works out to 2 additional execution.
182
+ chai_1.assert.equal(migrationImplementation.executionCount, 12);
183
+ });
184
+ });
185
+ //# sourceMappingURL=batched-migration-runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batched-migration-runner.test.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migration-runner.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import { z } from 'zod';
2
+ export declare const BatchedMigrationStatusSchema: z.ZodEnum<["pending", "paused", "running", "finalizing", "failed", "succeeded"]>;
3
+ export type BatchedMigrationStatus = z.infer<typeof BatchedMigrationStatusSchema>;
4
+ export declare const BatchedMigrationRowSchema: z.ZodObject<{
5
+ id: z.ZodString;
6
+ project: z.ZodString;
7
+ filename: z.ZodString;
8
+ timestamp: z.ZodString;
9
+ batch_size: z.ZodNumber;
10
+ min_value: z.ZodBigInt;
11
+ max_value: z.ZodBigInt;
12
+ status: z.ZodEnum<["pending", "paused", "running", "finalizing", "failed", "succeeded"]>;
13
+ created_at: z.ZodDate;
14
+ updated_at: z.ZodDate;
15
+ started_at: z.ZodNullable<z.ZodDate>;
16
+ }, "strip", z.ZodTypeAny, {
17
+ filename: string;
18
+ timestamp: string;
19
+ project: string;
20
+ status: "pending" | "paused" | "running" | "finalizing" | "failed" | "succeeded";
21
+ id: string;
22
+ batch_size: number;
23
+ min_value: bigint;
24
+ max_value: bigint;
25
+ created_at: Date;
26
+ updated_at: Date;
27
+ started_at: Date | null;
28
+ }, {
29
+ filename: string;
30
+ timestamp: string;
31
+ project: string;
32
+ status: "pending" | "paused" | "running" | "finalizing" | "failed" | "succeeded";
33
+ id: string;
34
+ batch_size: number;
35
+ min_value: bigint;
36
+ max_value: bigint;
37
+ created_at: Date;
38
+ updated_at: Date;
39
+ started_at: Date | null;
40
+ }>;
41
+ export type BatchedMigrationRow = z.infer<typeof BatchedMigrationRowSchema>;
42
+ export interface BatchedMigrationParameters {
43
+ min?: bigint | null;
44
+ max: bigint | null;
45
+ batchSize?: number;
46
+ }
47
+ export interface BatchedMigrationImplementation {
48
+ getParameters(): Promise<BatchedMigrationParameters>;
49
+ execute(start: bigint, end: bigint): Promise<void>;
50
+ }
51
+ /**
52
+ * Identity function that helps to write correct batched migrations.
53
+ */
54
+ export declare function makeBatchedMigration<T extends BatchedMigrationImplementation>(fns: T): T;
55
+ export declare function validateBatchedMigrationImplementation(fns: BatchedMigrationImplementation): asserts fns is BatchedMigrationImplementation;
56
+ type NewBatchedMigration = Pick<BatchedMigrationRow, 'project' | 'filename' | 'timestamp' | 'batch_size' | 'min_value' | 'max_value' | 'status'>;
57
+ /**
58
+ * Inserts a new batched migration. If one already exists for the given
59
+ * project/timestamp pair, returns null, otherwise returns the inserted row.
60
+ */
61
+ export declare function insertBatchedMigration(migration: NewBatchedMigration): Promise<BatchedMigrationRow | null>;
62
+ export declare function selectAllBatchedMigrations(project: string): Promise<{
63
+ filename: string;
64
+ timestamp: string;
65
+ project: string;
66
+ status: "pending" | "paused" | "running" | "finalizing" | "failed" | "succeeded";
67
+ id: string;
68
+ batch_size: number;
69
+ min_value: bigint;
70
+ max_value: bigint;
71
+ created_at: Date;
72
+ updated_at: Date;
73
+ started_at: Date | null;
74
+ }[]>;
75
+ export declare function selectBatchedMigration(project: string, id: string): Promise<BatchedMigrationRow>;
76
+ export declare function selectBatchedMigrationForTimestamp(project: string, timestamp: string): Promise<BatchedMigrationRow>;
77
+ export declare function updateBatchedMigrationStatus(id: string, status: BatchedMigrationStatus): Promise<BatchedMigrationRow>;
78
+ export declare function retryFailedBatchedMigrationJobs(project: string, id: string): Promise<void>;
79
+ export {};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.retryFailedBatchedMigrationJobs = exports.updateBatchedMigrationStatus = exports.selectBatchedMigrationForTimestamp = exports.selectBatchedMigration = exports.selectAllBatchedMigrations = exports.insertBatchedMigration = exports.validateBatchedMigrationImplementation = exports.makeBatchedMigration = exports.BatchedMigrationRowSchema = exports.BatchedMigrationStatusSchema = void 0;
4
+ const postgres_1 = require("@prairielearn/postgres");
5
+ const zod_1 = require("zod");
6
+ const sql = (0, postgres_1.loadSqlEquiv)(__filename);
7
+ exports.BatchedMigrationStatusSchema = zod_1.z.enum([
8
+ 'pending',
9
+ 'paused',
10
+ 'running',
11
+ 'finalizing',
12
+ 'failed',
13
+ 'succeeded',
14
+ ]);
15
+ exports.BatchedMigrationRowSchema = zod_1.z.object({
16
+ id: zod_1.z.string(),
17
+ project: zod_1.z.string(),
18
+ filename: zod_1.z.string(),
19
+ timestamp: zod_1.z.string(),
20
+ batch_size: zod_1.z.number(),
21
+ min_value: zod_1.z.bigint({ coerce: true }),
22
+ max_value: zod_1.z.bigint({ coerce: true }),
23
+ status: exports.BatchedMigrationStatusSchema,
24
+ created_at: zod_1.z.date(),
25
+ updated_at: zod_1.z.date(),
26
+ started_at: zod_1.z.date().nullable(),
27
+ });
28
+ /**
29
+ * Identity function that helps to write correct batched migrations.
30
+ */
31
+ function makeBatchedMigration(fns) {
32
+ validateBatchedMigrationImplementation(fns);
33
+ return fns;
34
+ }
35
+ exports.makeBatchedMigration = makeBatchedMigration;
36
+ function validateBatchedMigrationImplementation(fns) {
37
+ if (typeof fns.getParameters !== 'function') {
38
+ throw new Error('getParameters() must be a function');
39
+ }
40
+ if (typeof fns.execute !== 'function') {
41
+ throw new Error('execute() must be a function');
42
+ }
43
+ }
44
+ exports.validateBatchedMigrationImplementation = validateBatchedMigrationImplementation;
45
+ /**
46
+ * Inserts a new batched migration. If one already exists for the given
47
+ * project/timestamp pair, returns null, otherwise returns the inserted row.
48
+ */
49
+ async function insertBatchedMigration(migration) {
50
+ return (0, postgres_1.queryValidatedZeroOrOneRow)(sql.insert_batched_migration, migration, exports.BatchedMigrationRowSchema);
51
+ }
52
+ exports.insertBatchedMigration = insertBatchedMigration;
53
+ async function selectAllBatchedMigrations(project) {
54
+ return (0, postgres_1.queryValidatedRows)(sql.select_all_batched_migrations, { project }, exports.BatchedMigrationRowSchema);
55
+ }
56
+ exports.selectAllBatchedMigrations = selectAllBatchedMigrations;
57
+ async function selectBatchedMigration(project, id) {
58
+ return (0, postgres_1.queryValidatedOneRow)(sql.select_batched_migration, { project, id }, exports.BatchedMigrationRowSchema);
59
+ }
60
+ exports.selectBatchedMigration = selectBatchedMigration;
61
+ async function selectBatchedMigrationForTimestamp(project, timestamp) {
62
+ return (0, postgres_1.queryValidatedOneRow)(sql.select_batched_migration_for_timestamp, { project, timestamp }, exports.BatchedMigrationRowSchema);
63
+ }
64
+ exports.selectBatchedMigrationForTimestamp = selectBatchedMigrationForTimestamp;
65
+ async function updateBatchedMigrationStatus(id, status) {
66
+ return (0, postgres_1.queryValidatedOneRow)(sql.update_batched_migration_status, { id, status }, exports.BatchedMigrationRowSchema);
67
+ }
68
+ exports.updateBatchedMigrationStatus = updateBatchedMigrationStatus;
69
+ async function retryFailedBatchedMigrationJobs(project, id) {
70
+ await (0, postgres_1.queryAsync)(sql.retry_failed_jobs, { project, id });
71
+ }
72
+ exports.retryFailedBatchedMigrationJobs = retryFailedBatchedMigrationJobs;
73
+ //# sourceMappingURL=batched-migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batched-migration.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migration.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ -- BLOCK insert_batched_migration
2
+ INSERT INTO
3
+ batched_migrations (
4
+ project,
5
+ filename,
6
+ timestamp,
7
+ batch_size,
8
+ min_value,
9
+ max_value,
10
+ status,
11
+ started_at
12
+ )
13
+ VALUES
14
+ (
15
+ $project,
16
+ $filename,
17
+ $timestamp,
18
+ $batch_size,
19
+ $min_value,
20
+ $max_value,
21
+ $status,
22
+ -- If the migration is marked as already having succeeded, set `started_at`
23
+ -- since the migration did technically start.
24
+ CASE
25
+ WHEN $status::enum_batched_migration_status = 'succeeded' THEN CURRENT_TIMESTAMP
26
+ ELSE NULL
27
+ END
28
+ )
29
+ ON CONFLICT DO NOTHING
30
+ RETURNING
31
+ *;
32
+
33
+ -- BLOCK select_all_batched_migrations
34
+ SELECT
35
+ *
36
+ FROM
37
+ batched_migrations
38
+ WHERE
39
+ project = $project
40
+ ORDER BY
41
+ id ASC;
42
+
43
+ -- BLOCK select_batched_migration
44
+ SELECT
45
+ *
46
+ FROM
47
+ batched_migrations
48
+ WHERE
49
+ project = $project
50
+ AND id = $id;
51
+
52
+ -- BLOCK select_batched_migration_for_timestamp
53
+ SELECT
54
+ *
55
+ FROM
56
+ batched_migrations
57
+ WHERE
58
+ project = $project
59
+ AND timestamp = $timestamp;
60
+
61
+ -- BLOCK update_batched_migration_status
62
+ UPDATE batched_migrations
63
+ SET
64
+ status = $status,
65
+ updated_at = CURRENT_TIMESTAMP
66
+ WHERE
67
+ id = $id
68
+ RETURNING
69
+ *;
70
+
71
+ -- BLOCK retry_failed_jobs
72
+ WITH
73
+ updated_batched_migration AS (
74
+ UPDATE batched_migrations
75
+ SET
76
+ status = 'running',
77
+ started_at = CURRENT_TIMESTAMP,
78
+ updated_at = CURRENT_TIMESTAMP
79
+ WHERE
80
+ project = $project
81
+ AND id = $id
82
+ RETURNING
83
+ *
84
+ )
85
+ UPDATE batched_migration_jobs
86
+ SET
87
+ status = 'pending',
88
+ started_at = NULL,
89
+ finished_at = NULL,
90
+ updated_at = CURRENT_TIMESTAMP
91
+ FROM
92
+ updated_batched_migration
93
+ WHERE
94
+ batched_migration_id = updated_batched_migration.id
95
+ AND batched_migration_jobs.status = 'failed';
@@ -0,0 +1,63 @@
1
+ /// <reference types="node" />
2
+ import EventEmitter from 'node:events';
3
+ interface BatchedMigrationRunnerOptions {
4
+ project: string;
5
+ directories: string[];
6
+ }
7
+ interface BatchedMigrationStartOptions {
8
+ workDurationMs?: number;
9
+ sleepDurationMs?: number;
10
+ }
11
+ interface BatchedMigrationFinalizeOptions {
12
+ logProgress?: boolean;
13
+ }
14
+ export declare class BatchedMigrationsRunner extends EventEmitter {
15
+ private readonly options;
16
+ private readonly lockName;
17
+ private running;
18
+ private migrationFiles;
19
+ private abortController;
20
+ constructor(options: BatchedMigrationRunnerOptions);
21
+ private lockNameForTimestamp;
22
+ private getMigrationFiles;
23
+ private getMigrationForIdentifier;
24
+ /**
25
+ * Loads the implementation for the migration with the given identifier. The identifier
26
+ * must start with a 14-character timestamp. It may optionally be followed by
27
+ * an underscore with additional characters, which are ignored. These should
28
+ * typically be used to provide a human-readable name for the migration.
29
+ */
30
+ private loadMigrationImplementation;
31
+ enqueueBatchedMigration(identifier: string): Promise<void>;
32
+ finalizeBatchedMigration(identifier: string, options?: BatchedMigrationFinalizeOptions): Promise<void>;
33
+ start(options?: BatchedMigrationStartOptions): void;
34
+ loop({ workDurationMs, sleepDurationMs }: BatchedMigrationStartOptions): Promise<void>;
35
+ private getOrStartMigration;
36
+ maybePerformWork(durationMs: number): Promise<boolean>;
37
+ stop(): Promise<void>;
38
+ }
39
+ export declare function initBatchedMigrations(options: BatchedMigrationRunnerOptions): BatchedMigrationsRunner;
40
+ export declare function startBatchedMigrations(options?: BatchedMigrationStartOptions): BatchedMigrationsRunner;
41
+ export declare function stopBatchedMigrations(): Promise<void>;
42
+ /**
43
+ * Given a batched migration identifier like `20230406184103_migration`,
44
+ * enqueues it for execution by creating a row in the `batched_migrations`
45
+ * table.
46
+ *
47
+ * Despite taking a full identifier, only the timestamp is used to uniquely
48
+ * identify the batched migration. The remaining part is just used to make
49
+ * calls more human-readable.
50
+ *
51
+ * @param identifier The identifier of the batched migration to enqueue.
52
+ */
53
+ export declare function enqueueBatchedMigration(identifier: string): Promise<void>;
54
+ /**
55
+ * Given a batched migration identifier like `20230406184103_migration`,
56
+ * synchronously runs it to completion. An error will be thrown if the final
57
+ * status of the migration is not `succeeded`.
58
+ *
59
+ * @param identifier The identifier of the batched migration to finalize.
60
+ * @param options Options for finalizing the batched migration.
61
+ */
62
+ export declare function finalizeBatchedMigration(identifier: string, options?: BatchedMigrationFinalizeOptions): Promise<void>;
63
+ export {};