@prairielearn/migrations 4.0.2 → 4.0.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @prairielearn/migrations
2
2
 
3
+ ## 4.0.4
4
+
5
+ ### Patch Changes
6
+
7
+ - 70a8029: Upgrade all JavaScript dependencies
8
+ - Updated dependencies [70a8029]
9
+ - @prairielearn/named-locks@3.0.27
10
+ - @prairielearn/postgres@4.5.1
11
+ - @prairielearn/logger@2.0.24
12
+ - @prairielearn/error@2.0.23
13
+
14
+ ## 4.0.3
15
+
16
+ ### Patch Changes
17
+
18
+ - 0425922: Upgrade all JavaScript dependencies
19
+ - Updated dependencies [0425922]
20
+ - @prairielearn/named-locks@3.0.26
21
+ - @prairielearn/postgres@4.4.3
22
+ - @prairielearn/logger@2.0.23
23
+ - @prairielearn/error@2.0.22
24
+
3
25
  ## 4.0.2
4
26
 
5
27
  ### Patch Changes
@@ -65,8 +65,8 @@ async function insertTestBatchedMigration() {
65
65
  }
66
66
  describe('BatchedMigrationExecutor', () => {
67
67
  beforeAll(async () => {
68
- await postgresTestUtils.createDatabase();
69
- await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {
68
+ const poolConfig = await postgresTestUtils.createDatabase();
69
+ await namedLocks.init(poolConfig, (err) => {
70
70
  throw err;
71
71
  });
72
72
  await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });
@@ -1 +1 @@
1
- {"version":3,"file":"batched-migration-runner.test.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migration-runner.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE/E,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,UAAU,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE7F,OAAO,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAEhC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC;IAC9C,QAAQ,EAAE,yBAAyB;CACpC,CAAC,CAAC;AAEH,SAAS,sBAAsB;IAC7B,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,UAAU,GAAa,EAAE,CAAC;IAE9B,OAAO,oBAAoB,CAAC;QAC1B,KAAK,CAAC,aAAa;YACjB,OAAO;gBACL,GAAG,EAAE,EAAE;gBACP,GAAG,EAAE,MAAM;gBACX,SAAS,EAAE,IAAI;aAChB,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,GAAW;YACtC,cAAc,IAAI,CAAC,CAAC;YACpB,MAAM,UAAU,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC;YACrE,IAAI,UAAU,EAAE,CAAC;gBACf,mEAAmE;gBACnE,iEAAiE;gBACjE,mCAAmC;gBACnC,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,mBAAmB,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;QACD,aAAa,CAAC,GAAa;YACzB,UAAU,GAAG,GAAG,CAAC;QACnB,CAAC;QACD,IAAI,cAAc;YAChB,OAAO,cAAc,CAAC;QACxB,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IACpD,OAAO,MAAM,QAAQ,CACnB,kDAAkD,EAClD,EAAE,EAAE,EAAE,WAAW,EAAE,EACnB,yBAAyB,CAC1B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAC,WAAmB;IACxD,OAAO,MAAM,SAAS,CACpB,0GAA0G,EAC1G,EAAE,oBAAoB,EAAE,WAAW,EAAE,EACrC,4BAA4B,CAC7B,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,+BAA+B,CAAC,WAAmB;IAChE,MAAM,OAAO,CACX,+JAA+J,EAC/J,EAAE,oBAAoB,EAAE,WAAW,EAAE,CACtC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,0BAA0B;IACvC,MAAM,uBAAuB,GAAG,sBAAsB,EAAE,CAAC;IACzD,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,aAAa,EAAE,CAAC;IACjE,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAAC;QAC7C,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,wCAAwC;QAClD,SAAS,EAAE,gBAAgB;QAC3B,UAAU,EAAE,UAAU,CAAC,SAAS;QAChC,SAAS,EAAE,UAAU,CAAC,GAAG;QACzB,SAAS,EAAE,UAAU,CAAC,GAAG;QACzB,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;IACH,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,iBAAiB,CAAC,cAAc,EAAE,CAAC;QACzC,MAAM,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,aAAa,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE;YAC/D,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,sBAAsB,CAAC,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,iBAAiB,CAAC,aAAa,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;QACzB,MAAM,iBAAiB,CAAC,YAAY,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,SAAS,GAAG,MAAM,0BAA0B,EAAE,CAAC;QAErD,MAAM,uBAAuB,GAAG,sBAAsB,EAAE,CAAC;QACzD,MAAM,QAAQ,GAAG,IAAI,sBAAsB,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QAChF,MAAM,QAAQ,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QAEtC,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAEzB,MAAM,cAAc,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAE/C,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,SAAS,GAAG,MAAM,0BAA0B,EAAE,CAAC;QAErD,MAAM,uBAAuB,GAAG,sBAAsB,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,IAAI,sBAAsB,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QAC9E,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;QAEvD,MAAM,cAAc,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QACzC,IAAI,SAAS,GAAG,MAAM,0BAA0B,EAAE,CAAC;QAEnD,MAAM,uBAAuB,GAAG,sBAAsB,EAAE,CAAC;QACzD,uBAAuB,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,sBAAsB,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QAC9E,MAAM,MAAM,CAAC,GAAG,EAAE,CAAC;QAEnB,MAAM,IAAI,GAAG,MAAM,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QACjE,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;QACxE,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC1B,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;QACvD,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,OAAO,GAAG,GAAG,CAAC,IAAW,CAAC;YAChC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACzB,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC/B,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;YACjF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;YACzD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;YACjE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE/C,wDAAwD;QACxD,MAAM,+BAA+B,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACpD,SAAS,GAAG,MAAM,4BAA4B,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAExE,uBAAuB,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,IAAI,sBAAsB,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QACnF,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC;QAExB,MAAM,SAAS,GAAG,MAAM,uBAAuB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC9D,MAAM,eAAe,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QAC3E,MAAM,mBAAmB,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC;QAClF,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC/B,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;QACpC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC;QAE3D,SAAS,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QAE5C,oEAAoE;QACpE,uCAAuC;QACvC,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { afterAll, assert, beforeAll, beforeEach, describe, it } from 'vitest';\n\nimport * as error from '@prairielearn/error';\nimport * as namedLocks from '@prairielearn/named-locks';\nimport { execute, makePostgresTestUtils, queryRow, queryRows } from '@prairielearn/postgres';\n\nimport { SCHEMA_MIGRATIONS_PATH, init } from '../index.js';\n\nimport { BatchedMigrationJobRowSchema } from './batched-migration-job.js';\nimport { BatchedMigrationRunner } from './batched-migration-runner.js';\nimport {\n BatchedMigrationRowSchema,\n insertBatchedMigration,\n makeBatchedMigration,\n updateBatchedMigrationStatus,\n} from './batched-migration.js';\n\nconst postgresTestUtils = makePostgresTestUtils({\n database: 'prairielearn_migrations',\n});\n\nfunction makeTestBatchMigration() {\n let executionCount = 0;\n let failingIds: bigint[] = [];\n\n return makeBatchedMigration({\n async getParameters() {\n return {\n min: 1n,\n max: 10000n,\n batchSize: 1000,\n };\n },\n async execute(start: bigint, end: bigint) {\n executionCount += 1;\n const shouldFail = failingIds.some((id) => id >= start && id <= end);\n if (shouldFail) {\n // Throw an error with some data to make sure it gets persisted. We\n // specifically use BigInt values here to make sure that they are\n // correctly serialized to strings.\n throw new error.AugmentedError('Execution failure', { data: { start, end } });\n }\n },\n setFailingIds(ids: bigint[]) {\n failingIds = ids;\n },\n get executionCount() {\n return executionCount;\n },\n });\n}\n\nasync function getBatchedMigration(migrationId: string) {\n return await queryRow(\n 'SELECT * FROM batched_migrations WHERE id = $id;',\n { id: migrationId },\n BatchedMigrationRowSchema,\n );\n}\n\nasync function getBatchedMigrationJobs(migrationId: string) {\n return await queryRows(\n 'SELECT * FROM batched_migration_jobs WHERE batched_migration_id = $batched_migration_id ORDER BY id ASC;',\n { batched_migration_id: migrationId },\n BatchedMigrationJobRowSchema,\n );\n}\n\nasync function resetFailedBatchedMigrationJobs(migrationId: string) {\n await execute(\n \"UPDATE batched_migration_jobs SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE batched_migration_id = $batched_migration_id AND status = 'failed'\",\n { batched_migration_id: migrationId },\n );\n}\n\nasync function insertTestBatchedMigration() {\n const migrationImplementation = makeTestBatchMigration();\n const parameters = await migrationImplementation.getParameters();\n const migration = await insertBatchedMigration({\n project: 'test',\n filename: '20230406184103_test_batch_migration.js',\n timestamp: '20230406184103',\n batch_size: parameters.batchSize,\n min_value: parameters.min,\n max_value: parameters.max,\n status: 'running',\n });\n if (!migration) throw new Error('Failed to insert batched migration');\n return migration;\n}\n\ndescribe('BatchedMigrationExecutor', () => {\n beforeAll(async () => {\n await postgresTestUtils.createDatabase();\n await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {\n throw err;\n });\n await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });\n });\n\n beforeEach(async () => {\n await postgresTestUtils.resetDatabase();\n });\n\n afterAll(async () => {\n await namedLocks.close();\n await postgresTestUtils.dropDatabase();\n });\n\n it('runs one iteration of a batched migration', async () => {\n const migration = await insertTestBatchedMigration();\n\n const migrationImplementation = makeTestBatchMigration();\n const executor = new BatchedMigrationRunner(migration, migrationImplementation);\n await executor.run({ iterations: 1 });\n\n const jobs = await getBatchedMigrationJobs(migration.id);\n assert.lengthOf(jobs, 1);\n\n const finalMigration = await getBatchedMigration(migration.id);\n assert.equal(finalMigration.status, 'running');\n\n assert.equal(migrationImplementation.executionCount, 1);\n });\n\n it('runs an entire batched migration', async () => {\n const migration = await insertTestBatchedMigration();\n\n const migrationImplementation = makeTestBatchMigration();\n const runner = new BatchedMigrationRunner(migration, migrationImplementation);\n await runner.run();\n\n const jobs = await getBatchedMigrationJobs(migration.id);\n assert.lengthOf(jobs, 10);\n assert.equal(jobs[0].min_value, 1n);\n assert.equal(jobs[0].max_value, 1000n);\n assert.equal(jobs.at(-1)?.min_value, 9001n);\n assert.equal(jobs.at(-1)?.max_value, 10000n);\n assert.isTrue(jobs.every((job) => job.started_at !== null));\n assert.isTrue(jobs.every((job) => job.finished_at !== null));\n assert.isTrue(jobs.every((job) => job.status === 'succeeded'));\n assert.isTrue(jobs.every((job) => job.attempts === 1));\n\n const finalMigration = await getBatchedMigration(migration.id);\n assert.equal(finalMigration.status, 'succeeded');\n });\n\n it('handles failing execution', async () => {\n let migration = await insertTestBatchedMigration();\n\n const migrationImplementation = makeTestBatchMigration();\n migrationImplementation.setFailingIds([1n, 5010n]);\n const runner = new BatchedMigrationRunner(migration, migrationImplementation);\n await runner.run();\n\n const jobs = await getBatchedMigrationJobs(migration.id);\n const failedJobs = jobs.filter((job) => job.status === 'failed');\n const successfulJobs = jobs.filter((job) => job.status === 'succeeded');\n assert.lengthOf(jobs, 10);\n assert.lengthOf(failedJobs, 2);\n assert.lengthOf(successfulJobs, 8);\n assert.equal(migrationImplementation.executionCount, 10);\n assert.isTrue(jobs.every((job) => job.attempts === 1));\n failedJobs.forEach((job) => {\n const jobData = job.data as any;\n assert.isObject(jobData);\n assert.isObject(jobData.error);\n assert.hasAllKeys(jobData.error, ['name', 'message', 'stack', 'data', 'status']);\n assert.equal(jobData.error.name, 'Error');\n assert.equal(jobData.error.message, 'Execution failure');\n assert.equal(jobData.error.data.start, job.min_value.toString());\n assert.equal(jobData.error.data.end, job.max_value.toString());\n });\n\n const failedMigration = await getBatchedMigration(migration.id);\n assert.equal(failedMigration.status, 'failed');\n\n // Retry the failed jobs; ensure they succeed this time.\n await resetFailedBatchedMigrationJobs(migration.id);\n migration = await updateBatchedMigrationStatus(migration.id, 'running');\n\n migrationImplementation.setFailingIds([]);\n const retryRunner = new BatchedMigrationRunner(migration, migrationImplementation);\n await retryRunner.run();\n\n const finalJobs = await getBatchedMigrationJobs(migration.id);\n const finalFailedJobs = finalJobs.filter((job) => job.status === 'failed');\n const finalSuccessfulJobs = finalJobs.filter((job) => job.status === 'succeeded');\n const retriedJobs = finalJobs.filter((job) => job.attempts === 2);\n assert.lengthOf(finalJobs, 10);\n assert.lengthOf(finalFailedJobs, 0);\n assert.lengthOf(finalSuccessfulJobs, 10);\n assert.lengthOf(retriedJobs, 2);\n assert.isTrue(finalJobs.every((job) => job.data === null));\n\n migration = await getBatchedMigration(migration.id);\n assert.equal(migration.status, 'succeeded');\n\n // The runner should have run only the previously failed jobs, which\n // works out to 2 additional execution.\n assert.equal(migrationImplementation.executionCount, 12);\n });\n});\n"]}
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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","sourcesContent":["import { afterAll, assert, beforeAll, beforeEach, describe, it } from 'vitest';\n\nimport * as error from '@prairielearn/error';\nimport * as namedLocks from '@prairielearn/named-locks';\nimport { execute, makePostgresTestUtils, queryRow, queryRows } from '@prairielearn/postgres';\n\nimport { SCHEMA_MIGRATIONS_PATH, init } from '../index.js';\n\nimport { BatchedMigrationJobRowSchema } from './batched-migration-job.js';\nimport { BatchedMigrationRunner } from './batched-migration-runner.js';\nimport {\n BatchedMigrationRowSchema,\n insertBatchedMigration,\n makeBatchedMigration,\n updateBatchedMigrationStatus,\n} from './batched-migration.js';\n\nconst postgresTestUtils = makePostgresTestUtils({\n database: 'prairielearn_migrations',\n});\n\nfunction makeTestBatchMigration() {\n let executionCount = 0;\n let failingIds: bigint[] = [];\n\n return makeBatchedMigration({\n async getParameters() {\n return {\n min: 1n,\n max: 10000n,\n batchSize: 1000,\n };\n },\n async execute(start: bigint, end: bigint) {\n executionCount += 1;\n const shouldFail = failingIds.some((id) => id >= start && id <= end);\n if (shouldFail) {\n // Throw an error with some data to make sure it gets persisted. We\n // specifically use BigInt values here to make sure that they are\n // correctly serialized to strings.\n throw new error.AugmentedError('Execution failure', { data: { start, end } });\n }\n },\n setFailingIds(ids: bigint[]) {\n failingIds = ids;\n },\n get executionCount() {\n return executionCount;\n },\n });\n}\n\nasync function getBatchedMigration(migrationId: string) {\n return await queryRow(\n 'SELECT * FROM batched_migrations WHERE id = $id;',\n { id: migrationId },\n BatchedMigrationRowSchema,\n );\n}\n\nasync function getBatchedMigrationJobs(migrationId: string) {\n return await queryRows(\n 'SELECT * FROM batched_migration_jobs WHERE batched_migration_id = $batched_migration_id ORDER BY id ASC;',\n { batched_migration_id: migrationId },\n BatchedMigrationJobRowSchema,\n );\n}\n\nasync function resetFailedBatchedMigrationJobs(migrationId: string) {\n await execute(\n \"UPDATE batched_migration_jobs SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE batched_migration_id = $batched_migration_id AND status = 'failed'\",\n { batched_migration_id: migrationId },\n );\n}\n\nasync function insertTestBatchedMigration() {\n const migrationImplementation = makeTestBatchMigration();\n const parameters = await migrationImplementation.getParameters();\n const migration = await insertBatchedMigration({\n project: 'test',\n filename: '20230406184103_test_batch_migration.js',\n timestamp: '20230406184103',\n batch_size: parameters.batchSize,\n min_value: parameters.min,\n max_value: parameters.max,\n status: 'running',\n });\n if (!migration) throw new Error('Failed to insert batched migration');\n return migration;\n}\n\ndescribe('BatchedMigrationExecutor', () => {\n beforeAll(async () => {\n const poolConfig = await postgresTestUtils.createDatabase();\n await namedLocks.init(poolConfig, (err) => {\n throw err;\n });\n await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });\n });\n\n beforeEach(async () => {\n await postgresTestUtils.resetDatabase();\n });\n\n afterAll(async () => {\n await namedLocks.close();\n await postgresTestUtils.dropDatabase();\n });\n\n it('runs one iteration of a batched migration', async () => {\n const migration = await insertTestBatchedMigration();\n\n const migrationImplementation = makeTestBatchMigration();\n const executor = new BatchedMigrationRunner(migration, migrationImplementation);\n await executor.run({ iterations: 1 });\n\n const jobs = await getBatchedMigrationJobs(migration.id);\n assert.lengthOf(jobs, 1);\n\n const finalMigration = await getBatchedMigration(migration.id);\n assert.equal(finalMigration.status, 'running');\n\n assert.equal(migrationImplementation.executionCount, 1);\n });\n\n it('runs an entire batched migration', async () => {\n const migration = await insertTestBatchedMigration();\n\n const migrationImplementation = makeTestBatchMigration();\n const runner = new BatchedMigrationRunner(migration, migrationImplementation);\n await runner.run();\n\n const jobs = await getBatchedMigrationJobs(migration.id);\n assert.lengthOf(jobs, 10);\n assert.equal(jobs[0].min_value, 1n);\n assert.equal(jobs[0].max_value, 1000n);\n assert.equal(jobs.at(-1)?.min_value, 9001n);\n assert.equal(jobs.at(-1)?.max_value, 10000n);\n assert.isTrue(jobs.every((job) => job.started_at !== null));\n assert.isTrue(jobs.every((job) => job.finished_at !== null));\n assert.isTrue(jobs.every((job) => job.status === 'succeeded'));\n assert.isTrue(jobs.every((job) => job.attempts === 1));\n\n const finalMigration = await getBatchedMigration(migration.id);\n assert.equal(finalMigration.status, 'succeeded');\n });\n\n it('handles failing execution', async () => {\n let migration = await insertTestBatchedMigration();\n\n const migrationImplementation = makeTestBatchMigration();\n migrationImplementation.setFailingIds([1n, 5010n]);\n const runner = new BatchedMigrationRunner(migration, migrationImplementation);\n await runner.run();\n\n const jobs = await getBatchedMigrationJobs(migration.id);\n const failedJobs = jobs.filter((job) => job.status === 'failed');\n const successfulJobs = jobs.filter((job) => job.status === 'succeeded');\n assert.lengthOf(jobs, 10);\n assert.lengthOf(failedJobs, 2);\n assert.lengthOf(successfulJobs, 8);\n assert.equal(migrationImplementation.executionCount, 10);\n assert.isTrue(jobs.every((job) => job.attempts === 1));\n failedJobs.forEach((job) => {\n const jobData = job.data as any;\n assert.isObject(jobData);\n assert.isObject(jobData.error);\n assert.hasAllKeys(jobData.error, ['name', 'message', 'stack', 'data', 'status']);\n assert.equal(jobData.error.name, 'Error');\n assert.equal(jobData.error.message, 'Execution failure');\n assert.equal(jobData.error.data.start, job.min_value.toString());\n assert.equal(jobData.error.data.end, job.max_value.toString());\n });\n\n const failedMigration = await getBatchedMigration(migration.id);\n assert.equal(failedMigration.status, 'failed');\n\n // Retry the failed jobs; ensure they succeed this time.\n await resetFailedBatchedMigrationJobs(migration.id);\n migration = await updateBatchedMigrationStatus(migration.id, 'running');\n\n migrationImplementation.setFailingIds([]);\n const retryRunner = new BatchedMigrationRunner(migration, migrationImplementation);\n await retryRunner.run();\n\n const finalJobs = await getBatchedMigrationJobs(migration.id);\n const finalFailedJobs = finalJobs.filter((job) => job.status === 'failed');\n const finalSuccessfulJobs = finalJobs.filter((job) => job.status === 'succeeded');\n const retriedJobs = finalJobs.filter((job) => job.attempts === 2);\n assert.lengthOf(finalJobs, 10);\n assert.lengthOf(finalFailedJobs, 0);\n assert.lengthOf(finalSuccessfulJobs, 10);\n assert.lengthOf(retriedJobs, 2);\n assert.isTrue(finalJobs.every((job) => job.data === null));\n\n migration = await getBatchedMigration(migration.id);\n assert.equal(migration.status, 'succeeded');\n\n // The runner should have run only the previously failed jobs, which\n // works out to 2 additional execution.\n assert.equal(migrationImplementation.executionCount, 12);\n });\n});\n"]}
@@ -10,8 +10,8 @@ const postgresTestUtils = makePostgresTestUtils({
10
10
  });
11
11
  describe('BatchedMigrationsRunner', () => {
12
12
  beforeAll(async () => {
13
- await postgresTestUtils.createDatabase();
14
- await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {
13
+ const poolConfig = await postgresTestUtils.createDatabase();
14
+ await namedLocks.init(poolConfig, (err) => {
15
15
  throw err;
16
16
  });
17
17
  await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });
@@ -1 +1 @@
1
- {"version":3,"file":"batched-migrations-runner.test.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migrations-runner.test.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\n\nimport { afterAll, afterEach, assert, beforeAll, describe, expect, it } from 'vitest';\n\nimport * as namedLocks from '@prairielearn/named-locks';\nimport { makePostgresTestUtils } from '@prairielearn/postgres';\n\nimport { SCHEMA_MIGRATIONS_PATH, init } from '../index.js';\n\nimport { selectAllBatchedMigrations } from './batched-migration.js';\nimport { BatchedMigrationsRunner } from './batched-migrations-runner.js';\n\nconst postgresTestUtils = makePostgresTestUtils({\n database: 'prairielearn_migrations',\n});\n\ndescribe('BatchedMigrationsRunner', () => {\n beforeAll(async () => {\n await postgresTestUtils.createDatabase();\n await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {\n throw err;\n });\n await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });\n });\n\n afterEach(async () => {\n await postgresTestUtils.resetDatabase();\n });\n\n afterAll(async () => {\n await namedLocks.close();\n await postgresTestUtils.dropDatabase();\n });\n\n it('enqueues migrations', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.enqueueBatchedMigration('20230406184107_failing_migration');\n await runner.enqueueBatchedMigration('20230407230446_no_rows_migration');\n\n const migrations = await selectAllBatchedMigrations('test');\n\n assert.lengthOf(migrations, 3);\n assert.equal(migrations[0].timestamp, '20230406184103');\n assert.equal(migrations[0].filename, '20230406184103_successful_migration.ts');\n assert.equal(migrations[0].status, 'pending');\n assert.equal(migrations[1].timestamp, '20230406184107');\n assert.equal(migrations[1].filename, '20230406184107_failing_migration.ts');\n assert.equal(migrations[1].status, 'pending');\n assert.equal(migrations[2].timestamp, '20230407230446');\n assert.equal(migrations[2].filename, '20230407230446_no_rows_migration.ts');\n assert.equal(migrations[2].status, 'succeeded');\n });\n\n it('safely enqueues migrations multiple times', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n\n const migrations = await selectAllBatchedMigrations('test');\n\n assert.lengthOf(migrations, 1);\n });\n\n it('finalizes a successful migration', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.finalizeBatchedMigration('20230406184103_successful_migration', {\n logProgress: false,\n });\n\n const migrations = await selectAllBatchedMigrations('test');\n assert.lengthOf(migrations, 1);\n assert.equal(migrations[0].timestamp, '20230406184103');\n assert.equal(migrations[0].status, 'succeeded');\n });\n\n it('finalizes a failing migration', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184107_failing_migration');\n\n await expect(\n runner.finalizeBatchedMigration('20230406184107_failing_migration', {\n logProgress: false,\n }),\n ).rejects.toThrow(\"but it is 'failed'\");\n const migrations = await selectAllBatchedMigrations('test');\n assert.lengthOf(migrations, 1);\n assert.equal(migrations[0].timestamp, '20230406184107');\n assert.equal(migrations[0].status, 'failed');\n });\n});\n"]}
1
+ {"version":3,"file":"batched-migrations-runner.test.js","sourceRoot":"","sources":["../../src/batched-migrations/batched-migrations-runner.test.ts"],"names":[],"mappings":"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","sourcesContent":["import path from 'node:path';\n\nimport { afterAll, afterEach, assert, beforeAll, describe, expect, it } from 'vitest';\n\nimport * as namedLocks from '@prairielearn/named-locks';\nimport { makePostgresTestUtils } from '@prairielearn/postgres';\n\nimport { SCHEMA_MIGRATIONS_PATH, init } from '../index.js';\n\nimport { selectAllBatchedMigrations } from './batched-migration.js';\nimport { BatchedMigrationsRunner } from './batched-migrations-runner.js';\n\nconst postgresTestUtils = makePostgresTestUtils({\n database: 'prairielearn_migrations',\n});\n\ndescribe('BatchedMigrationsRunner', () => {\n beforeAll(async () => {\n const poolConfig = await postgresTestUtils.createDatabase();\n await namedLocks.init(poolConfig, (err) => {\n throw err;\n });\n await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });\n });\n\n afterEach(async () => {\n await postgresTestUtils.resetDatabase();\n });\n\n afterAll(async () => {\n await namedLocks.close();\n await postgresTestUtils.dropDatabase();\n });\n\n it('enqueues migrations', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.enqueueBatchedMigration('20230406184107_failing_migration');\n await runner.enqueueBatchedMigration('20230407230446_no_rows_migration');\n\n const migrations = await selectAllBatchedMigrations('test');\n\n assert.lengthOf(migrations, 3);\n assert.equal(migrations[0].timestamp, '20230406184103');\n assert.equal(migrations[0].filename, '20230406184103_successful_migration.ts');\n assert.equal(migrations[0].status, 'pending');\n assert.equal(migrations[1].timestamp, '20230406184107');\n assert.equal(migrations[1].filename, '20230406184107_failing_migration.ts');\n assert.equal(migrations[1].status, 'pending');\n assert.equal(migrations[2].timestamp, '20230407230446');\n assert.equal(migrations[2].filename, '20230407230446_no_rows_migration.ts');\n assert.equal(migrations[2].status, 'succeeded');\n });\n\n it('safely enqueues migrations multiple times', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n\n const migrations = await selectAllBatchedMigrations('test');\n\n assert.lengthOf(migrations, 1);\n });\n\n it('finalizes a successful migration', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184103_successful_migration');\n await runner.finalizeBatchedMigration('20230406184103_successful_migration', {\n logProgress: false,\n });\n\n const migrations = await selectAllBatchedMigrations('test');\n assert.lengthOf(migrations, 1);\n assert.equal(migrations[0].timestamp, '20230406184103');\n assert.equal(migrations[0].status, 'succeeded');\n });\n\n it('finalizes a failing migration', async () => {\n const runner = new BatchedMigrationsRunner({\n project: 'test',\n directories: [path.join(import.meta.dirname, 'fixtures')],\n });\n\n await runner.enqueueBatchedMigration('20230406184107_failing_migration');\n\n await expect(\n runner.finalizeBatchedMigration('20230406184107_failing_migration', {\n logProgress: false,\n }),\n ).rejects.toThrow(\"but it is 'failed'\");\n const migrations = await selectAllBatchedMigrations('test');\n assert.lengthOf(migrations, 1);\n assert.equal(migrations[0].timestamp, '20230406184107');\n assert.equal(migrations[0].status, 'failed');\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/migrations",
3
- "version": "4.0.2",
3
+ "version": "4.0.4",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -14,23 +14,23 @@
14
14
  "test": "vitest run --coverage"
15
15
  },
16
16
  "dependencies": {
17
- "@prairielearn/error": "^2.0.21",
18
- "@prairielearn/logger": "^2.0.22",
19
- "@prairielearn/named-locks": "^3.0.25",
20
- "@prairielearn/postgres": "^4.4.2",
21
- "fs-extra": "^11.3.2",
17
+ "@prairielearn/error": "^2.0.23",
18
+ "@prairielearn/logger": "^2.0.24",
19
+ "@prairielearn/named-locks": "^3.0.27",
20
+ "@prairielearn/postgres": "^4.5.1",
21
+ "fs-extra": "^11.3.3",
22
22
  "serialize-error": "^12.0.0",
23
23
  "zod": "^3.25.76"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@prairielearn/tsconfig": "^0.0.0",
27
27
  "@types/fs-extra": "^11.0.4",
28
- "@types/node": "^22.18.8",
29
- "@vitest/coverage-v8": "^3.2.4",
28
+ "@types/node": "^22.19.3",
29
+ "@vitest/coverage-v8": "^4.0.16",
30
30
  "tmp-promise": "^3.0.3",
31
- "tsx": "^4.20.6",
31
+ "tsx": "^4.21.0",
32
32
  "typescript": "^5.9.3",
33
33
  "typescript-cp": "^0.1.9",
34
- "vitest": "^3.2.4"
34
+ "vitest": "^4.0.16"
35
35
  }
36
36
  }
@@ -91,8 +91,8 @@ async function insertTestBatchedMigration() {
91
91
 
92
92
  describe('BatchedMigrationExecutor', () => {
93
93
  beforeAll(async () => {
94
- await postgresTestUtils.createDatabase();
95
- await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {
94
+ const poolConfig = await postgresTestUtils.createDatabase();
95
+ await namedLocks.init(poolConfig, (err) => {
96
96
  throw err;
97
97
  });
98
98
  await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });
@@ -16,8 +16,8 @@ const postgresTestUtils = makePostgresTestUtils({
16
16
 
17
17
  describe('BatchedMigrationsRunner', () => {
18
18
  beforeAll(async () => {
19
- await postgresTestUtils.createDatabase();
20
- await namedLocks.init(postgresTestUtils.getPoolConfig(), (err) => {
19
+ const poolConfig = await postgresTestUtils.createDatabase();
20
+ await namedLocks.init(poolConfig, (err) => {
21
21
  throw err;
22
22
  });
23
23
  await init({ directories: [SCHEMA_MIGRATIONS_PATH], project: 'prairielearn_migrations' });
package/vitest.config.ts CHANGED
@@ -2,10 +2,10 @@ import { defineConfig } from 'vitest/config';
2
2
 
3
3
  export default defineConfig({
4
4
  test: {
5
+ dir: `${import.meta.dirname}/src`,
5
6
  coverage: {
6
7
  reporter: ['html', 'text-summary', 'cobertura'],
7
- all: true,
8
- include: ['src/**'],
8
+ include: ['src/**/*.{ts,tsx}'],
9
9
  },
10
10
  },
11
11
  });