From 5afe783edcfaeba9fc2ff8df35de40fc0112539a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 10 Jan 2025 11:30:58 +0000 Subject: [PATCH 001/133] wip: replace knex for new database migrations --- lib/bin/run-migrations.js | 7 ++++--- lib/model/migrate.js | 36 ++++++++++++++++++++++++++++++++++-- lib/task/task.js | 3 ++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index 0a681ce1b..9549c3cf2 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -7,13 +7,14 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withDatabase, migrate } = require('../model/migrate'); +const { withDatabase, knexMigrations, postKnexMigrations } = require('../model/migrate'); (async () => { try { - await withDatabase(require('config').get('default.database'))(migrate); + await withKnex(require('config').get('default.database'))(knexMigrations); + await withSlonikOrPg(postKnexMigrations); } catch (err) { - console.error('Error:', err.message); + console.error(err); process.exit(1); } })(); diff --git a/lib/model/migrate.js b/lib/model/migrate.js index fe18ed2f5..cf4da24c6 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -11,6 +11,7 @@ // top-level operations with a database, like migrations. const knex = require('knex'); +const { Migrator } = require('knex/lib/migrate/Migrator'); const { connectionObject } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. @@ -23,7 +24,38 @@ const withDatabase = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations` }); +const knexMigrations = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy` }); +const postKnexMigrations = (db) => { + // In the main, this migrator is written to behave similarly to knex's: + // + // * re-uses knex_migrations table + // * expects transaction property async .up({ raw }) + // * provides implementation of db.raw() + // + // Notable differences + // + // * ONLY provides db.raw() function to transactions - no knex query builder etc. + // * ONLY implements up(); will throw if a transaction has other properties, except for `down()` which will be ignored for pre-2025 migrations + // * does not use a separate knex_migrations_lock table (in fact, this should be DROPped as the first post-knex migration TODO is this comfortable?) + // * gets list of migrations to run _after_ acquiring db lock + // * sets migration_time to be the start of the migration batch's transaction rather than some other intermediate time + + + // TODO consider whether the knex_migrations_lock table is useful vs. just locking the whole migrations table (probably fine) + // TODO can we just fail if there is ANY waiting for lock acquisition? probably simpler than handling edge cases like knex does (probably) + // TODO would life be simpler if we get the list of migrations to run AFTER acquiring the lock? (probably) + // TODO understand whether we want to run all migrations in the same transaction, or separately. seems like currently all run in the same transaction, although knex provides options for isolating a single migration, and for using separate transactions for each + + // 1. TODO start transaction (most aggressive type) + // 2. TODO if migration table does not exist, CREATE IT + // 3. TODO get lock on knex_migrations table; throw if lock not available IMMEDIATELY + // 4. TODO get list of migrations to run + // 5. TODO validate migrations to run (e.g. do they have unexpected properties) + // 7. TODO remove any migrations from list which were run while waiting for the lock + // 8. TODO run all migrations + // 9. TODO get migration batch number (COALESCE(MAX(batch), 0) + 1) + // 10. TODO update knex_migrations table to include newly-run migrations (migration_time should either be NOW() or CLOCK_TIMESTAMP(), but currently unclear whether knex has been running all migrations in the same tx or not) +}; // Checks for pending migrations and returns an exit code of 1 if any are // still pending/unapplied (e.g. automatically running migrations just failed). @@ -33,5 +65,5 @@ const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migra process.exitCode = 1; }); -module.exports = { checkMigrations, connect, withDatabase, migrate }; +module.exports = { checkMigrations, connect, withDatabase, knexMigrations, postKnexMigrations }; diff --git a/lib/task/task.js b/lib/task/task.js index 516e6c29d..f72fa23e2 100644 --- a/lib/task/task.js +++ b/lib/task/task.js @@ -75,6 +75,7 @@ const writeTo = (output) => (x) => output.write(`${x}\n`); const writeToStderr = writeTo(process.stderr); /* istanbul ignore next */ const fault = (error) => { + console.log('fault()', error); // first print our error. if ((error != null) && (error.isProblem === true) && (error.httpCode < 500)) { writeToStderr(error.message); @@ -105,7 +106,7 @@ const auditing = (action, t) => ((typeof t === 'function') return Promise.resolve(result); }) )), - ((error) => auditLog(action, false, Option.of(error).map(Problem.serializable).orNull()).then( + ((error) => console.log('auditing() error', error) || auditLog(action, false, Option.of(error).map(Problem.serializable).orNull()).then( (() => Promise.reject(error)), ((auditError) => { writeToStderr('Failed to audit-log task failure message!'); From 7a0260d54ac332009c08f18aeb1ed84b98a9f564 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 09:39:56 +0000 Subject: [PATCH 002/133] move all the migrations; implement the migrator --- lib/bin/check-migrations.js | 4 +- lib/bin/run-migrations.js | 12 +- lib/model/knexfile.js | 4 +- lib/model/migrate.js | 165 +++++++++++++++--- ...-01-disable-nullable-blob-content-types.js | 23 +++ .../{ => legacy}/20170920-01-initial.js | 0 .../{ => legacy}/20171010-01-auth.js | 0 .../{ => legacy}/20171023-01-authz-forms.js | 0 .../20171030-01-add-default-authz-records.js | 0 ...0171106-01-remove-user-update-timestamp.js | 0 .../20171121-01-add-submissions-constraint.js | 0 .../{ => legacy}/20171121-02-add-submitter.js | 0 .../20171213-01-unrequire-display-name.js | 0 .../20180108-01-expiring-actors.js | 0 .../20180108-02-enum-to-varchar.js | 0 .../{ => legacy}/20180112-01-audit-table.js | 0 .../20180112-02-add-field-keys.js | 0 .../20180118-01-rerequire-display-name.js | 0 .../20180125-01-add-form-detail-fields.js | 0 .../20180125-02-more-field-key-grants.js | 0 .../20180125-03-add-blob-tables.js | 0 .../{ => legacy}/20180301-01-configuration.js | 0 .../20180322-01-additional-form-options.js | 0 .../20180327-01-update-form-constraints.js | 0 .../20180501-01-add-configs-timestamp.js | 0 .../20180501-02-fix-date-columns.js | 0 ...0180515-01-enforce-nonnull-form-version.js | 0 .../20180727-01-rename-attachments-table.js | 0 .../20180727-02-add-md5-to-blobs.js | 0 .../20180727-03-add-form-attachments-table.js | 0 .../20181011-make-email-case-insensitive.js | 0 ...1012-01-add-submissions-createdat-index.js | 0 .../{ => legacy}/20181206-01-add-projects.js | 0 .../20181207-01-grant-verbs-to-text.js | 0 .../20181207-02-rename-grant-verbs.js | 0 .../20181211-01-audit-verbs-to-text.js | 0 .../20181211-02-rename-audit-actions.js | 0 .../{ => legacy}/20181212-00-fix-user-type.js | 0 .../{ => legacy}/20181212-01-add-roles.js | 0 .../{ => legacy}/20181212-02-remove-groups.js | 0 .../20181212-03-add-single-use-roles.js | 0 .../20181219-01-add-submission-update-verb.js | 0 .../20181221-01-nullable-submission-blobs.js | 0 ...20181230-01-add-device-id-to-submission.js | 0 .../20190225-01-add-actor-trigram-indices.js | 0 .../20190225-02-add-role-grants.js | 0 .../20190226-01-convert-verbs-to-jsonb.js | 0 .../20190226-02-add-role-actee-species.js | 0 .../20190226-03-add-assignment-verbs.js | 0 ...0190226-04-add-assignment-actee-species.js | 0 .../20190227-01-add-project-manager-role.js | 0 .../20190405-01-add-project-archival-flag.js | 0 .../20190416-01-email-uniqueness.js | 0 .../20190416-02-add-user-delete-verb.js | 0 .../20190520-01-add-form-versioning.js | 0 .../20190523-01-add-form-state-constraint.js | 0 .../20190605-01-reformat-audits.js | 0 ...90607-01-convert-audit-details-to-jsonb.js | 0 ...190607-02-standardize-attachment-actees.js | 0 ...0190607-03-rename-sub-attachment-audits.js | 0 .../20190610-01-add-audits-verbs.js | 0 ...2-backfill-submission-audit-instanceids.js | 0 ...11-01-add-updatedat-to-form-attachments.js | 0 .../20190618-01-add-csrf-token.js | 0 .../20190618-01-add-encryption-tracking.js | 0 ...701-01-add-managed-encryption-key-check.js | 0 ...916-01-granularize-app-user-permissions.js | 0 .../20190917-01-cleanup-app-user-role.js | 0 .../20190923-01-add-project-viewer-role.js | 0 .../20190925-01-add-client-audits.js | 0 .../20191007-01-backfill-client-audits.js | 0 .../20191010-01-add-excel-blob-reference.js | 0 ...0191023-01-add-worker-columns-to-audits.js | 0 .../20191025-01-add-id-to-audits.js | 0 ...106-01-remove-deleted-actor-assignments.js | 0 .../20191231-01-remove-transformations.js | 0 .../20191231-02-add-schema-storage.js | 0 .../{ => legacy}/20200110-01-add-drafts.js | 0 .../20200112-01-check-field-collisions.js | 0 ...0114-01-remove-formid-sha256-constraint.js | 0 .../20200117-01-draft-test-submissions.js | 0 .../20200121-01-add-draft-keys.js | 0 .../20200122-01-remove-draft-form-state.js | 0 .../20200129-01-cascade-submission-deletes.js | 0 .../20200220-01-repair-submission-parsing.js | 0 .../20200403-01-add-performance-indices.js | 0 ...0407-01-allow-actorless-submission-defs.js | 0 ...0200423-01-fix-field-insert-performance.js | 0 .../20200428-01-allow-string-downcast.js | 0 .../{ => legacy}/20200519-01-add-enketo-id.js | 0 .../20200519-02-add-form-viewer-role.js | 0 .../20200520-01-backfill-enketo.js | 0 .../20200715-01-add-data-collector-role.js | 0 .../20200721-01-add-public-links.js | 0 ...728-01-add-enketo-single-token-to-forms.js | 0 ...-allow-project-managers-to-end-sessions.js | 0 ...0200810-01-reschedule-enketo-processing.js | 0 .../20200918-01-repair-publishedat-dates.js | 0 .../20200930-01-add-backup-run-verb.js | 0 ...-remove-deleted-actor-assignments-again.js | 0 ...01207-01-harmonize-submitter-id-columns.js | 0 ...-01-add-current-flag-to-submission-defs.js | 0 .../20210120-01-instance-names.js | 0 .../20210203-01-add-hierarchy-to-actees.js | 0 ...10-01-add-instanceid-to-submission-defs.js | 0 .../20210218-01-add-submission-edit-verbs.js | 0 ...0218-02-add-draft-to-submissions-unique.js | 0 .../20210219-01-add-review-state.js | 0 ...210219-02-add-notes-and-index-to-audits.js | 0 ...1-add-submission-edit-verbs-to-managers.js | 0 .../20210325-01-remove-project.list-verb.js | 0 .../20210408-01-drop-public-link-createdat.js | 0 ...08-02-backfill-specialized-actor-audits.js | 0 .../{ => legacy}/20210409-01-add-comments.js | 0 .../20210409-02-update-review-states.js | 0 .../20210423-01-add-name-to-form-def.js | 0 .../20210423-02-drop-form-name.js | 0 .../20210716-01-config-value-jsonb.js | 0 .../20210721-01-add-config-set-verb.js | 0 ...1-disallow-structure-downcast-to-string.js | 0 .../20210825-01-add-analytics-read-verb.js | 0 ...903-01-backfill-encrypted-client-audits.js | 0 ...7-01-revert-disallow-structure-downcast.js | 0 .../20211008-01-track-select-many-options.js | 0 .../20211021-remove-hashes-from-audits.js | 0 ...211109-01-add-user-agent-to-submissions.js | 0 ...20211114-01-flag-initial-submission-def.js | 0 .../20211117-01-add-form-restore-verb.js | 0 ...0211129-01-add-purged-details-to-actees.js | 0 .../20220121-01-form-cascade-delete.js | 0 .../20220121-02-purge-deleted-forms.js | 0 .../20220209-01-purge-unneeded-drafts.js | 0 .../20220309-01-add-project-description.js | 0 .../20220803-01-create-entities-schema.js | 0 .../20221003-01-add-dataset-verbs.js | 0 .../20221114-01-explict-dataset-publish.js | 0 ...eck-datasetId-is-null-for-non-file-type.js | 0 ...21118-01-make-entities-columns-not-null.js | 0 .../20221208-01-reduce-tz-precision.js | 0 .../20230106-01-remove-revision-number.js | 0 .../20230109-01-add-form-schema.js | 0 .../20230123-01-remove-google-backups.js | 0 .../20230126-01-add-entity-indices.js | 0 .../20230127-01-rename-entity-created-by.js | 0 .../20230324-01-edit-dataset-verbs.js | 0 .../20230406-01-add-entity-def-fields.js | 0 ...0406-02-move-entity-label-add-deletedAt.js | 0 .../20230414-01-remove-user-mfa-secret.js | 0 .../20230419-01-optimize-indices-sub-defs.js | 0 .../20230509-01-dataset-approval-flag.js | 0 .../20230512-01-add-entity-root.js | 0 .../20230512-02-backfill-entity-id.js | 0 .../20230512-03-add-entity-source.js | 0 .../20230518-01-add-entity-index-to-audits.js | 0 .../20230802-01-delete-orphan-submissions.js | 0 ...1-remove-schemaId-from-dsPropertyFields.js | 0 .../20230824-01-add-entity-version.js | 0 ...0830-01-remove-entity-label-from-audits.js | 0 .../20230907-01-opened-form-verb.js | 0 .../20231002-01-add-conflict-details.js | 0 .../20231013-01-change-entity-error-action.js | 0 .../20231208-01-dataset-form-def-actions.js | 0 .../20240215-01-entity-delete-verb.js | 0 .../{ => legacy}/20240215-02-dedupe-verbs.js | 0 .../20240312-01-add-dataset-create-verb.js | 0 ...22-01-add-entity-source-index-to-audits.js | 0 .../20240515-01-entity-tz-precision.js | 0 ...01-add-offline-entity-branch-trunk-info.js | 0 .../20240607-02-add-submission-backlog.js | 0 ...0240715-01-backlog-add-event-entityuuid.js | 0 .../{ => legacy}/20240913-01-add-blob-s3.js | 0 .../20240914-01-add-submission-delete-verb.js | 0 ...240914-02-remove-orphaned-client-audits.js | 0 .../20241001-01-index-on-session-table.js | 0 .../20241008-01-add-user_preferences.js | 0 ...0241010-01-schedule-entity-form-upgrade.js | 0 ...hedule-entity-form-upgrade-create-forms.js | 0 ...20241030-01-add-force-entity-def-source.js | 0 lib/util/db.js | 4 +- test/unit/util/db.js | 18 +- 180 files changed, 188 insertions(+), 42 deletions(-) create mode 100644 lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js rename lib/model/migrations/{ => legacy}/20170920-01-initial.js (100%) rename lib/model/migrations/{ => legacy}/20171010-01-auth.js (100%) rename lib/model/migrations/{ => legacy}/20171023-01-authz-forms.js (100%) rename lib/model/migrations/{ => legacy}/20171030-01-add-default-authz-records.js (100%) rename lib/model/migrations/{ => legacy}/20171106-01-remove-user-update-timestamp.js (100%) rename lib/model/migrations/{ => legacy}/20171121-01-add-submissions-constraint.js (100%) rename lib/model/migrations/{ => legacy}/20171121-02-add-submitter.js (100%) rename lib/model/migrations/{ => legacy}/20171213-01-unrequire-display-name.js (100%) rename lib/model/migrations/{ => legacy}/20180108-01-expiring-actors.js (100%) rename lib/model/migrations/{ => legacy}/20180108-02-enum-to-varchar.js (100%) rename lib/model/migrations/{ => legacy}/20180112-01-audit-table.js (100%) rename lib/model/migrations/{ => legacy}/20180112-02-add-field-keys.js (100%) rename lib/model/migrations/{ => legacy}/20180118-01-rerequire-display-name.js (100%) rename lib/model/migrations/{ => legacy}/20180125-01-add-form-detail-fields.js (100%) rename lib/model/migrations/{ => legacy}/20180125-02-more-field-key-grants.js (100%) rename lib/model/migrations/{ => legacy}/20180125-03-add-blob-tables.js (100%) rename lib/model/migrations/{ => legacy}/20180301-01-configuration.js (100%) rename lib/model/migrations/{ => legacy}/20180322-01-additional-form-options.js (100%) rename lib/model/migrations/{ => legacy}/20180327-01-update-form-constraints.js (100%) rename lib/model/migrations/{ => legacy}/20180501-01-add-configs-timestamp.js (100%) rename lib/model/migrations/{ => legacy}/20180501-02-fix-date-columns.js (100%) rename lib/model/migrations/{ => legacy}/20180515-01-enforce-nonnull-form-version.js (100%) rename lib/model/migrations/{ => legacy}/20180727-01-rename-attachments-table.js (100%) rename lib/model/migrations/{ => legacy}/20180727-02-add-md5-to-blobs.js (100%) rename lib/model/migrations/{ => legacy}/20180727-03-add-form-attachments-table.js (100%) rename lib/model/migrations/{ => legacy}/20181011-make-email-case-insensitive.js (100%) rename lib/model/migrations/{ => legacy}/20181012-01-add-submissions-createdat-index.js (100%) rename lib/model/migrations/{ => legacy}/20181206-01-add-projects.js (100%) rename lib/model/migrations/{ => legacy}/20181207-01-grant-verbs-to-text.js (100%) rename lib/model/migrations/{ => legacy}/20181207-02-rename-grant-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20181211-01-audit-verbs-to-text.js (100%) rename lib/model/migrations/{ => legacy}/20181211-02-rename-audit-actions.js (100%) rename lib/model/migrations/{ => legacy}/20181212-00-fix-user-type.js (100%) rename lib/model/migrations/{ => legacy}/20181212-01-add-roles.js (100%) rename lib/model/migrations/{ => legacy}/20181212-02-remove-groups.js (100%) rename lib/model/migrations/{ => legacy}/20181212-03-add-single-use-roles.js (100%) rename lib/model/migrations/{ => legacy}/20181219-01-add-submission-update-verb.js (100%) rename lib/model/migrations/{ => legacy}/20181221-01-nullable-submission-blobs.js (100%) rename lib/model/migrations/{ => legacy}/20181230-01-add-device-id-to-submission.js (100%) rename lib/model/migrations/{ => legacy}/20190225-01-add-actor-trigram-indices.js (100%) rename lib/model/migrations/{ => legacy}/20190225-02-add-role-grants.js (100%) rename lib/model/migrations/{ => legacy}/20190226-01-convert-verbs-to-jsonb.js (100%) rename lib/model/migrations/{ => legacy}/20190226-02-add-role-actee-species.js (100%) rename lib/model/migrations/{ => legacy}/20190226-03-add-assignment-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20190226-04-add-assignment-actee-species.js (100%) rename lib/model/migrations/{ => legacy}/20190227-01-add-project-manager-role.js (100%) rename lib/model/migrations/{ => legacy}/20190405-01-add-project-archival-flag.js (100%) rename lib/model/migrations/{ => legacy}/20190416-01-email-uniqueness.js (100%) rename lib/model/migrations/{ => legacy}/20190416-02-add-user-delete-verb.js (100%) rename lib/model/migrations/{ => legacy}/20190520-01-add-form-versioning.js (100%) rename lib/model/migrations/{ => legacy}/20190523-01-add-form-state-constraint.js (100%) rename lib/model/migrations/{ => legacy}/20190605-01-reformat-audits.js (100%) rename lib/model/migrations/{ => legacy}/20190607-01-convert-audit-details-to-jsonb.js (100%) rename lib/model/migrations/{ => legacy}/20190607-02-standardize-attachment-actees.js (100%) rename lib/model/migrations/{ => legacy}/20190607-03-rename-sub-attachment-audits.js (100%) rename lib/model/migrations/{ => legacy}/20190610-01-add-audits-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20190610-02-backfill-submission-audit-instanceids.js (100%) rename lib/model/migrations/{ => legacy}/20190611-01-add-updatedat-to-form-attachments.js (100%) rename lib/model/migrations/{ => legacy}/20190618-01-add-csrf-token.js (100%) rename lib/model/migrations/{ => legacy}/20190618-01-add-encryption-tracking.js (100%) rename lib/model/migrations/{ => legacy}/20190701-01-add-managed-encryption-key-check.js (100%) rename lib/model/migrations/{ => legacy}/20190916-01-granularize-app-user-permissions.js (100%) rename lib/model/migrations/{ => legacy}/20190917-01-cleanup-app-user-role.js (100%) rename lib/model/migrations/{ => legacy}/20190923-01-add-project-viewer-role.js (100%) rename lib/model/migrations/{ => legacy}/20190925-01-add-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191007-01-backfill-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191010-01-add-excel-blob-reference.js (100%) rename lib/model/migrations/{ => legacy}/20191023-01-add-worker-columns-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191025-01-add-id-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191106-01-remove-deleted-actor-assignments.js (100%) rename lib/model/migrations/{ => legacy}/20191231-01-remove-transformations.js (100%) rename lib/model/migrations/{ => legacy}/20191231-02-add-schema-storage.js (100%) rename lib/model/migrations/{ => legacy}/20200110-01-add-drafts.js (100%) rename lib/model/migrations/{ => legacy}/20200112-01-check-field-collisions.js (100%) rename lib/model/migrations/{ => legacy}/20200114-01-remove-formid-sha256-constraint.js (100%) rename lib/model/migrations/{ => legacy}/20200117-01-draft-test-submissions.js (100%) rename lib/model/migrations/{ => legacy}/20200121-01-add-draft-keys.js (100%) rename lib/model/migrations/{ => legacy}/20200122-01-remove-draft-form-state.js (100%) rename lib/model/migrations/{ => legacy}/20200129-01-cascade-submission-deletes.js (100%) rename lib/model/migrations/{ => legacy}/20200220-01-repair-submission-parsing.js (100%) rename lib/model/migrations/{ => legacy}/20200403-01-add-performance-indices.js (100%) rename lib/model/migrations/{ => legacy}/20200407-01-allow-actorless-submission-defs.js (100%) rename lib/model/migrations/{ => legacy}/20200423-01-fix-field-insert-performance.js (100%) rename lib/model/migrations/{ => legacy}/20200428-01-allow-string-downcast.js (100%) rename lib/model/migrations/{ => legacy}/20200519-01-add-enketo-id.js (100%) rename lib/model/migrations/{ => legacy}/20200519-02-add-form-viewer-role.js (100%) rename lib/model/migrations/{ => legacy}/20200520-01-backfill-enketo.js (100%) rename lib/model/migrations/{ => legacy}/20200715-01-add-data-collector-role.js (100%) rename lib/model/migrations/{ => legacy}/20200721-01-add-public-links.js (100%) rename lib/model/migrations/{ => legacy}/20200728-01-add-enketo-single-token-to-forms.js (100%) rename lib/model/migrations/{ => legacy}/20200731-01-allow-project-managers-to-end-sessions.js (100%) rename lib/model/migrations/{ => legacy}/20200810-01-reschedule-enketo-processing.js (100%) rename lib/model/migrations/{ => legacy}/20200918-01-repair-publishedat-dates.js (100%) rename lib/model/migrations/{ => legacy}/20200930-01-add-backup-run-verb.js (100%) rename lib/model/migrations/{ => legacy}/20201117-01-remove-deleted-actor-assignments-again.js (100%) rename lib/model/migrations/{ => legacy}/20201207-01-harmonize-submitter-id-columns.js (100%) rename lib/model/migrations/{ => legacy}/20210118-01-add-current-flag-to-submission-defs.js (100%) rename lib/model/migrations/{ => legacy}/20210120-01-instance-names.js (100%) rename lib/model/migrations/{ => legacy}/20210203-01-add-hierarchy-to-actees.js (100%) rename lib/model/migrations/{ => legacy}/20210210-01-add-instanceid-to-submission-defs.js (100%) rename lib/model/migrations/{ => legacy}/20210218-01-add-submission-edit-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20210218-02-add-draft-to-submissions-unique.js (100%) rename lib/model/migrations/{ => legacy}/20210219-01-add-review-state.js (100%) rename lib/model/migrations/{ => legacy}/20210219-02-add-notes-and-index-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20210324-01-add-submission-edit-verbs-to-managers.js (100%) rename lib/model/migrations/{ => legacy}/20210325-01-remove-project.list-verb.js (100%) rename lib/model/migrations/{ => legacy}/20210408-01-drop-public-link-createdat.js (100%) rename lib/model/migrations/{ => legacy}/20210408-02-backfill-specialized-actor-audits.js (100%) rename lib/model/migrations/{ => legacy}/20210409-01-add-comments.js (100%) rename lib/model/migrations/{ => legacy}/20210409-02-update-review-states.js (100%) rename lib/model/migrations/{ => legacy}/20210423-01-add-name-to-form-def.js (100%) rename lib/model/migrations/{ => legacy}/20210423-02-drop-form-name.js (100%) rename lib/model/migrations/{ => legacy}/20210716-01-config-value-jsonb.js (100%) rename lib/model/migrations/{ => legacy}/20210721-01-add-config-set-verb.js (100%) rename lib/model/migrations/{ => legacy}/20210817-01-disallow-structure-downcast-to-string.js (100%) rename lib/model/migrations/{ => legacy}/20210825-01-add-analytics-read-verb.js (100%) rename lib/model/migrations/{ => legacy}/20210903-01-backfill-encrypted-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20210927-01-revert-disallow-structure-downcast.js (100%) rename lib/model/migrations/{ => legacy}/20211008-01-track-select-many-options.js (100%) rename lib/model/migrations/{ => legacy}/20211021-remove-hashes-from-audits.js (100%) rename lib/model/migrations/{ => legacy}/20211109-01-add-user-agent-to-submissions.js (100%) rename lib/model/migrations/{ => legacy}/20211114-01-flag-initial-submission-def.js (100%) rename lib/model/migrations/{ => legacy}/20211117-01-add-form-restore-verb.js (100%) rename lib/model/migrations/{ => legacy}/20211129-01-add-purged-details-to-actees.js (100%) rename lib/model/migrations/{ => legacy}/20220121-01-form-cascade-delete.js (100%) rename lib/model/migrations/{ => legacy}/20220121-02-purge-deleted-forms.js (100%) rename lib/model/migrations/{ => legacy}/20220209-01-purge-unneeded-drafts.js (100%) rename lib/model/migrations/{ => legacy}/20220309-01-add-project-description.js (100%) rename lib/model/migrations/{ => legacy}/20220803-01-create-entities-schema.js (100%) rename lib/model/migrations/{ => legacy}/20221003-01-add-dataset-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20221114-01-explict-dataset-publish.js (100%) rename lib/model/migrations/{ => legacy}/20221117-01-check-datasetId-is-null-for-non-file-type.js (100%) rename lib/model/migrations/{ => legacy}/20221118-01-make-entities-columns-not-null.js (100%) rename lib/model/migrations/{ => legacy}/20221208-01-reduce-tz-precision.js (100%) rename lib/model/migrations/{ => legacy}/20230106-01-remove-revision-number.js (100%) rename lib/model/migrations/{ => legacy}/20230109-01-add-form-schema.js (100%) rename lib/model/migrations/{ => legacy}/20230123-01-remove-google-backups.js (100%) rename lib/model/migrations/{ => legacy}/20230126-01-add-entity-indices.js (100%) rename lib/model/migrations/{ => legacy}/20230127-01-rename-entity-created-by.js (100%) rename lib/model/migrations/{ => legacy}/20230324-01-edit-dataset-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20230406-01-add-entity-def-fields.js (100%) rename lib/model/migrations/{ => legacy}/20230406-02-move-entity-label-add-deletedAt.js (100%) rename lib/model/migrations/{ => legacy}/20230414-01-remove-user-mfa-secret.js (100%) rename lib/model/migrations/{ => legacy}/20230419-01-optimize-indices-sub-defs.js (100%) rename lib/model/migrations/{ => legacy}/20230509-01-dataset-approval-flag.js (100%) rename lib/model/migrations/{ => legacy}/20230512-01-add-entity-root.js (100%) rename lib/model/migrations/{ => legacy}/20230512-02-backfill-entity-id.js (100%) rename lib/model/migrations/{ => legacy}/20230512-03-add-entity-source.js (100%) rename lib/model/migrations/{ => legacy}/20230518-01-add-entity-index-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20230802-01-delete-orphan-submissions.js (100%) rename lib/model/migrations/{ => legacy}/20230818-01-remove-schemaId-from-dsPropertyFields.js (100%) rename lib/model/migrations/{ => legacy}/20230824-01-add-entity-version.js (100%) rename lib/model/migrations/{ => legacy}/20230830-01-remove-entity-label-from-audits.js (100%) rename lib/model/migrations/{ => legacy}/20230907-01-opened-form-verb.js (100%) rename lib/model/migrations/{ => legacy}/20231002-01-add-conflict-details.js (100%) rename lib/model/migrations/{ => legacy}/20231013-01-change-entity-error-action.js (100%) rename lib/model/migrations/{ => legacy}/20231208-01-dataset-form-def-actions.js (100%) rename lib/model/migrations/{ => legacy}/20240215-01-entity-delete-verb.js (100%) rename lib/model/migrations/{ => legacy}/20240215-02-dedupe-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20240312-01-add-dataset-create-verb.js (100%) rename lib/model/migrations/{ => legacy}/20240322-01-add-entity-source-index-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20240515-01-entity-tz-precision.js (100%) rename lib/model/migrations/{ => legacy}/20240607-01-add-offline-entity-branch-trunk-info.js (100%) rename lib/model/migrations/{ => legacy}/20240607-02-add-submission-backlog.js (100%) rename lib/model/migrations/{ => legacy}/20240715-01-backlog-add-event-entityuuid.js (100%) rename lib/model/migrations/{ => legacy}/20240913-01-add-blob-s3.js (100%) rename lib/model/migrations/{ => legacy}/20240914-01-add-submission-delete-verb.js (100%) rename lib/model/migrations/{ => legacy}/20240914-02-remove-orphaned-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20241001-01-index-on-session-table.js (100%) rename lib/model/migrations/{ => legacy}/20241008-01-add-user_preferences.js (100%) rename lib/model/migrations/{ => legacy}/20241010-01-schedule-entity-form-upgrade.js (100%) rename lib/model/migrations/{ => legacy}/20241029-01-schedule-entity-form-upgrade-create-forms.js (100%) rename lib/model/migrations/{ => legacy}/20241030-01-add-force-entity-def-source.js (100%) diff --git a/lib/bin/check-migrations.js b/lib/bin/check-migrations.js index e5d4308da..20b9c5e82 100644 --- a/lib/bin/check-migrations.js +++ b/lib/bin/check-migrations.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withDatabase, checkMigrations } = require('../model/migrate'); +const { withKnex, checkMigrations } = require('../model/migrate'); (async () => { try { - await withDatabase(require('config').get('default.database'))(checkMigrations); + await withKnex(require('config').get('default.database'))(checkMigrations); } catch (err) { console.error('Error:', err.message); process.exit(1); diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index 9549c3cf2..93324f8c6 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -7,12 +7,18 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withDatabase, knexMigrations, postKnexMigrations } = require('../model/migrate'); +const { + withKnex, + knexMigrations, + + postKnexMigrations, +} = require('../model/migrate'); (async () => { try { - await withKnex(require('config').get('default.database'))(knexMigrations); - await withSlonikOrPg(postKnexMigrations); + const config = require('config').get('default.database'); + await withKnex(config)(knexMigrations); + await postKnexMigrations(config); } catch (err) { console.error(err); process.exit(1); diff --git a/lib/model/knexfile.js b/lib/model/knexfile.js index 84622389b..511584825 100644 --- a/lib/model/knexfile.js +++ b/lib/model/knexfile.js @@ -28,10 +28,10 @@ NODE_CONFIG_DIR=../../config DEBUG=knex:query,knex:bindings npx knex migrate:up */ const config = require('config'); -const { connectionObject } = require('../util/db'); +const { knexConfig } = require('../util/db'); module.exports = { client: 'pg', - connection: connectionObject(config.get('default.database')) + connection: knexConfig(config.get('default.database')) }; diff --git a/lib/model/migrate.js b/lib/model/migrate.js index cf4da24c6..53c3b9ec7 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -10,51 +10,168 @@ // This is a variety of functions helpful for connecting to and performing // top-level operations with a database, like migrations. +const { lstatSync, readdirSync } = require('node:fs'); + +const _ = require('lodash'); const knex = require('knex'); +const pg = require('pg'); const { Migrator } = require('knex/lib/migrate/Migrator'); -const { connectionObject } = require('../util/db'); +const { knexConfig } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. -const connect = (config) => knex({ client: 'pg', connection: connectionObject(config) }); +const initKnex = (config) => knex({ client: 'pg', connection: knexConfig(config) }); // Connects to a database, passes it to a function for operations, then ensures its closure. -const withDatabase = (config) => (mutator) => { - const db = connect(config); +const withKnex = (config) => (mutator) => { + const db = initKnex(config); return mutator(db).finally(() => db.destroy()); }; // Given a database, initiates migrations on it. const knexMigrations = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy` }); -const postKnexMigrations = (db) => { + +const postKnexMigrations = async (config) => { + const log = (...args) => console.log('[postKnexMigrations]', ...args); + log('ENTRY'); + + const { Client } = pg; + const client = new Client(config); + + log('client created'); + // In the main, this migrator is written to behave similarly to knex's: // - // * re-uses knex_migrations table // * expects transaction property async .up({ raw }) // * provides implementation of db.raw() + // * runs all new migrations in the same transaction // // Notable differences // - // * ONLY provides db.raw() function to transactions - no knex query builder etc. - // * ONLY implements up(); will throw if a transaction has other properties, except for `down()` which will be ignored for pre-2025 migrations - // * does not use a separate knex_migrations_lock table (in fact, this should be DROPped as the first post-knex migration TODO is this comfortable?) + // * uses new post_knex_migrations table + // * ONLY provides db.raw()-equivalent function to transactions - no knex query builder etc. + // * ONLY implements up(); will throw if a transaction has other properties, except for `down()` which is currently ignored TODO implement this if it's useful to devs // * gets list of migrations to run _after_ acquiring db lock // * sets migration_time to be the start of the migration batch's transaction rather than some other intermediate time + try { + log('Connecting to client...'); + await client.connect(); + log('Client connected OK.'); + + log('Testing client...'); + const res = await client.query('SELECT NOW()'); + log('Client returned:', res); + + log('Starting transaction...'); + await client.query('BEGIN'); // TODO do we need a specific transaction type? + log('Transaction started.'); + + log('Acquiring knex lock...'); + // TODO do this... if it's useful. Need to think of _some_ way to prevent new migrations and old migrations running simultaneously. + log('Knex lock acquired'); + + log('Creating new table if not exists...'); + // N.B. this table is created to be similar to the legacy knex-created table. + // The key difference is that name, batch and migration_time columns are + // not nullable. + await client.query(` + CREATE TABLE IF NOT EXISTS post_knex_migrations ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + batch INTEGER NOT NULL, + migration_time TIMESTAMP(3) WITH TIME ZONE NOT NULL + )`); + log('Table now definitely exists.'); + + log('Acquiring lock on post_knex_migrations table...'); + await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); + log('Lock acquired.'); + + const migrationsDir = `${__dirname}/migrations`; + const allMigrations = readdirSync(migrationsDir) + .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) + .sort(); + log('allMigrations:', allMigrations); + + const alreadyRun = (await client.query('SELECT name FROM post_knex_migrations')).rows.map(r => r.name); + log('alreadyRun:', alreadyRun); + + const toRunNames = allMigrations.filter(m => !alreadyRun.includes(m)); + log('toRunNames:', toRunNames); + + const toRun = toRunNames.map(name => { + const path = `${migrationsDir}/${name}`; + const migration = require(path); + return { name, path, migration }; + }); + log('toRun:', toRun); + + if(!toRun.length) { + log('No migrations to run - exiting.'); + await client.query('ROLLBACK'); + return; + } + + log('Validating', toRun.length, 'migrations...'); + for(const { migration, name, path } of toRun) { + log('Validing migration:', name, '...'); + + if(name.length > 255) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); + + // TODO check for illegal chars in name? + + const keys = Object.keys(migration); + const unexpectedKeys = _.omit(keys, 'up', 'down'); + if(unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); + + if(!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); + if(typeof migration.up !== 'function') { + throw new Error(`Required prop .up of migration ${name} has incorrect type - expected 'function', but got '${typeof migration.up}'`); + } + + if(migration.down && typeof migration.down !== 'function') { + throw new Error(`Optional prop .down of migration ${name} has incorrect type - expected 'function' but got '${typeof migration.down}'`); + } + + log('Migration', name, 'looks valid.'); + } + log(toRun.length, 'migrations look valid.'); + + log('Running', toRun.length, 'migrations...'); + for (const { migration, name, path } of toRun) { + log('Running migration:', name); + await migration.up(client); + log('Migration complete:', name); + } + log(toRun.length, 'migrations ran OK.'); + + const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM post_knex_migrations`)).rows[0]; + log('lastBatch:', lastBatch); + + // Note that migration_time is CLOCK_TIMESTAMP() to match knex implementation. + // TODO confirm in relevant version of knex source code that this is actually the case, and link here. + const namesJson = JSON.stringify(toRun.map(m => m.name)); + // See: https://www.postgresql.org/docs/current/functions-json.html + await client.query(` + INSERT INTO post_knex_migrations(name, batch, migration_time) + SELECT value#>>'{}' AS name + , ${lastBatch + 1} AS batch + , CLOCK_TIMESTAMP() AS migration_time + FROM JSON_ARRAY_ELEMENTS($1) + `, [ namesJson ]); - // TODO consider whether the knex_migrations_lock table is useful vs. just locking the whole migrations table (probably fine) - // TODO can we just fail if there is ANY waiting for lock acquisition? probably simpler than handling edge cases like knex does (probably) - // TODO would life be simpler if we get the list of migrations to run AFTER acquiring the lock? (probably) - // TODO understand whether we want to run all migrations in the same transaction, or separately. seems like currently all run in the same transaction, although knex provides options for isolating a single migration, and for using separate transactions for each - - // 1. TODO start transaction (most aggressive type) - // 2. TODO if migration table does not exist, CREATE IT - // 3. TODO get lock on knex_migrations table; throw if lock not available IMMEDIATELY - // 4. TODO get list of migrations to run - // 5. TODO validate migrations to run (e.g. do they have unexpected properties) - // 7. TODO remove any migrations from list which were run while waiting for the lock - // 8. TODO run all migrations - // 9. TODO get migration batch number (COALESCE(MAX(batch), 0) + 1) - // 10. TODO update knex_migrations table to include newly-run migrations (migration_time should either be NOW() or CLOCK_TIMESTAMP(), but currently unclear whether knex has been running all migrations in the same tx or not) + log('Committing migrations...'); + await client.query('COMMIT'); + log('Migrations committed.'); + } catch (err) { + log('Caught error; rolling back', err); + await client.query('ROLLBACK'); + throw err; + } finally { + log('Ending client...'); + await client.end(); // TODO needs await or callback? + log('Client ended.'); + } }; // Checks for pending migrations and returns an exit code of 1 if any are @@ -65,5 +182,5 @@ const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migra process.exitCode = 1; }); -module.exports = { checkMigrations, connect, withDatabase, knexMigrations, postKnexMigrations }; +module.exports = { checkMigrations, initKnex, withKnex, knexMigrations, postKnexMigrations }; diff --git a/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js b/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js new file mode 100644 index 000000000..eb7bc2c39 --- /dev/null +++ b/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js @@ -0,0 +1,23 @@ +// Copyright 2025 ODK Central Developers +// See the NOTICE file at the top-level directory of this distribution and at +// https://github.com/getodk/central-backend/blob/master/NOTICE. +// This file is part of ODK Central. It is subject to the license terms in +// the LICENSE file found in the top-level directory of this distribution and at +// https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, +// including this file, may be copied, modified, propagated, or distributed +// except according to the terms contained in the LICENSE file. + +const up = (db) => db.query(` + ALTER TABLE blobs + ALTER COLUMN "contentType" TYPE TEXT USING(COALESCE("contentType", 'application/octet-stream')), + ALTER COLUMN "contentType" SET DEFAULT 'application/octet-stream', + ALTER COLUMN "contentType" SET NOT NULL +`); + +const down = (db) => db.query(` + ALTER TABLE blobs + ALTER COLUMN "contentType" DROP NOT NULL, + ALTER COLUMN "contentType" DROP DEFAULT +`); + +module.exports = { up, down }; diff --git a/lib/model/migrations/20170920-01-initial.js b/lib/model/migrations/legacy/20170920-01-initial.js similarity index 100% rename from lib/model/migrations/20170920-01-initial.js rename to lib/model/migrations/legacy/20170920-01-initial.js diff --git a/lib/model/migrations/20171010-01-auth.js b/lib/model/migrations/legacy/20171010-01-auth.js similarity index 100% rename from lib/model/migrations/20171010-01-auth.js rename to lib/model/migrations/legacy/20171010-01-auth.js diff --git a/lib/model/migrations/20171023-01-authz-forms.js b/lib/model/migrations/legacy/20171023-01-authz-forms.js similarity index 100% rename from lib/model/migrations/20171023-01-authz-forms.js rename to lib/model/migrations/legacy/20171023-01-authz-forms.js diff --git a/lib/model/migrations/20171030-01-add-default-authz-records.js b/lib/model/migrations/legacy/20171030-01-add-default-authz-records.js similarity index 100% rename from lib/model/migrations/20171030-01-add-default-authz-records.js rename to lib/model/migrations/legacy/20171030-01-add-default-authz-records.js diff --git a/lib/model/migrations/20171106-01-remove-user-update-timestamp.js b/lib/model/migrations/legacy/20171106-01-remove-user-update-timestamp.js similarity index 100% rename from lib/model/migrations/20171106-01-remove-user-update-timestamp.js rename to lib/model/migrations/legacy/20171106-01-remove-user-update-timestamp.js diff --git a/lib/model/migrations/20171121-01-add-submissions-constraint.js b/lib/model/migrations/legacy/20171121-01-add-submissions-constraint.js similarity index 100% rename from lib/model/migrations/20171121-01-add-submissions-constraint.js rename to lib/model/migrations/legacy/20171121-01-add-submissions-constraint.js diff --git a/lib/model/migrations/20171121-02-add-submitter.js b/lib/model/migrations/legacy/20171121-02-add-submitter.js similarity index 100% rename from lib/model/migrations/20171121-02-add-submitter.js rename to lib/model/migrations/legacy/20171121-02-add-submitter.js diff --git a/lib/model/migrations/20171213-01-unrequire-display-name.js b/lib/model/migrations/legacy/20171213-01-unrequire-display-name.js similarity index 100% rename from lib/model/migrations/20171213-01-unrequire-display-name.js rename to lib/model/migrations/legacy/20171213-01-unrequire-display-name.js diff --git a/lib/model/migrations/20180108-01-expiring-actors.js b/lib/model/migrations/legacy/20180108-01-expiring-actors.js similarity index 100% rename from lib/model/migrations/20180108-01-expiring-actors.js rename to lib/model/migrations/legacy/20180108-01-expiring-actors.js diff --git a/lib/model/migrations/20180108-02-enum-to-varchar.js b/lib/model/migrations/legacy/20180108-02-enum-to-varchar.js similarity index 100% rename from lib/model/migrations/20180108-02-enum-to-varchar.js rename to lib/model/migrations/legacy/20180108-02-enum-to-varchar.js diff --git a/lib/model/migrations/20180112-01-audit-table.js b/lib/model/migrations/legacy/20180112-01-audit-table.js similarity index 100% rename from lib/model/migrations/20180112-01-audit-table.js rename to lib/model/migrations/legacy/20180112-01-audit-table.js diff --git a/lib/model/migrations/20180112-02-add-field-keys.js b/lib/model/migrations/legacy/20180112-02-add-field-keys.js similarity index 100% rename from lib/model/migrations/20180112-02-add-field-keys.js rename to lib/model/migrations/legacy/20180112-02-add-field-keys.js diff --git a/lib/model/migrations/20180118-01-rerequire-display-name.js b/lib/model/migrations/legacy/20180118-01-rerequire-display-name.js similarity index 100% rename from lib/model/migrations/20180118-01-rerequire-display-name.js rename to lib/model/migrations/legacy/20180118-01-rerequire-display-name.js diff --git a/lib/model/migrations/20180125-01-add-form-detail-fields.js b/lib/model/migrations/legacy/20180125-01-add-form-detail-fields.js similarity index 100% rename from lib/model/migrations/20180125-01-add-form-detail-fields.js rename to lib/model/migrations/legacy/20180125-01-add-form-detail-fields.js diff --git a/lib/model/migrations/20180125-02-more-field-key-grants.js b/lib/model/migrations/legacy/20180125-02-more-field-key-grants.js similarity index 100% rename from lib/model/migrations/20180125-02-more-field-key-grants.js rename to lib/model/migrations/legacy/20180125-02-more-field-key-grants.js diff --git a/lib/model/migrations/20180125-03-add-blob-tables.js b/lib/model/migrations/legacy/20180125-03-add-blob-tables.js similarity index 100% rename from lib/model/migrations/20180125-03-add-blob-tables.js rename to lib/model/migrations/legacy/20180125-03-add-blob-tables.js diff --git a/lib/model/migrations/20180301-01-configuration.js b/lib/model/migrations/legacy/20180301-01-configuration.js similarity index 100% rename from lib/model/migrations/20180301-01-configuration.js rename to lib/model/migrations/legacy/20180301-01-configuration.js diff --git a/lib/model/migrations/20180322-01-additional-form-options.js b/lib/model/migrations/legacy/20180322-01-additional-form-options.js similarity index 100% rename from lib/model/migrations/20180322-01-additional-form-options.js rename to lib/model/migrations/legacy/20180322-01-additional-form-options.js diff --git a/lib/model/migrations/20180327-01-update-form-constraints.js b/lib/model/migrations/legacy/20180327-01-update-form-constraints.js similarity index 100% rename from lib/model/migrations/20180327-01-update-form-constraints.js rename to lib/model/migrations/legacy/20180327-01-update-form-constraints.js diff --git a/lib/model/migrations/20180501-01-add-configs-timestamp.js b/lib/model/migrations/legacy/20180501-01-add-configs-timestamp.js similarity index 100% rename from lib/model/migrations/20180501-01-add-configs-timestamp.js rename to lib/model/migrations/legacy/20180501-01-add-configs-timestamp.js diff --git a/lib/model/migrations/20180501-02-fix-date-columns.js b/lib/model/migrations/legacy/20180501-02-fix-date-columns.js similarity index 100% rename from lib/model/migrations/20180501-02-fix-date-columns.js rename to lib/model/migrations/legacy/20180501-02-fix-date-columns.js diff --git a/lib/model/migrations/20180515-01-enforce-nonnull-form-version.js b/lib/model/migrations/legacy/20180515-01-enforce-nonnull-form-version.js similarity index 100% rename from lib/model/migrations/20180515-01-enforce-nonnull-form-version.js rename to lib/model/migrations/legacy/20180515-01-enforce-nonnull-form-version.js diff --git a/lib/model/migrations/20180727-01-rename-attachments-table.js b/lib/model/migrations/legacy/20180727-01-rename-attachments-table.js similarity index 100% rename from lib/model/migrations/20180727-01-rename-attachments-table.js rename to lib/model/migrations/legacy/20180727-01-rename-attachments-table.js diff --git a/lib/model/migrations/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js similarity index 100% rename from lib/model/migrations/20180727-02-add-md5-to-blobs.js rename to lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js diff --git a/lib/model/migrations/20180727-03-add-form-attachments-table.js b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js similarity index 100% rename from lib/model/migrations/20180727-03-add-form-attachments-table.js rename to lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js diff --git a/lib/model/migrations/20181011-make-email-case-insensitive.js b/lib/model/migrations/legacy/20181011-make-email-case-insensitive.js similarity index 100% rename from lib/model/migrations/20181011-make-email-case-insensitive.js rename to lib/model/migrations/legacy/20181011-make-email-case-insensitive.js diff --git a/lib/model/migrations/20181012-01-add-submissions-createdat-index.js b/lib/model/migrations/legacy/20181012-01-add-submissions-createdat-index.js similarity index 100% rename from lib/model/migrations/20181012-01-add-submissions-createdat-index.js rename to lib/model/migrations/legacy/20181012-01-add-submissions-createdat-index.js diff --git a/lib/model/migrations/20181206-01-add-projects.js b/lib/model/migrations/legacy/20181206-01-add-projects.js similarity index 100% rename from lib/model/migrations/20181206-01-add-projects.js rename to lib/model/migrations/legacy/20181206-01-add-projects.js diff --git a/lib/model/migrations/20181207-01-grant-verbs-to-text.js b/lib/model/migrations/legacy/20181207-01-grant-verbs-to-text.js similarity index 100% rename from lib/model/migrations/20181207-01-grant-verbs-to-text.js rename to lib/model/migrations/legacy/20181207-01-grant-verbs-to-text.js diff --git a/lib/model/migrations/20181207-02-rename-grant-verbs.js b/lib/model/migrations/legacy/20181207-02-rename-grant-verbs.js similarity index 100% rename from lib/model/migrations/20181207-02-rename-grant-verbs.js rename to lib/model/migrations/legacy/20181207-02-rename-grant-verbs.js diff --git a/lib/model/migrations/20181211-01-audit-verbs-to-text.js b/lib/model/migrations/legacy/20181211-01-audit-verbs-to-text.js similarity index 100% rename from lib/model/migrations/20181211-01-audit-verbs-to-text.js rename to lib/model/migrations/legacy/20181211-01-audit-verbs-to-text.js diff --git a/lib/model/migrations/20181211-02-rename-audit-actions.js b/lib/model/migrations/legacy/20181211-02-rename-audit-actions.js similarity index 100% rename from lib/model/migrations/20181211-02-rename-audit-actions.js rename to lib/model/migrations/legacy/20181211-02-rename-audit-actions.js diff --git a/lib/model/migrations/20181212-00-fix-user-type.js b/lib/model/migrations/legacy/20181212-00-fix-user-type.js similarity index 100% rename from lib/model/migrations/20181212-00-fix-user-type.js rename to lib/model/migrations/legacy/20181212-00-fix-user-type.js diff --git a/lib/model/migrations/20181212-01-add-roles.js b/lib/model/migrations/legacy/20181212-01-add-roles.js similarity index 100% rename from lib/model/migrations/20181212-01-add-roles.js rename to lib/model/migrations/legacy/20181212-01-add-roles.js diff --git a/lib/model/migrations/20181212-02-remove-groups.js b/lib/model/migrations/legacy/20181212-02-remove-groups.js similarity index 100% rename from lib/model/migrations/20181212-02-remove-groups.js rename to lib/model/migrations/legacy/20181212-02-remove-groups.js diff --git a/lib/model/migrations/20181212-03-add-single-use-roles.js b/lib/model/migrations/legacy/20181212-03-add-single-use-roles.js similarity index 100% rename from lib/model/migrations/20181212-03-add-single-use-roles.js rename to lib/model/migrations/legacy/20181212-03-add-single-use-roles.js diff --git a/lib/model/migrations/20181219-01-add-submission-update-verb.js b/lib/model/migrations/legacy/20181219-01-add-submission-update-verb.js similarity index 100% rename from lib/model/migrations/20181219-01-add-submission-update-verb.js rename to lib/model/migrations/legacy/20181219-01-add-submission-update-verb.js diff --git a/lib/model/migrations/20181221-01-nullable-submission-blobs.js b/lib/model/migrations/legacy/20181221-01-nullable-submission-blobs.js similarity index 100% rename from lib/model/migrations/20181221-01-nullable-submission-blobs.js rename to lib/model/migrations/legacy/20181221-01-nullable-submission-blobs.js diff --git a/lib/model/migrations/20181230-01-add-device-id-to-submission.js b/lib/model/migrations/legacy/20181230-01-add-device-id-to-submission.js similarity index 100% rename from lib/model/migrations/20181230-01-add-device-id-to-submission.js rename to lib/model/migrations/legacy/20181230-01-add-device-id-to-submission.js diff --git a/lib/model/migrations/20190225-01-add-actor-trigram-indices.js b/lib/model/migrations/legacy/20190225-01-add-actor-trigram-indices.js similarity index 100% rename from lib/model/migrations/20190225-01-add-actor-trigram-indices.js rename to lib/model/migrations/legacy/20190225-01-add-actor-trigram-indices.js diff --git a/lib/model/migrations/20190225-02-add-role-grants.js b/lib/model/migrations/legacy/20190225-02-add-role-grants.js similarity index 100% rename from lib/model/migrations/20190225-02-add-role-grants.js rename to lib/model/migrations/legacy/20190225-02-add-role-grants.js diff --git a/lib/model/migrations/20190226-01-convert-verbs-to-jsonb.js b/lib/model/migrations/legacy/20190226-01-convert-verbs-to-jsonb.js similarity index 100% rename from lib/model/migrations/20190226-01-convert-verbs-to-jsonb.js rename to lib/model/migrations/legacy/20190226-01-convert-verbs-to-jsonb.js diff --git a/lib/model/migrations/20190226-02-add-role-actee-species.js b/lib/model/migrations/legacy/20190226-02-add-role-actee-species.js similarity index 100% rename from lib/model/migrations/20190226-02-add-role-actee-species.js rename to lib/model/migrations/legacy/20190226-02-add-role-actee-species.js diff --git a/lib/model/migrations/20190226-03-add-assignment-verbs.js b/lib/model/migrations/legacy/20190226-03-add-assignment-verbs.js similarity index 100% rename from lib/model/migrations/20190226-03-add-assignment-verbs.js rename to lib/model/migrations/legacy/20190226-03-add-assignment-verbs.js diff --git a/lib/model/migrations/20190226-04-add-assignment-actee-species.js b/lib/model/migrations/legacy/20190226-04-add-assignment-actee-species.js similarity index 100% rename from lib/model/migrations/20190226-04-add-assignment-actee-species.js rename to lib/model/migrations/legacy/20190226-04-add-assignment-actee-species.js diff --git a/lib/model/migrations/20190227-01-add-project-manager-role.js b/lib/model/migrations/legacy/20190227-01-add-project-manager-role.js similarity index 100% rename from lib/model/migrations/20190227-01-add-project-manager-role.js rename to lib/model/migrations/legacy/20190227-01-add-project-manager-role.js diff --git a/lib/model/migrations/20190405-01-add-project-archival-flag.js b/lib/model/migrations/legacy/20190405-01-add-project-archival-flag.js similarity index 100% rename from lib/model/migrations/20190405-01-add-project-archival-flag.js rename to lib/model/migrations/legacy/20190405-01-add-project-archival-flag.js diff --git a/lib/model/migrations/20190416-01-email-uniqueness.js b/lib/model/migrations/legacy/20190416-01-email-uniqueness.js similarity index 100% rename from lib/model/migrations/20190416-01-email-uniqueness.js rename to lib/model/migrations/legacy/20190416-01-email-uniqueness.js diff --git a/lib/model/migrations/20190416-02-add-user-delete-verb.js b/lib/model/migrations/legacy/20190416-02-add-user-delete-verb.js similarity index 100% rename from lib/model/migrations/20190416-02-add-user-delete-verb.js rename to lib/model/migrations/legacy/20190416-02-add-user-delete-verb.js diff --git a/lib/model/migrations/20190520-01-add-form-versioning.js b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js similarity index 100% rename from lib/model/migrations/20190520-01-add-form-versioning.js rename to lib/model/migrations/legacy/20190520-01-add-form-versioning.js diff --git a/lib/model/migrations/20190523-01-add-form-state-constraint.js b/lib/model/migrations/legacy/20190523-01-add-form-state-constraint.js similarity index 100% rename from lib/model/migrations/20190523-01-add-form-state-constraint.js rename to lib/model/migrations/legacy/20190523-01-add-form-state-constraint.js diff --git a/lib/model/migrations/20190605-01-reformat-audits.js b/lib/model/migrations/legacy/20190605-01-reformat-audits.js similarity index 100% rename from lib/model/migrations/20190605-01-reformat-audits.js rename to lib/model/migrations/legacy/20190605-01-reformat-audits.js diff --git a/lib/model/migrations/20190607-01-convert-audit-details-to-jsonb.js b/lib/model/migrations/legacy/20190607-01-convert-audit-details-to-jsonb.js similarity index 100% rename from lib/model/migrations/20190607-01-convert-audit-details-to-jsonb.js rename to lib/model/migrations/legacy/20190607-01-convert-audit-details-to-jsonb.js diff --git a/lib/model/migrations/20190607-02-standardize-attachment-actees.js b/lib/model/migrations/legacy/20190607-02-standardize-attachment-actees.js similarity index 100% rename from lib/model/migrations/20190607-02-standardize-attachment-actees.js rename to lib/model/migrations/legacy/20190607-02-standardize-attachment-actees.js diff --git a/lib/model/migrations/20190607-03-rename-sub-attachment-audits.js b/lib/model/migrations/legacy/20190607-03-rename-sub-attachment-audits.js similarity index 100% rename from lib/model/migrations/20190607-03-rename-sub-attachment-audits.js rename to lib/model/migrations/legacy/20190607-03-rename-sub-attachment-audits.js diff --git a/lib/model/migrations/20190610-01-add-audits-verbs.js b/lib/model/migrations/legacy/20190610-01-add-audits-verbs.js similarity index 100% rename from lib/model/migrations/20190610-01-add-audits-verbs.js rename to lib/model/migrations/legacy/20190610-01-add-audits-verbs.js diff --git a/lib/model/migrations/20190610-02-backfill-submission-audit-instanceids.js b/lib/model/migrations/legacy/20190610-02-backfill-submission-audit-instanceids.js similarity index 100% rename from lib/model/migrations/20190610-02-backfill-submission-audit-instanceids.js rename to lib/model/migrations/legacy/20190610-02-backfill-submission-audit-instanceids.js diff --git a/lib/model/migrations/20190611-01-add-updatedat-to-form-attachments.js b/lib/model/migrations/legacy/20190611-01-add-updatedat-to-form-attachments.js similarity index 100% rename from lib/model/migrations/20190611-01-add-updatedat-to-form-attachments.js rename to lib/model/migrations/legacy/20190611-01-add-updatedat-to-form-attachments.js diff --git a/lib/model/migrations/20190618-01-add-csrf-token.js b/lib/model/migrations/legacy/20190618-01-add-csrf-token.js similarity index 100% rename from lib/model/migrations/20190618-01-add-csrf-token.js rename to lib/model/migrations/legacy/20190618-01-add-csrf-token.js diff --git a/lib/model/migrations/20190618-01-add-encryption-tracking.js b/lib/model/migrations/legacy/20190618-01-add-encryption-tracking.js similarity index 100% rename from lib/model/migrations/20190618-01-add-encryption-tracking.js rename to lib/model/migrations/legacy/20190618-01-add-encryption-tracking.js diff --git a/lib/model/migrations/20190701-01-add-managed-encryption-key-check.js b/lib/model/migrations/legacy/20190701-01-add-managed-encryption-key-check.js similarity index 100% rename from lib/model/migrations/20190701-01-add-managed-encryption-key-check.js rename to lib/model/migrations/legacy/20190701-01-add-managed-encryption-key-check.js diff --git a/lib/model/migrations/20190916-01-granularize-app-user-permissions.js b/lib/model/migrations/legacy/20190916-01-granularize-app-user-permissions.js similarity index 100% rename from lib/model/migrations/20190916-01-granularize-app-user-permissions.js rename to lib/model/migrations/legacy/20190916-01-granularize-app-user-permissions.js diff --git a/lib/model/migrations/20190917-01-cleanup-app-user-role.js b/lib/model/migrations/legacy/20190917-01-cleanup-app-user-role.js similarity index 100% rename from lib/model/migrations/20190917-01-cleanup-app-user-role.js rename to lib/model/migrations/legacy/20190917-01-cleanup-app-user-role.js diff --git a/lib/model/migrations/20190923-01-add-project-viewer-role.js b/lib/model/migrations/legacy/20190923-01-add-project-viewer-role.js similarity index 100% rename from lib/model/migrations/20190923-01-add-project-viewer-role.js rename to lib/model/migrations/legacy/20190923-01-add-project-viewer-role.js diff --git a/lib/model/migrations/20190925-01-add-client-audits.js b/lib/model/migrations/legacy/20190925-01-add-client-audits.js similarity index 100% rename from lib/model/migrations/20190925-01-add-client-audits.js rename to lib/model/migrations/legacy/20190925-01-add-client-audits.js diff --git a/lib/model/migrations/20191007-01-backfill-client-audits.js b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js similarity index 100% rename from lib/model/migrations/20191007-01-backfill-client-audits.js rename to lib/model/migrations/legacy/20191007-01-backfill-client-audits.js diff --git a/lib/model/migrations/20191010-01-add-excel-blob-reference.js b/lib/model/migrations/legacy/20191010-01-add-excel-blob-reference.js similarity index 100% rename from lib/model/migrations/20191010-01-add-excel-blob-reference.js rename to lib/model/migrations/legacy/20191010-01-add-excel-blob-reference.js diff --git a/lib/model/migrations/20191023-01-add-worker-columns-to-audits.js b/lib/model/migrations/legacy/20191023-01-add-worker-columns-to-audits.js similarity index 100% rename from lib/model/migrations/20191023-01-add-worker-columns-to-audits.js rename to lib/model/migrations/legacy/20191023-01-add-worker-columns-to-audits.js diff --git a/lib/model/migrations/20191025-01-add-id-to-audits.js b/lib/model/migrations/legacy/20191025-01-add-id-to-audits.js similarity index 100% rename from lib/model/migrations/20191025-01-add-id-to-audits.js rename to lib/model/migrations/legacy/20191025-01-add-id-to-audits.js diff --git a/lib/model/migrations/20191106-01-remove-deleted-actor-assignments.js b/lib/model/migrations/legacy/20191106-01-remove-deleted-actor-assignments.js similarity index 100% rename from lib/model/migrations/20191106-01-remove-deleted-actor-assignments.js rename to lib/model/migrations/legacy/20191106-01-remove-deleted-actor-assignments.js diff --git a/lib/model/migrations/20191231-01-remove-transformations.js b/lib/model/migrations/legacy/20191231-01-remove-transformations.js similarity index 100% rename from lib/model/migrations/20191231-01-remove-transformations.js rename to lib/model/migrations/legacy/20191231-01-remove-transformations.js diff --git a/lib/model/migrations/20191231-02-add-schema-storage.js b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js similarity index 100% rename from lib/model/migrations/20191231-02-add-schema-storage.js rename to lib/model/migrations/legacy/20191231-02-add-schema-storage.js diff --git a/lib/model/migrations/20200110-01-add-drafts.js b/lib/model/migrations/legacy/20200110-01-add-drafts.js similarity index 100% rename from lib/model/migrations/20200110-01-add-drafts.js rename to lib/model/migrations/legacy/20200110-01-add-drafts.js diff --git a/lib/model/migrations/20200112-01-check-field-collisions.js b/lib/model/migrations/legacy/20200112-01-check-field-collisions.js similarity index 100% rename from lib/model/migrations/20200112-01-check-field-collisions.js rename to lib/model/migrations/legacy/20200112-01-check-field-collisions.js diff --git a/lib/model/migrations/20200114-01-remove-formid-sha256-constraint.js b/lib/model/migrations/legacy/20200114-01-remove-formid-sha256-constraint.js similarity index 100% rename from lib/model/migrations/20200114-01-remove-formid-sha256-constraint.js rename to lib/model/migrations/legacy/20200114-01-remove-formid-sha256-constraint.js diff --git a/lib/model/migrations/20200117-01-draft-test-submissions.js b/lib/model/migrations/legacy/20200117-01-draft-test-submissions.js similarity index 100% rename from lib/model/migrations/20200117-01-draft-test-submissions.js rename to lib/model/migrations/legacy/20200117-01-draft-test-submissions.js diff --git a/lib/model/migrations/20200121-01-add-draft-keys.js b/lib/model/migrations/legacy/20200121-01-add-draft-keys.js similarity index 100% rename from lib/model/migrations/20200121-01-add-draft-keys.js rename to lib/model/migrations/legacy/20200121-01-add-draft-keys.js diff --git a/lib/model/migrations/20200122-01-remove-draft-form-state.js b/lib/model/migrations/legacy/20200122-01-remove-draft-form-state.js similarity index 100% rename from lib/model/migrations/20200122-01-remove-draft-form-state.js rename to lib/model/migrations/legacy/20200122-01-remove-draft-form-state.js diff --git a/lib/model/migrations/20200129-01-cascade-submission-deletes.js b/lib/model/migrations/legacy/20200129-01-cascade-submission-deletes.js similarity index 100% rename from lib/model/migrations/20200129-01-cascade-submission-deletes.js rename to lib/model/migrations/legacy/20200129-01-cascade-submission-deletes.js diff --git a/lib/model/migrations/20200220-01-repair-submission-parsing.js b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js similarity index 100% rename from lib/model/migrations/20200220-01-repair-submission-parsing.js rename to lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js diff --git a/lib/model/migrations/20200403-01-add-performance-indices.js b/lib/model/migrations/legacy/20200403-01-add-performance-indices.js similarity index 100% rename from lib/model/migrations/20200403-01-add-performance-indices.js rename to lib/model/migrations/legacy/20200403-01-add-performance-indices.js diff --git a/lib/model/migrations/20200407-01-allow-actorless-submission-defs.js b/lib/model/migrations/legacy/20200407-01-allow-actorless-submission-defs.js similarity index 100% rename from lib/model/migrations/20200407-01-allow-actorless-submission-defs.js rename to lib/model/migrations/legacy/20200407-01-allow-actorless-submission-defs.js diff --git a/lib/model/migrations/20200423-01-fix-field-insert-performance.js b/lib/model/migrations/legacy/20200423-01-fix-field-insert-performance.js similarity index 100% rename from lib/model/migrations/20200423-01-fix-field-insert-performance.js rename to lib/model/migrations/legacy/20200423-01-fix-field-insert-performance.js diff --git a/lib/model/migrations/20200428-01-allow-string-downcast.js b/lib/model/migrations/legacy/20200428-01-allow-string-downcast.js similarity index 100% rename from lib/model/migrations/20200428-01-allow-string-downcast.js rename to lib/model/migrations/legacy/20200428-01-allow-string-downcast.js diff --git a/lib/model/migrations/20200519-01-add-enketo-id.js b/lib/model/migrations/legacy/20200519-01-add-enketo-id.js similarity index 100% rename from lib/model/migrations/20200519-01-add-enketo-id.js rename to lib/model/migrations/legacy/20200519-01-add-enketo-id.js diff --git a/lib/model/migrations/20200519-02-add-form-viewer-role.js b/lib/model/migrations/legacy/20200519-02-add-form-viewer-role.js similarity index 100% rename from lib/model/migrations/20200519-02-add-form-viewer-role.js rename to lib/model/migrations/legacy/20200519-02-add-form-viewer-role.js diff --git a/lib/model/migrations/20200520-01-backfill-enketo.js b/lib/model/migrations/legacy/20200520-01-backfill-enketo.js similarity index 100% rename from lib/model/migrations/20200520-01-backfill-enketo.js rename to lib/model/migrations/legacy/20200520-01-backfill-enketo.js diff --git a/lib/model/migrations/20200715-01-add-data-collector-role.js b/lib/model/migrations/legacy/20200715-01-add-data-collector-role.js similarity index 100% rename from lib/model/migrations/20200715-01-add-data-collector-role.js rename to lib/model/migrations/legacy/20200715-01-add-data-collector-role.js diff --git a/lib/model/migrations/20200721-01-add-public-links.js b/lib/model/migrations/legacy/20200721-01-add-public-links.js similarity index 100% rename from lib/model/migrations/20200721-01-add-public-links.js rename to lib/model/migrations/legacy/20200721-01-add-public-links.js diff --git a/lib/model/migrations/20200728-01-add-enketo-single-token-to-forms.js b/lib/model/migrations/legacy/20200728-01-add-enketo-single-token-to-forms.js similarity index 100% rename from lib/model/migrations/20200728-01-add-enketo-single-token-to-forms.js rename to lib/model/migrations/legacy/20200728-01-add-enketo-single-token-to-forms.js diff --git a/lib/model/migrations/20200731-01-allow-project-managers-to-end-sessions.js b/lib/model/migrations/legacy/20200731-01-allow-project-managers-to-end-sessions.js similarity index 100% rename from lib/model/migrations/20200731-01-allow-project-managers-to-end-sessions.js rename to lib/model/migrations/legacy/20200731-01-allow-project-managers-to-end-sessions.js diff --git a/lib/model/migrations/20200810-01-reschedule-enketo-processing.js b/lib/model/migrations/legacy/20200810-01-reschedule-enketo-processing.js similarity index 100% rename from lib/model/migrations/20200810-01-reschedule-enketo-processing.js rename to lib/model/migrations/legacy/20200810-01-reschedule-enketo-processing.js diff --git a/lib/model/migrations/20200918-01-repair-publishedat-dates.js b/lib/model/migrations/legacy/20200918-01-repair-publishedat-dates.js similarity index 100% rename from lib/model/migrations/20200918-01-repair-publishedat-dates.js rename to lib/model/migrations/legacy/20200918-01-repair-publishedat-dates.js diff --git a/lib/model/migrations/20200930-01-add-backup-run-verb.js b/lib/model/migrations/legacy/20200930-01-add-backup-run-verb.js similarity index 100% rename from lib/model/migrations/20200930-01-add-backup-run-verb.js rename to lib/model/migrations/legacy/20200930-01-add-backup-run-verb.js diff --git a/lib/model/migrations/20201117-01-remove-deleted-actor-assignments-again.js b/lib/model/migrations/legacy/20201117-01-remove-deleted-actor-assignments-again.js similarity index 100% rename from lib/model/migrations/20201117-01-remove-deleted-actor-assignments-again.js rename to lib/model/migrations/legacy/20201117-01-remove-deleted-actor-assignments-again.js diff --git a/lib/model/migrations/20201207-01-harmonize-submitter-id-columns.js b/lib/model/migrations/legacy/20201207-01-harmonize-submitter-id-columns.js similarity index 100% rename from lib/model/migrations/20201207-01-harmonize-submitter-id-columns.js rename to lib/model/migrations/legacy/20201207-01-harmonize-submitter-id-columns.js diff --git a/lib/model/migrations/20210118-01-add-current-flag-to-submission-defs.js b/lib/model/migrations/legacy/20210118-01-add-current-flag-to-submission-defs.js similarity index 100% rename from lib/model/migrations/20210118-01-add-current-flag-to-submission-defs.js rename to lib/model/migrations/legacy/20210118-01-add-current-flag-to-submission-defs.js diff --git a/lib/model/migrations/20210120-01-instance-names.js b/lib/model/migrations/legacy/20210120-01-instance-names.js similarity index 100% rename from lib/model/migrations/20210120-01-instance-names.js rename to lib/model/migrations/legacy/20210120-01-instance-names.js diff --git a/lib/model/migrations/20210203-01-add-hierarchy-to-actees.js b/lib/model/migrations/legacy/20210203-01-add-hierarchy-to-actees.js similarity index 100% rename from lib/model/migrations/20210203-01-add-hierarchy-to-actees.js rename to lib/model/migrations/legacy/20210203-01-add-hierarchy-to-actees.js diff --git a/lib/model/migrations/20210210-01-add-instanceid-to-submission-defs.js b/lib/model/migrations/legacy/20210210-01-add-instanceid-to-submission-defs.js similarity index 100% rename from lib/model/migrations/20210210-01-add-instanceid-to-submission-defs.js rename to lib/model/migrations/legacy/20210210-01-add-instanceid-to-submission-defs.js diff --git a/lib/model/migrations/20210218-01-add-submission-edit-verbs.js b/lib/model/migrations/legacy/20210218-01-add-submission-edit-verbs.js similarity index 100% rename from lib/model/migrations/20210218-01-add-submission-edit-verbs.js rename to lib/model/migrations/legacy/20210218-01-add-submission-edit-verbs.js diff --git a/lib/model/migrations/20210218-02-add-draft-to-submissions-unique.js b/lib/model/migrations/legacy/20210218-02-add-draft-to-submissions-unique.js similarity index 100% rename from lib/model/migrations/20210218-02-add-draft-to-submissions-unique.js rename to lib/model/migrations/legacy/20210218-02-add-draft-to-submissions-unique.js diff --git a/lib/model/migrations/20210219-01-add-review-state.js b/lib/model/migrations/legacy/20210219-01-add-review-state.js similarity index 100% rename from lib/model/migrations/20210219-01-add-review-state.js rename to lib/model/migrations/legacy/20210219-01-add-review-state.js diff --git a/lib/model/migrations/20210219-02-add-notes-and-index-to-audits.js b/lib/model/migrations/legacy/20210219-02-add-notes-and-index-to-audits.js similarity index 100% rename from lib/model/migrations/20210219-02-add-notes-and-index-to-audits.js rename to lib/model/migrations/legacy/20210219-02-add-notes-and-index-to-audits.js diff --git a/lib/model/migrations/20210324-01-add-submission-edit-verbs-to-managers.js b/lib/model/migrations/legacy/20210324-01-add-submission-edit-verbs-to-managers.js similarity index 100% rename from lib/model/migrations/20210324-01-add-submission-edit-verbs-to-managers.js rename to lib/model/migrations/legacy/20210324-01-add-submission-edit-verbs-to-managers.js diff --git a/lib/model/migrations/20210325-01-remove-project.list-verb.js b/lib/model/migrations/legacy/20210325-01-remove-project.list-verb.js similarity index 100% rename from lib/model/migrations/20210325-01-remove-project.list-verb.js rename to lib/model/migrations/legacy/20210325-01-remove-project.list-verb.js diff --git a/lib/model/migrations/20210408-01-drop-public-link-createdat.js b/lib/model/migrations/legacy/20210408-01-drop-public-link-createdat.js similarity index 100% rename from lib/model/migrations/20210408-01-drop-public-link-createdat.js rename to lib/model/migrations/legacy/20210408-01-drop-public-link-createdat.js diff --git a/lib/model/migrations/20210408-02-backfill-specialized-actor-audits.js b/lib/model/migrations/legacy/20210408-02-backfill-specialized-actor-audits.js similarity index 100% rename from lib/model/migrations/20210408-02-backfill-specialized-actor-audits.js rename to lib/model/migrations/legacy/20210408-02-backfill-specialized-actor-audits.js diff --git a/lib/model/migrations/20210409-01-add-comments.js b/lib/model/migrations/legacy/20210409-01-add-comments.js similarity index 100% rename from lib/model/migrations/20210409-01-add-comments.js rename to lib/model/migrations/legacy/20210409-01-add-comments.js diff --git a/lib/model/migrations/20210409-02-update-review-states.js b/lib/model/migrations/legacy/20210409-02-update-review-states.js similarity index 100% rename from lib/model/migrations/20210409-02-update-review-states.js rename to lib/model/migrations/legacy/20210409-02-update-review-states.js diff --git a/lib/model/migrations/20210423-01-add-name-to-form-def.js b/lib/model/migrations/legacy/20210423-01-add-name-to-form-def.js similarity index 100% rename from lib/model/migrations/20210423-01-add-name-to-form-def.js rename to lib/model/migrations/legacy/20210423-01-add-name-to-form-def.js diff --git a/lib/model/migrations/20210423-02-drop-form-name.js b/lib/model/migrations/legacy/20210423-02-drop-form-name.js similarity index 100% rename from lib/model/migrations/20210423-02-drop-form-name.js rename to lib/model/migrations/legacy/20210423-02-drop-form-name.js diff --git a/lib/model/migrations/20210716-01-config-value-jsonb.js b/lib/model/migrations/legacy/20210716-01-config-value-jsonb.js similarity index 100% rename from lib/model/migrations/20210716-01-config-value-jsonb.js rename to lib/model/migrations/legacy/20210716-01-config-value-jsonb.js diff --git a/lib/model/migrations/20210721-01-add-config-set-verb.js b/lib/model/migrations/legacy/20210721-01-add-config-set-verb.js similarity index 100% rename from lib/model/migrations/20210721-01-add-config-set-verb.js rename to lib/model/migrations/legacy/20210721-01-add-config-set-verb.js diff --git a/lib/model/migrations/20210817-01-disallow-structure-downcast-to-string.js b/lib/model/migrations/legacy/20210817-01-disallow-structure-downcast-to-string.js similarity index 100% rename from lib/model/migrations/20210817-01-disallow-structure-downcast-to-string.js rename to lib/model/migrations/legacy/20210817-01-disallow-structure-downcast-to-string.js diff --git a/lib/model/migrations/20210825-01-add-analytics-read-verb.js b/lib/model/migrations/legacy/20210825-01-add-analytics-read-verb.js similarity index 100% rename from lib/model/migrations/20210825-01-add-analytics-read-verb.js rename to lib/model/migrations/legacy/20210825-01-add-analytics-read-verb.js diff --git a/lib/model/migrations/20210903-01-backfill-encrypted-client-audits.js b/lib/model/migrations/legacy/20210903-01-backfill-encrypted-client-audits.js similarity index 100% rename from lib/model/migrations/20210903-01-backfill-encrypted-client-audits.js rename to lib/model/migrations/legacy/20210903-01-backfill-encrypted-client-audits.js diff --git a/lib/model/migrations/20210927-01-revert-disallow-structure-downcast.js b/lib/model/migrations/legacy/20210927-01-revert-disallow-structure-downcast.js similarity index 100% rename from lib/model/migrations/20210927-01-revert-disallow-structure-downcast.js rename to lib/model/migrations/legacy/20210927-01-revert-disallow-structure-downcast.js diff --git a/lib/model/migrations/20211008-01-track-select-many-options.js b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js similarity index 100% rename from lib/model/migrations/20211008-01-track-select-many-options.js rename to lib/model/migrations/legacy/20211008-01-track-select-many-options.js diff --git a/lib/model/migrations/20211021-remove-hashes-from-audits.js b/lib/model/migrations/legacy/20211021-remove-hashes-from-audits.js similarity index 100% rename from lib/model/migrations/20211021-remove-hashes-from-audits.js rename to lib/model/migrations/legacy/20211021-remove-hashes-from-audits.js diff --git a/lib/model/migrations/20211109-01-add-user-agent-to-submissions.js b/lib/model/migrations/legacy/20211109-01-add-user-agent-to-submissions.js similarity index 100% rename from lib/model/migrations/20211109-01-add-user-agent-to-submissions.js rename to lib/model/migrations/legacy/20211109-01-add-user-agent-to-submissions.js diff --git a/lib/model/migrations/20211114-01-flag-initial-submission-def.js b/lib/model/migrations/legacy/20211114-01-flag-initial-submission-def.js similarity index 100% rename from lib/model/migrations/20211114-01-flag-initial-submission-def.js rename to lib/model/migrations/legacy/20211114-01-flag-initial-submission-def.js diff --git a/lib/model/migrations/20211117-01-add-form-restore-verb.js b/lib/model/migrations/legacy/20211117-01-add-form-restore-verb.js similarity index 100% rename from lib/model/migrations/20211117-01-add-form-restore-verb.js rename to lib/model/migrations/legacy/20211117-01-add-form-restore-verb.js diff --git a/lib/model/migrations/20211129-01-add-purged-details-to-actees.js b/lib/model/migrations/legacy/20211129-01-add-purged-details-to-actees.js similarity index 100% rename from lib/model/migrations/20211129-01-add-purged-details-to-actees.js rename to lib/model/migrations/legacy/20211129-01-add-purged-details-to-actees.js diff --git a/lib/model/migrations/20220121-01-form-cascade-delete.js b/lib/model/migrations/legacy/20220121-01-form-cascade-delete.js similarity index 100% rename from lib/model/migrations/20220121-01-form-cascade-delete.js rename to lib/model/migrations/legacy/20220121-01-form-cascade-delete.js diff --git a/lib/model/migrations/20220121-02-purge-deleted-forms.js b/lib/model/migrations/legacy/20220121-02-purge-deleted-forms.js similarity index 100% rename from lib/model/migrations/20220121-02-purge-deleted-forms.js rename to lib/model/migrations/legacy/20220121-02-purge-deleted-forms.js diff --git a/lib/model/migrations/20220209-01-purge-unneeded-drafts.js b/lib/model/migrations/legacy/20220209-01-purge-unneeded-drafts.js similarity index 100% rename from lib/model/migrations/20220209-01-purge-unneeded-drafts.js rename to lib/model/migrations/legacy/20220209-01-purge-unneeded-drafts.js diff --git a/lib/model/migrations/20220309-01-add-project-description.js b/lib/model/migrations/legacy/20220309-01-add-project-description.js similarity index 100% rename from lib/model/migrations/20220309-01-add-project-description.js rename to lib/model/migrations/legacy/20220309-01-add-project-description.js diff --git a/lib/model/migrations/20220803-01-create-entities-schema.js b/lib/model/migrations/legacy/20220803-01-create-entities-schema.js similarity index 100% rename from lib/model/migrations/20220803-01-create-entities-schema.js rename to lib/model/migrations/legacy/20220803-01-create-entities-schema.js diff --git a/lib/model/migrations/20221003-01-add-dataset-verbs.js b/lib/model/migrations/legacy/20221003-01-add-dataset-verbs.js similarity index 100% rename from lib/model/migrations/20221003-01-add-dataset-verbs.js rename to lib/model/migrations/legacy/20221003-01-add-dataset-verbs.js diff --git a/lib/model/migrations/20221114-01-explict-dataset-publish.js b/lib/model/migrations/legacy/20221114-01-explict-dataset-publish.js similarity index 100% rename from lib/model/migrations/20221114-01-explict-dataset-publish.js rename to lib/model/migrations/legacy/20221114-01-explict-dataset-publish.js diff --git a/lib/model/migrations/20221117-01-check-datasetId-is-null-for-non-file-type.js b/lib/model/migrations/legacy/20221117-01-check-datasetId-is-null-for-non-file-type.js similarity index 100% rename from lib/model/migrations/20221117-01-check-datasetId-is-null-for-non-file-type.js rename to lib/model/migrations/legacy/20221117-01-check-datasetId-is-null-for-non-file-type.js diff --git a/lib/model/migrations/20221118-01-make-entities-columns-not-null.js b/lib/model/migrations/legacy/20221118-01-make-entities-columns-not-null.js similarity index 100% rename from lib/model/migrations/20221118-01-make-entities-columns-not-null.js rename to lib/model/migrations/legacy/20221118-01-make-entities-columns-not-null.js diff --git a/lib/model/migrations/20221208-01-reduce-tz-precision.js b/lib/model/migrations/legacy/20221208-01-reduce-tz-precision.js similarity index 100% rename from lib/model/migrations/20221208-01-reduce-tz-precision.js rename to lib/model/migrations/legacy/20221208-01-reduce-tz-precision.js diff --git a/lib/model/migrations/20230106-01-remove-revision-number.js b/lib/model/migrations/legacy/20230106-01-remove-revision-number.js similarity index 100% rename from lib/model/migrations/20230106-01-remove-revision-number.js rename to lib/model/migrations/legacy/20230106-01-remove-revision-number.js diff --git a/lib/model/migrations/20230109-01-add-form-schema.js b/lib/model/migrations/legacy/20230109-01-add-form-schema.js similarity index 100% rename from lib/model/migrations/20230109-01-add-form-schema.js rename to lib/model/migrations/legacy/20230109-01-add-form-schema.js diff --git a/lib/model/migrations/20230123-01-remove-google-backups.js b/lib/model/migrations/legacy/20230123-01-remove-google-backups.js similarity index 100% rename from lib/model/migrations/20230123-01-remove-google-backups.js rename to lib/model/migrations/legacy/20230123-01-remove-google-backups.js diff --git a/lib/model/migrations/20230126-01-add-entity-indices.js b/lib/model/migrations/legacy/20230126-01-add-entity-indices.js similarity index 100% rename from lib/model/migrations/20230126-01-add-entity-indices.js rename to lib/model/migrations/legacy/20230126-01-add-entity-indices.js diff --git a/lib/model/migrations/20230127-01-rename-entity-created-by.js b/lib/model/migrations/legacy/20230127-01-rename-entity-created-by.js similarity index 100% rename from lib/model/migrations/20230127-01-rename-entity-created-by.js rename to lib/model/migrations/legacy/20230127-01-rename-entity-created-by.js diff --git a/lib/model/migrations/20230324-01-edit-dataset-verbs.js b/lib/model/migrations/legacy/20230324-01-edit-dataset-verbs.js similarity index 100% rename from lib/model/migrations/20230324-01-edit-dataset-verbs.js rename to lib/model/migrations/legacy/20230324-01-edit-dataset-verbs.js diff --git a/lib/model/migrations/20230406-01-add-entity-def-fields.js b/lib/model/migrations/legacy/20230406-01-add-entity-def-fields.js similarity index 100% rename from lib/model/migrations/20230406-01-add-entity-def-fields.js rename to lib/model/migrations/legacy/20230406-01-add-entity-def-fields.js diff --git a/lib/model/migrations/20230406-02-move-entity-label-add-deletedAt.js b/lib/model/migrations/legacy/20230406-02-move-entity-label-add-deletedAt.js similarity index 100% rename from lib/model/migrations/20230406-02-move-entity-label-add-deletedAt.js rename to lib/model/migrations/legacy/20230406-02-move-entity-label-add-deletedAt.js diff --git a/lib/model/migrations/20230414-01-remove-user-mfa-secret.js b/lib/model/migrations/legacy/20230414-01-remove-user-mfa-secret.js similarity index 100% rename from lib/model/migrations/20230414-01-remove-user-mfa-secret.js rename to lib/model/migrations/legacy/20230414-01-remove-user-mfa-secret.js diff --git a/lib/model/migrations/20230419-01-optimize-indices-sub-defs.js b/lib/model/migrations/legacy/20230419-01-optimize-indices-sub-defs.js similarity index 100% rename from lib/model/migrations/20230419-01-optimize-indices-sub-defs.js rename to lib/model/migrations/legacy/20230419-01-optimize-indices-sub-defs.js diff --git a/lib/model/migrations/20230509-01-dataset-approval-flag.js b/lib/model/migrations/legacy/20230509-01-dataset-approval-flag.js similarity index 100% rename from lib/model/migrations/20230509-01-dataset-approval-flag.js rename to lib/model/migrations/legacy/20230509-01-dataset-approval-flag.js diff --git a/lib/model/migrations/20230512-01-add-entity-root.js b/lib/model/migrations/legacy/20230512-01-add-entity-root.js similarity index 100% rename from lib/model/migrations/20230512-01-add-entity-root.js rename to lib/model/migrations/legacy/20230512-01-add-entity-root.js diff --git a/lib/model/migrations/20230512-02-backfill-entity-id.js b/lib/model/migrations/legacy/20230512-02-backfill-entity-id.js similarity index 100% rename from lib/model/migrations/20230512-02-backfill-entity-id.js rename to lib/model/migrations/legacy/20230512-02-backfill-entity-id.js diff --git a/lib/model/migrations/20230512-03-add-entity-source.js b/lib/model/migrations/legacy/20230512-03-add-entity-source.js similarity index 100% rename from lib/model/migrations/20230512-03-add-entity-source.js rename to lib/model/migrations/legacy/20230512-03-add-entity-source.js diff --git a/lib/model/migrations/20230518-01-add-entity-index-to-audits.js b/lib/model/migrations/legacy/20230518-01-add-entity-index-to-audits.js similarity index 100% rename from lib/model/migrations/20230518-01-add-entity-index-to-audits.js rename to lib/model/migrations/legacy/20230518-01-add-entity-index-to-audits.js diff --git a/lib/model/migrations/20230802-01-delete-orphan-submissions.js b/lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js similarity index 100% rename from lib/model/migrations/20230802-01-delete-orphan-submissions.js rename to lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js diff --git a/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js b/lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js similarity index 100% rename from lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js rename to lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js diff --git a/lib/model/migrations/20230824-01-add-entity-version.js b/lib/model/migrations/legacy/20230824-01-add-entity-version.js similarity index 100% rename from lib/model/migrations/20230824-01-add-entity-version.js rename to lib/model/migrations/legacy/20230824-01-add-entity-version.js diff --git a/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js b/lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js similarity index 100% rename from lib/model/migrations/20230830-01-remove-entity-label-from-audits.js rename to lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js diff --git a/lib/model/migrations/20230907-01-opened-form-verb.js b/lib/model/migrations/legacy/20230907-01-opened-form-verb.js similarity index 100% rename from lib/model/migrations/20230907-01-opened-form-verb.js rename to lib/model/migrations/legacy/20230907-01-opened-form-verb.js diff --git a/lib/model/migrations/20231002-01-add-conflict-details.js b/lib/model/migrations/legacy/20231002-01-add-conflict-details.js similarity index 100% rename from lib/model/migrations/20231002-01-add-conflict-details.js rename to lib/model/migrations/legacy/20231002-01-add-conflict-details.js diff --git a/lib/model/migrations/20231013-01-change-entity-error-action.js b/lib/model/migrations/legacy/20231013-01-change-entity-error-action.js similarity index 100% rename from lib/model/migrations/20231013-01-change-entity-error-action.js rename to lib/model/migrations/legacy/20231013-01-change-entity-error-action.js diff --git a/lib/model/migrations/20231208-01-dataset-form-def-actions.js b/lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js similarity index 100% rename from lib/model/migrations/20231208-01-dataset-form-def-actions.js rename to lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js diff --git a/lib/model/migrations/20240215-01-entity-delete-verb.js b/lib/model/migrations/legacy/20240215-01-entity-delete-verb.js similarity index 100% rename from lib/model/migrations/20240215-01-entity-delete-verb.js rename to lib/model/migrations/legacy/20240215-01-entity-delete-verb.js diff --git a/lib/model/migrations/20240215-02-dedupe-verbs.js b/lib/model/migrations/legacy/20240215-02-dedupe-verbs.js similarity index 100% rename from lib/model/migrations/20240215-02-dedupe-verbs.js rename to lib/model/migrations/legacy/20240215-02-dedupe-verbs.js diff --git a/lib/model/migrations/20240312-01-add-dataset-create-verb.js b/lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js similarity index 100% rename from lib/model/migrations/20240312-01-add-dataset-create-verb.js rename to lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js diff --git a/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js b/lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js similarity index 100% rename from lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js rename to lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js diff --git a/lib/model/migrations/20240515-01-entity-tz-precision.js b/lib/model/migrations/legacy/20240515-01-entity-tz-precision.js similarity index 100% rename from lib/model/migrations/20240515-01-entity-tz-precision.js rename to lib/model/migrations/legacy/20240515-01-entity-tz-precision.js diff --git a/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js b/lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js similarity index 100% rename from lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js rename to lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js diff --git a/lib/model/migrations/20240607-02-add-submission-backlog.js b/lib/model/migrations/legacy/20240607-02-add-submission-backlog.js similarity index 100% rename from lib/model/migrations/20240607-02-add-submission-backlog.js rename to lib/model/migrations/legacy/20240607-02-add-submission-backlog.js diff --git a/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js b/lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js similarity index 100% rename from lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js rename to lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js diff --git a/lib/model/migrations/20240913-01-add-blob-s3.js b/lib/model/migrations/legacy/20240913-01-add-blob-s3.js similarity index 100% rename from lib/model/migrations/20240913-01-add-blob-s3.js rename to lib/model/migrations/legacy/20240913-01-add-blob-s3.js diff --git a/lib/model/migrations/20240914-01-add-submission-delete-verb.js b/lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js similarity index 100% rename from lib/model/migrations/20240914-01-add-submission-delete-verb.js rename to lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js diff --git a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js b/lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js similarity index 100% rename from lib/model/migrations/20240914-02-remove-orphaned-client-audits.js rename to lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js diff --git a/lib/model/migrations/20241001-01-index-on-session-table.js b/lib/model/migrations/legacy/20241001-01-index-on-session-table.js similarity index 100% rename from lib/model/migrations/20241001-01-index-on-session-table.js rename to lib/model/migrations/legacy/20241001-01-index-on-session-table.js diff --git a/lib/model/migrations/20241008-01-add-user_preferences.js b/lib/model/migrations/legacy/20241008-01-add-user_preferences.js similarity index 100% rename from lib/model/migrations/20241008-01-add-user_preferences.js rename to lib/model/migrations/legacy/20241008-01-add-user_preferences.js diff --git a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js b/lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js similarity index 100% rename from lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js rename to lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js diff --git a/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js b/lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js similarity index 100% rename from lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js rename to lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js diff --git a/lib/model/migrations/20241030-01-add-force-entity-def-source.js b/lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js similarity index 100% rename from lib/model/migrations/20241030-01-add-force-entity-def-source.js rename to lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js diff --git a/lib/util/db.js b/lib/util/db.js index 918fb3797..91f7ef85b 100644 --- a/lib/util/db.js +++ b/lib/util/db.js @@ -48,7 +48,7 @@ const connectionString = (config) => { }; // Returns an object that Knex will use to connect to the database. -const connectionObject = (config) => { +const knexConfig = (config) => { const problem = validateConfig(config); if (problem != null) throw problem; // We ignore maximumPoolSize when using Knex. @@ -588,7 +588,7 @@ const postgresErrorToProblem = (x) => { }; module.exports = { - connectionString, connectionObject, + connectionString, knexConfig, unjoiner, extender, sqlEquals, page, queryFuncs, insert, insertMany, updater, markDeleted, markUndeleted, QueryOptions, diff --git a/test/unit/util/db.js b/test/unit/util/db.js index 6a804d812..2bed332fe 100644 --- a/test/unit/util/db.js +++ b/test/unit/util/db.js @@ -97,11 +97,11 @@ describe('util/db', () => { }); }); - describe('connectionObject', () => { - const { connectionObject } = util; + describe('knexConfig', () => { + const { knexConfig } = util; it('should return an object with the required options', () => { - const result = connectionObject({ + const result = knexConfig({ host: 'localhost', database: 'foo', user: 'bar', @@ -116,7 +116,7 @@ describe('util/db', () => { }); it('should include the port if one is specified', () => { - const result = connectionObject({ + const result = knexConfig({ host: 'localhost', database: 'foo', user: 'bar', @@ -133,7 +133,7 @@ describe('util/db', () => { }); it('should return the correct object if ssl is true', () => { - const result = connectionObject({ + const result = knexConfig({ host: 'localhost', database: 'foo', user: 'bar', @@ -150,7 +150,7 @@ describe('util/db', () => { }); it('should throw if ssl is false', () => { - const result = () => connectionObject({ + const result = () => knexConfig({ host: 'localhost', database: 'foo', user: 'bar', @@ -161,7 +161,7 @@ describe('util/db', () => { }); it('should throw if ssl is an object', () => { - const result = () => connectionObject({ + const result = () => knexConfig({ host: 'localhost', database: 'foo', user: 'bar', @@ -172,7 +172,7 @@ describe('util/db', () => { }); it('should allow (but ignore) maximumPoolSize', () => { - const result = connectionObject({ + const result = knexConfig({ host: 'localhost', database: 'foo', user: 'bar', @@ -188,7 +188,7 @@ describe('util/db', () => { }); it('should throw for an unsupported option', () => { - const result = () => connectionObject({ + const result = () => knexConfig({ host: 'localhost', database: 'foo', user: 'bar', From 2d9ff155f8bb0b22990f2489ca55affd183916c2 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 09:41:00 +0000 Subject: [PATCH 003/133] Add db migration test from other PR --- ...isable-nullable-blob-content-types.spec.js | 58 +++++++++++++++++ test/db-migrations/utils.js | 63 +++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js diff --git a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js new file mode 100644 index 000000000..e3fb41c03 --- /dev/null +++ b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js @@ -0,0 +1,58 @@ +const assert = require('node:assert/strict'); +const { hash, randomBytes } = require('node:crypto'); + +const { // eslint-disable-line object-curly-newline + assertTableContents, + describeMigration, + rowsExistFor, +} = require('./utils'); // eslint-disable-line object-curly-newline + +describeMigration('20250113-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { + const aBlobWith = props => { + const randomContent = randomBytes(100); + const md5 = hash('md5', randomContent); // eslint-disable-line no-multi-spaces + const sha = hash('sha1', randomContent); + return { md5, sha, ...props }; + }; + const aBlob = () => aBlobWith({}); + + const blob1 = aBlobWith({ contentType: null }); + const blob2 = aBlobWith({ contentType: 'text/plain' }); + + before(async () => { + await rowsExistFor('blobs', blob1, blob2); + + await runMigrationBeingTested(); + }); + + it('should change existing NULL contentType values to application/octet-stream, and preserve non-NULL values', async () => { + await assertTableContents('blobs', + { ...blob1, contentType: 'application/octet-stream' }, + { ...blob2, contentType: 'text/plain' }, + ); + }); + + it(`should create new blobs with contentType 'application/octet-stream' (contentType not supplied)`, async () => { + const { md5, sha } = aBlob(); + + const created = await db.oneFirst(sql` + INSERT INTO blobs (md5, sha, "contentType") + VALUES(${md5}, ${sha}, DEFAULT) + RETURNING "contentType" + `); + + assert.equal(created, 'application/octet-stream'); + }); + + it(`should create new blobs with contentType 'application/octet-stream' (supplied DEFAULT contentType)`, async () => { + const { md5, sha } = aBlob(); + + const created = await db.oneFirst(sql` + INSERT INTO blobs (md5, sha, "contentType") + VALUES(${md5}, ${sha}, DEFAULT) + RETURNING "contentType" + `); + + assert.equal(created, 'application/octet-stream'); + }); +}); diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index 85788ea01..43e811d2d 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -115,9 +115,72 @@ function assertIncludes(actual, expected) { } } +async function rowsExistFor(tableName, ...rows) { + if (!rows.length) throw new Error(`Attempted to insert 0 rows into table ${tableName}`); + + assertAllHaveSameProps(rows); // eslint-disable-line no-use-before-define + const colNames = Object.keys(rows[0]); + if (!colNames.length) throw new Error(`Attempted to insert data with 0 defined columns`); + + const table = sql.identifier([tableName]); + const cols = sql.join(colNames.map(k => sql.identifier([k])), sql`,`); + + return db.query( + sql` + INSERT INTO ${table} (${cols}) + SELECT ${cols} + FROM JSON_POPULATE_RECORDSET(NULL::${table}, ${JSON.stringify(rows)}) + `, + ); +} + +async function assertTableContents(tableName, ...expected) { + const { rows: actual } = await db.query(sql`SELECT * FROM ${sql.identifier([tableName])}`); + + assert.equal( + actual.length, + expected.length, + `Unexpected number of rows in table '${tableName}'. ` + + `Expected ${expected.length} but got ${actual.length}. ` + + `DB returned: ${JSON.stringify(actual, null, 2)}`, + ); + + const remainingRows = [ ...actual ]; + for (let i=0; i _.pick(r, Object.keys(x))); + assert.fail(`Expected row ${i} not found in table '${tableName}':\n json=${JSON.stringify({ remainingRows, filteredRemainingRows, expectedRow: x })}`); + } + } +} + +function assertAllHaveSameProps(list) { + if (list.length < 2) return; + const [ first, ...rest ] = list.map(Object.keys); + + rest.forEach((v, i) => { + assert.deepEqual(v, first, `Row #${i+1} has different props to row #0. All supplied rows must have the same props.`); + }); +} + module.exports = { assertIndexExists, + assertTableContents, assertTableDoesNotExist, assertTableSchema, + describeMigration, + + rowsExistFor, }; From 42023e07153c7752118b8a0c91a2204ef7885159 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 09:49:49 +0000 Subject: [PATCH 004/133] fix imports; lints --- lib/bin/run-migrations.js | 4 +-- lib/model/migrate.js | 35 +++++++++---------- .../legacy/20180727-02-add-md5-to-blobs.js | 2 +- .../20180727-03-add-form-attachments-table.js | 2 +- .../legacy/20190520-01-add-form-versioning.js | 2 +- .../20191007-01-backfill-client-audits.js | 6 ++-- .../legacy/20191231-02-add-schema-storage.js | 4 +-- .../20200220-01-repair-submission-parsing.js | 2 +- .../legacy/20210120-01-instance-names.js | 2 +- .../20211008-01-track-select-many-options.js | 8 ++--- .../legacy/20230109-01-add-form-schema.js | 2 +- lib/task/task.js | 4 +-- lib/util/db.js | 8 ++--- 13 files changed, 40 insertions(+), 41 deletions(-) diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index 93324f8c6..10e9d3edd 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { +const { // eslint-disable-line object-curly-newline withKnex, knexMigrations, postKnexMigrations, -} = require('../model/migrate'); +} = require('../model/migrate'); // eslint-disable-line object-curly-newline (async () => { try { diff --git a/lib/model/migrate.js b/lib/model/migrate.js index 53c3b9ec7..982ea1bc6 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -12,10 +12,9 @@ const { lstatSync, readdirSync } = require('node:fs'); -const _ = require('lodash'); +const _ = require('lodash'); // eslint-disable-line import/no-extraneous-dependencies const knex = require('knex'); const pg = require('pg'); -const { Migrator } = require('knex/lib/migrate/Migrator'); const { knexConfig } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. @@ -31,7 +30,7 @@ const withKnex = (config) => (mutator) => { const knexMigrations = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy` }); const postKnexMigrations = async (config) => { - const log = (...args) => console.log('[postKnexMigrations]', ...args); + const log = (...args) => console.log('[postKnexMigrations]', ...args); // eslint-disable-line no-console log('ENTRY'); const { Client } = pg; @@ -74,10 +73,11 @@ const postKnexMigrations = async (config) => { // N.B. this table is created to be similar to the legacy knex-created table. // The key difference is that name, batch and migration_time columns are // not nullable. + const maxLen = 255; await client.query(` CREATE TABLE IF NOT EXISTS post_knex_migrations ( id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, + name VARCHAR(${maxLen}) NOT NULL, batch INTEGER NOT NULL, migration_time TIMESTAMP(3) WITH TIME ZONE NOT NULL )`); @@ -89,8 +89,8 @@ const postKnexMigrations = async (config) => { const migrationsDir = `${__dirname}/migrations`; const allMigrations = readdirSync(migrationsDir) - .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) - .sort(); + .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) + .sort(); log('allMigrations:', allMigrations); const alreadyRun = (await client.query('SELECT name FROM post_knex_migrations')).rows.map(r => r.name); @@ -101,35 +101,35 @@ const postKnexMigrations = async (config) => { const toRun = toRunNames.map(name => { const path = `${migrationsDir}/${name}`; - const migration = require(path); + const migration = require(path); // eslint-disable-line import/no-dynamic-require return { name, path, migration }; }); log('toRun:', toRun); - if(!toRun.length) { + if (!toRun.length) { log('No migrations to run - exiting.'); await client.query('ROLLBACK'); return; } log('Validating', toRun.length, 'migrations...'); - for(const { migration, name, path } of toRun) { + for (const { migration, name } of toRun) { log('Validing migration:', name, '...'); - if(name.length > 255) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); + if (name.length > maxLen) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); // TODO check for illegal chars in name? const keys = Object.keys(migration); const unexpectedKeys = _.omit(keys, 'up', 'down'); - if(unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); + if (unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); - if(!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); - if(typeof migration.up !== 'function') { + if (!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); + if (typeof migration.up !== 'function') { throw new Error(`Required prop .up of migration ${name} has incorrect type - expected 'function', but got '${typeof migration.up}'`); } - if(migration.down && typeof migration.down !== 'function') { + if (migration.down && typeof migration.down !== 'function') { throw new Error(`Optional prop .down of migration ${name} has incorrect type - expected 'function' but got '${typeof migration.down}'`); } @@ -138,9 +138,9 @@ const postKnexMigrations = async (config) => { log(toRun.length, 'migrations look valid.'); log('Running', toRun.length, 'migrations...'); - for (const { migration, name, path } of toRun) { + for (const { migration, name } of toRun) { log('Running migration:', name); - await migration.up(client); + await migration.up(client); // eslint-disable-line no-await-in-loop log('Migration complete:', name); } log(toRun.length, 'migrations ran OK.'); @@ -150,7 +150,7 @@ const postKnexMigrations = async (config) => { // Note that migration_time is CLOCK_TIMESTAMP() to match knex implementation. // TODO confirm in relevant version of knex source code that this is actually the case, and link here. - const namesJson = JSON.stringify(toRun.map(m => m.name)); + const namesJson = JSON.stringify(toRun.map(m => m.name)); // See: https://www.postgresql.org/docs/current/functions-json.html await client.query(` INSERT INTO post_knex_migrations(name, batch, migration_time) @@ -183,4 +183,3 @@ const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migra }); module.exports = { checkMigrations, initKnex, withKnex, knexMigrations, postKnexMigrations }; - diff --git a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js index de05f99a4..8c487f7ae 100644 --- a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js +++ b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. // -const { md5sum } = require('../../util/crypto'); +const { md5sum } = require('../../../util/crypto'); const up = (knex) => knex.schema.table('blobs', (blobs) => { blobs.string('md5', 32); }) diff --git a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js index 80aea61ab..1633829ae 100644 --- a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js +++ b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js @@ -23,7 +23,7 @@ const up = (knex) => fa.index([ 'formId' ]); }).then(() => { - const { expectedFormAttachments } = require('../../data/schema'); + const { expectedFormAttachments } = require('../../../data/schema'); const { uniq, pluck } = require('ramda'); // now add all expected attachments on extant forms. diff --git a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js index 2d11c8ce3..8b8e9c490 100644 --- a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js +++ b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { shasum, sha256sum } = require('../../util/crypto'); +const { shasum, sha256sum } = require('../../../util/crypto'); const assert = require('assert').strict; const check = (message, query) => diff --git a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js index c6551c255..9067ccc06 100644 --- a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js +++ b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js @@ -7,9 +7,9 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { parseClientAudits } = require('../../data/client-audits'); -const { getFormFields } = require('../../data/schema'); -const { traverseXml, findOne, root, node, text } = require('../../util/xml'); +const { parseClientAudits } = require('../../../data/client-audits'); +const { getFormFields } = require('../../../data/schema'); +const { traverseXml, findOne, root, node, text } = require('../../../util/xml'); const up = (db) => new Promise((resolve, reject) => { const work = []; diff --git a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js index ec317539e..f331a1eaa 100644 --- a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields } = require('../../data/schema'); +const { getFormFields } = require('../../../data/schema'); const up = async (db) => { await db.schema.createTable('form_fields', (fields) => { @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../migrate').connect(config); + const db2 = require('../../migrate').connect(config); return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js index d1bd9e0ee..f6f671ef3 100644 --- a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js +++ b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../frames'); +const { Submission } = require('../../frames'); const up = async (db) => { const work = []; diff --git a/lib/model/migrations/legacy/20210120-01-instance-names.js b/lib/model/migrations/legacy/20210120-01-instance-names.js index 832407dfc..36c625343 100644 --- a/lib/model/migrations/legacy/20210120-01-instance-names.js +++ b/lib/model/migrations/legacy/20210120-01-instance-names.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../frames'); +const { Submission } = require('../../frames'); const up = async (db) => { await db.schema.table('submission_defs', (sds) => { diff --git a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js index 413e0f1aa..caa466186 100644 --- a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js +++ b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const { map } = require('ramda'); -const { getFormFields } = require('../../data/schema'); -const { getSelectMultipleResponses } = require('../../data/submission'); -const { Form } = require('../frames'); -const { construct } = require('../../util/util'); +const { getFormFields } = require('../../../data/schema'); +const { getSelectMultipleResponses } = require('../../../data/submission'); +const { Form } = require('../../frames'); +const { construct } = require('../../../util/util'); const up = async (db) => { // add select many flag, options field to fields diff --git a/lib/model/migrations/legacy/20230109-01-add-form-schema.js b/lib/model/migrations/legacy/20230109-01-add-form-schema.js index 3f591473e..40013f840 100644 --- a/lib/model/migrations/legacy/20230109-01-add-form-schema.js +++ b/lib/model/migrations/legacy/20230109-01-add-form-schema.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields, compare } = require('../../data/schema'); +const { getFormFields, compare } = require('../../../data/schema'); /* Steps of this migration 1. remove check field collision trigger diff --git a/lib/task/task.js b/lib/task/task.js index f72fa23e2..6f9a1eb13 100644 --- a/lib/task/task.js +++ b/lib/task/task.js @@ -75,7 +75,7 @@ const writeTo = (output) => (x) => output.write(`${x}\n`); const writeToStderr = writeTo(process.stderr); /* istanbul ignore next */ const fault = (error) => { - console.log('fault()', error); + console.log('fault()', error); // eslint-disable-line no-console // first print our error. if ((error != null) && (error.isProblem === true) && (error.httpCode < 500)) { writeToStderr(error.message); @@ -106,7 +106,7 @@ const auditing = (action, t) => ((typeof t === 'function') return Promise.resolve(result); }) )), - ((error) => console.log('auditing() error', error) || auditLog(action, false, Option.of(error).map(Problem.serializable).orNull()).then( + ((error) => console.log('auditing() error', error) || auditLog(action, false, Option.of(error).map(Problem.serializable).orNull()).then( // eslint-disable-line no-console (() => Promise.reject(error)), ((auditError) => { writeToStderr('Failed to audit-log task failure message!'); diff --git a/lib/util/db.js b/lib/util/db.js index 91f7ef85b..b85e6b9e3 100644 --- a/lib/util/db.js +++ b/lib/util/db.js @@ -52,16 +52,16 @@ const knexConfig = (config) => { const problem = validateConfig(config); if (problem != null) throw problem; // We ignore maximumPoolSize when using Knex. - const { maximumPoolSize, ...knexConfig } = config; - if (knexConfig.ssl === true) { + const { maximumPoolSize, ...rest } = config; + if (rest.ssl === true) { // Slonik seems to specify `false` for `rejectUnauthorized` whenever SSL is // specified: // https://github.com/gajus/slonik/issues/159#issuecomment-891089466. We do // the same here so that Knex will connect to the database in the same way // as Slonik. - knexConfig.ssl = { rejectUnauthorized: false }; + rest.ssl = { rejectUnauthorized: false }; } - return knexConfig; + return rest; }; From c838cf6c4a72e69c51e989924cbfe140b43ebd2a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:04:41 +0000 Subject: [PATCH 005/133] Add eslint rules --- lib/model/migrations/.eslintrc.json | 9 +++++++++ lib/model/migrations/legacy/.eslintrc.json | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 lib/model/migrations/.eslintrc.json create mode 100644 lib/model/migrations/legacy/.eslintrc.json diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/.eslintrc.json new file mode 100644 index 000000000..ca7bff3bc --- /dev/null +++ b/lib/model/migrations/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../.eslintrc.json", + "rules": { + "no-restricted-modules": [ + "error", + { "patterns": [ "../*" ] } + ] + } +} diff --git a/lib/model/migrations/legacy/.eslintrc.json b/lib/model/migrations/legacy/.eslintrc.json new file mode 100644 index 000000000..27d39fc27 --- /dev/null +++ b/lib/model/migrations/legacy/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../../.eslintrc.json", + "rules": { + "no-restricted-modules": [ + "warn", + { "patterns": [ "../*" ] } + ] + } +} From a9aea26a8f4c0aaf86c5a2377401e59dbc674686 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:05:00 +0000 Subject: [PATCH 006/133] whitespace --- lib/model/migrations/.eslintrc.json | 12 ++++++------ lib/model/migrations/legacy/.eslintrc.json | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/.eslintrc.json index ca7bff3bc..f34c5819a 100644 --- a/lib/model/migrations/.eslintrc.json +++ b/lib/model/migrations/.eslintrc.json @@ -1,9 +1,9 @@ { "extends": "../../../.eslintrc.json", - "rules": { - "no-restricted-modules": [ - "error", - { "patterns": [ "../*" ] } - ] - } + "rules": { + "no-restricted-modules": [ + "error", + { "patterns": [ "../*" ] } + ] + } } diff --git a/lib/model/migrations/legacy/.eslintrc.json b/lib/model/migrations/legacy/.eslintrc.json index 27d39fc27..4fe3ba4a9 100644 --- a/lib/model/migrations/legacy/.eslintrc.json +++ b/lib/model/migrations/legacy/.eslintrc.json @@ -1,9 +1,9 @@ { "extends": "../../../../.eslintrc.json", - "rules": { - "no-restricted-modules": [ - "warn", - { "patterns": [ "../*" ] } - ] - } + "rules": { + "no-restricted-modules": [ + "warn", + { "patterns": [ "../*" ] } + ] + } } From 609c34c7da0fcbdc2800dbd006c67e5a607ca8a8 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:06:56 +0000 Subject: [PATCH 007/133] rename withDatabase() --- lib/bin/check-open-db-queries.js | 4 ++-- .../other/{migrations.js => knex-migrations.js} | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) rename test/integration/other/{migrations.js => knex-migrations.js} (99%) diff --git a/lib/bin/check-open-db-queries.js b/lib/bin/check-open-db-queries.js index 603776d09..3299f839a 100644 --- a/lib/bin/check-open-db-queries.js +++ b/lib/bin/check-open-db-queries.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withDatabase } = require('../model/migrate'); +const { withKnex } = require('../model/migrate'); (async () => { try { - const { rows } = await withDatabase(require('config').get('default.database'))((db) => + const { rows } = await withKnex(require('config').get('default.database'))((db) => db.raw('SELECT COUNT(*) FROM pg_stat_activity WHERE usename=CURRENT_USER')); const queryCount = rows[0].count - 1; // the count query will appear as one of the open queries diff --git a/test/integration/other/migrations.js b/test/integration/other/knex-migrations.js similarity index 99% rename from test/integration/other/migrations.js rename to test/integration/other/knex-migrations.js index b582c83da..9b51e3aac 100644 --- a/test/integration/other/migrations.js +++ b/test/integration/other/knex-migrations.js @@ -6,7 +6,7 @@ const { testContainerFullTrx, testServiceFullTrx } = require('../setup'); const { sql } = require('slonik'); const { createReadStream } = require('fs'); const { Actor, Config } = require(appRoot + '/lib/model/frames'); -const { withDatabase } = require(appRoot + '/lib/model/migrate'); +const { withKnex } = require(appRoot + '/lib/model/migrate'); const { exhaust } = require(appRoot + '/lib/worker/worker'); const testData = require('../../data/xml'); @@ -14,8 +14,8 @@ const populateUsers = require('../fixtures/01-users'); const populateForms = require('../fixtures/02-forms'); const { getFormFields } = require('../../../lib/data/schema'); -const withTestDatabase = withDatabase(config.get('test.database')); -const migrationsDir = appRoot + '/lib/model/migrations'; +const withTestDatabase = withKnex(config.get('test.database')); +const migrationsDir = appRoot + '/lib/model/migrations/legacy'; const upToMigration = (toName, inclusive = true) => withTestDatabase(async (migrator) => { await migrator.raw('drop owned by current_user'); const migrations = await migrator.migrate.list({ directory: migrationsDir }); @@ -59,7 +59,7 @@ testMigration.skip = (filename, tests) => // column to projects and forms, it is not possible to migrate part way // (before the new column) and populate the data when frames expect the // new column to exist. -describe.skip('database migrations', function() { +describe.skip('legacy (knex) database migrations', function() { this.timeout(8000); it('should purge deleted forms via migration', testServiceFullTrx(async (service, container) => { From c2ce4baf713e6ca80327008014fd4913f363a1af Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:11:18 +0000 Subject: [PATCH 008/133] lint? --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8760c350e..22921d682 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,8 @@ test-coverage: node_version .PHONY: lint lint: node_version - npx eslint --cache --max-warnings 0 . + # max-warnings set to take account of legacy database migrations + npx eslint --cache --max-warnings 15 . ################################################################################ From 714985f332392b14ee3dd53e507ab9c40def6be9 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:26:26 +0000 Subject: [PATCH 009/133] make sure client closed --- lib/bin/check-migrations.js | 6 ++- lib/model/migrate.js | 98 +++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/lib/bin/check-migrations.js b/lib/bin/check-migrations.js index 20b9c5e82..65180cd11 100644 --- a/lib/bin/check-migrations.js +++ b/lib/bin/check-migrations.js @@ -7,11 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex, checkMigrations } = require('../model/migrate'); +const { withKnex, checkKnexMigrations, checkPostKnexMigrations } = require('../model/migrate'); (async () => { try { - await withKnex(require('config').get('default.database'))(checkMigrations); + const config = require('config').get('default.database'); + await withKnex(config)(checkKnexMigrations); + await checkPostKnexMigrations(config); } catch (err) { console.error('Error:', err.message); process.exit(1); diff --git a/lib/model/migrate.js b/lib/model/migrate.js index 982ea1bc6..fa436665d 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -20,6 +20,9 @@ const { knexConfig } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. const initKnex = (config) => knex({ client: 'pg', connection: knexConfig(config) }); +const legacyPath = `${__dirname}/migrations/legacy`; +const postKnexPath = `${__dirname}/migrations`; + // Connects to a database, passes it to a function for operations, then ensures its closure. const withKnex = (config) => (mutator) => { const db = initKnex(config); @@ -27,10 +30,10 @@ const withKnex = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -const knexMigrations = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy` }); +const knexMigrations = (db) => db.migrate.latest({ directory: legacyPath }); -const postKnexMigrations = async (config) => { - const log = (...args) => console.log('[postKnexMigrations]', ...args); // eslint-disable-line no-console +const getPostKnexClient = async config => { + const log = (...args) => console.log('[getPostKnexClient]', ...args); // eslint-disable-line no-console log('ENTRY'); const { Client } = pg; @@ -38,6 +41,45 @@ const postKnexMigrations = async (config) => { log('client created'); + log('Connecting to client...'); + await client.connect(); + log('Client connected OK.'); + + return client; +}; + +const getPostKnexMigrationsToRun = async client => { + const log = (...args) => console.log('[getPostKnexMigrationsToRun]', ...args); // eslint-disable-line no-console + log('ENTRY'); + + const migrationsDir = postKnexPath; + const allMigrations = readdirSync(migrationsDir) + .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) + .sort(); + log('allMigrations:', allMigrations); + + const alreadyRun = (await client.query('SELECT name FROM post_knex_migrations')).rows.map(r => r.name); + log('alreadyRun:', alreadyRun); + + const toRunNames = allMigrations.filter(m => !alreadyRun.includes(m)); + log('toRunNames:', toRunNames); + + const toRun = toRunNames.map(name => { + const path = `${migrationsDir}/${name}`; + const migration = require(path); // eslint-disable-line import/no-dynamic-require + return { name, path, migration }; + }); + log('toRun:', toRun); + + return toRun; +}; + +const postKnexMigrations = async (config) => { + const log = (...args) => console.log('[postKnexMigrations]', ...args); // eslint-disable-line no-console + log('ENTRY'); + + const client = await getPostKnexClient(config); + // In the main, this migrator is written to behave similarly to knex's: // // * expects transaction property async .up({ raw }) @@ -53,14 +95,6 @@ const postKnexMigrations = async (config) => { // * sets migration_time to be the start of the migration batch's transaction rather than some other intermediate time try { - log('Connecting to client...'); - await client.connect(); - log('Client connected OK.'); - - log('Testing client...'); - const res = await client.query('SELECT NOW()'); - log('Client returned:', res); - log('Starting transaction...'); await client.query('BEGIN'); // TODO do we need a specific transaction type? log('Transaction started.'); @@ -87,24 +121,7 @@ const postKnexMigrations = async (config) => { await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); log('Lock acquired.'); - const migrationsDir = `${__dirname}/migrations`; - const allMigrations = readdirSync(migrationsDir) - .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) - .sort(); - log('allMigrations:', allMigrations); - - const alreadyRun = (await client.query('SELECT name FROM post_knex_migrations')).rows.map(r => r.name); - log('alreadyRun:', alreadyRun); - - const toRunNames = allMigrations.filter(m => !alreadyRun.includes(m)); - log('toRunNames:', toRunNames); - - const toRun = toRunNames.map(name => { - const path = `${migrationsDir}/${name}`; - const migration = require(path); // eslint-disable-line import/no-dynamic-require - return { name, path, migration }; - }); - log('toRun:', toRun); + const toRun = getPostKnexMigrationsToRun(client); if (!toRun.length) { log('No migrations to run - exiting.'); @@ -169,17 +186,34 @@ const postKnexMigrations = async (config) => { throw err; } finally { log('Ending client...'); - await client.end(); // TODO needs await or callback? + await client.end(); log('Client ended.'); } }; // Checks for pending migrations and returns an exit code of 1 if any are // still pending/unapplied (e.g. automatically running migrations just failed). -const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migrations` }) +const checkKnexMigrations = (db) => db.migrate.list({ directory: legacyPath }) .then((res) => { if (res[1].length > 0) process.exitCode = 1; }); -module.exports = { checkMigrations, initKnex, withKnex, knexMigrations, postKnexMigrations }; +// Checks for pending migrations and returns an exit code of 1 if any are +// still pending/unapplied (e.g. automatically running migrations just failed). +const checkPostKnexMigrations = async config => { + const log = (...args) => console.log('[checkPostKnexMigrations]', ...args); // eslint-disable-line no-console + log('ENTRY'); + + const client = await getPostKnexClient(config); + try { + const toRun = await getPostKnexMigrationsToRun(client); + if (toRun.length) process.exitCode = 1; + } finally { + log('Ending client...'); + await client.end(); + log('Client ended.'); + } +}; + +module.exports = { checkKnexMigrations, checkPostKnexMigrations, initKnex, withKnex, knexMigrations, postKnexMigrations }; From 72bb6b0436e1e02c8177d0beb832b9068ae1f71c Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:28:17 +0000 Subject: [PATCH 010/133] add comment --- lib/bin/check-migrations.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/bin/check-migrations.js b/lib/bin/check-migrations.js index 65180cd11..2119c203d 100644 --- a/lib/bin/check-migrations.js +++ b/lib/bin/check-migrations.js @@ -9,6 +9,8 @@ const { withKnex, checkKnexMigrations, checkPostKnexMigrations } = require('../model/migrate'); +// REVIEW why is check-migrations required in the first place? + (async () => { try { const config = require('config').get('default.database'); From 65e7709e1b77e487c885e7f0feaa5c821fa1fa76 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:31:53 +0000 Subject: [PATCH 011/133] await --- lib/model/migrate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model/migrate.js b/lib/model/migrate.js index fa436665d..dccdc5057 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -121,7 +121,7 @@ const postKnexMigrations = async (config) => { await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); log('Lock acquired.'); - const toRun = getPostKnexMigrationsToRun(client); + const toRun = await getPostKnexMigrationsToRun(client); if (!toRun.length) { log('No migrations to run - exiting.'); From 2fceecfd1d805ce5cf80751b65423a35f8a6f91f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:35:53 +0000 Subject: [PATCH 012/133] handle connection closing --- lib/model/migrate.js | 189 +++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 96 deletions(-) diff --git a/lib/model/migrate.js b/lib/model/migrate.js index dccdc5057..d940771f1 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -32,8 +32,8 @@ const withKnex = (config) => (mutator) => { // Given a database, initiates migrations on it. const knexMigrations = (db) => db.migrate.latest({ directory: legacyPath }); -const getPostKnexClient = async config => { - const log = (...args) => console.log('[getPostKnexClient]', ...args); // eslint-disable-line no-console +const withPg = async (config, fn) => { + const log = (...args) => console.log('[withPg]', ...args); // eslint-disable-line no-console log('ENTRY'); const { Client } = pg; @@ -45,7 +45,13 @@ const getPostKnexClient = async config => { await client.connect(); log('Client connected OK.'); - return client; + try { + await fn(client); + } finally { + log('Ending client...'); + await client.end(); + log('Client ended.'); + } }; const getPostKnexMigrationsToRun = async client => { @@ -78,8 +84,6 @@ const postKnexMigrations = async (config) => { const log = (...args) => console.log('[postKnexMigrations]', ...args); // eslint-disable-line no-console log('ENTRY'); - const client = await getPostKnexClient(config); - // In the main, this migrator is written to behave similarly to knex's: // // * expects transaction property async .up({ raw }) @@ -94,101 +98,99 @@ const postKnexMigrations = async (config) => { // * gets list of migrations to run _after_ acquiring db lock // * sets migration_time to be the start of the migration batch's transaction rather than some other intermediate time - try { - log('Starting transaction...'); - await client.query('BEGIN'); // TODO do we need a specific transaction type? - log('Transaction started.'); - - log('Acquiring knex lock...'); - // TODO do this... if it's useful. Need to think of _some_ way to prevent new migrations and old migrations running simultaneously. - log('Knex lock acquired'); - - log('Creating new table if not exists...'); - // N.B. this table is created to be similar to the legacy knex-created table. - // The key difference is that name, batch and migration_time columns are - // not nullable. - const maxLen = 255; - await client.query(` - CREATE TABLE IF NOT EXISTS post_knex_migrations ( - id SERIAL PRIMARY KEY, - name VARCHAR(${maxLen}) NOT NULL, - batch INTEGER NOT NULL, - migration_time TIMESTAMP(3) WITH TIME ZONE NOT NULL - )`); - log('Table now definitely exists.'); - - log('Acquiring lock on post_knex_migrations table...'); - await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); - log('Lock acquired.'); + await withPg(config, async client => { + try { + log('Starting transaction...'); + await client.query('BEGIN'); // TODO do we need a specific transaction type? + log('Transaction started.'); + + log('Acquiring knex lock...'); + // TODO do this... if it's useful. Need to think of _some_ way to prevent new migrations and old migrations running simultaneously. + log('Knex lock acquired'); + + log('Creating new table if not exists...'); + // N.B. this table is created to be similar to the legacy knex-created table. + // The key difference is that name, batch and migration_time columns are + // not nullable. + const maxLen = 255; + await client.query(` + CREATE TABLE IF NOT EXISTS post_knex_migrations ( + id SERIAL PRIMARY KEY, + name VARCHAR(${maxLen}) NOT NULL, + batch INTEGER NOT NULL, + migration_time TIMESTAMP(3) WITH TIME ZONE NOT NULL + )`); + log('Table now definitely exists.'); + + log('Acquiring lock on post_knex_migrations table...'); + await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); + log('Lock acquired.'); + + const toRun = await getPostKnexMigrationsToRun(client); + + if (!toRun.length) { + log('No migrations to run - exiting.'); + await client.query('ROLLBACK'); + return; + } - const toRun = await getPostKnexMigrationsToRun(client); + log('Validating', toRun.length, 'migrations...'); + for (const { migration, name } of toRun) { + log('Validing migration:', name, '...'); - if (!toRun.length) { - log('No migrations to run - exiting.'); - await client.query('ROLLBACK'); - return; - } + if (name.length > maxLen) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); - log('Validating', toRun.length, 'migrations...'); - for (const { migration, name } of toRun) { - log('Validing migration:', name, '...'); + // TODO check for illegal chars in name? - if (name.length > maxLen) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); + const keys = Object.keys(migration); + const unexpectedKeys = _.omit(keys, 'up', 'down'); + if (unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); - // TODO check for illegal chars in name? + if (!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); + if (typeof migration.up !== 'function') { + throw new Error(`Required prop .up of migration ${name} has incorrect type - expected 'function', but got '${typeof migration.up}'`); + } - const keys = Object.keys(migration); - const unexpectedKeys = _.omit(keys, 'up', 'down'); - if (unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); + if (migration.down && typeof migration.down !== 'function') { + throw new Error(`Optional prop .down of migration ${name} has incorrect type - expected 'function' but got '${typeof migration.down}'`); + } - if (!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); - if (typeof migration.up !== 'function') { - throw new Error(`Required prop .up of migration ${name} has incorrect type - expected 'function', but got '${typeof migration.up}'`); + log('Migration', name, 'looks valid.'); } + log(toRun.length, 'migrations look valid.'); - if (migration.down && typeof migration.down !== 'function') { - throw new Error(`Optional prop .down of migration ${name} has incorrect type - expected 'function' but got '${typeof migration.down}'`); + log('Running', toRun.length, 'migrations...'); + for (const { migration, name } of toRun) { + log('Running migration:', name); + await migration.up(client); // eslint-disable-line no-await-in-loop + log('Migration complete:', name); } - - log('Migration', name, 'looks valid.'); - } - log(toRun.length, 'migrations look valid.'); - - log('Running', toRun.length, 'migrations...'); - for (const { migration, name } of toRun) { - log('Running migration:', name); - await migration.up(client); // eslint-disable-line no-await-in-loop - log('Migration complete:', name); + log(toRun.length, 'migrations ran OK.'); + + const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM post_knex_migrations`)).rows[0]; + log('lastBatch:', lastBatch); + + // Note that migration_time is CLOCK_TIMESTAMP() to match knex implementation. + // TODO confirm in relevant version of knex source code that this is actually the case, and link here. + const namesJson = JSON.stringify(toRun.map(m => m.name)); + // See: https://www.postgresql.org/docs/current/functions-json.html + await client.query(` + INSERT INTO post_knex_migrations(name, batch, migration_time) + SELECT value#>>'{}' AS name + , ${lastBatch + 1} AS batch + , CLOCK_TIMESTAMP() AS migration_time + FROM JSON_ARRAY_ELEMENTS($1) + `, [ namesJson ]); + + log('Committing migrations...'); + await client.query('COMMIT'); + log('Migrations committed.'); + } catch (err) { + log('Caught error; rolling back', err); + await client.query('ROLLBACK'); + throw err; } - log(toRun.length, 'migrations ran OK.'); - - const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM post_knex_migrations`)).rows[0]; - log('lastBatch:', lastBatch); - - // Note that migration_time is CLOCK_TIMESTAMP() to match knex implementation. - // TODO confirm in relevant version of knex source code that this is actually the case, and link here. - const namesJson = JSON.stringify(toRun.map(m => m.name)); - // See: https://www.postgresql.org/docs/current/functions-json.html - await client.query(` - INSERT INTO post_knex_migrations(name, batch, migration_time) - SELECT value#>>'{}' AS name - , ${lastBatch + 1} AS batch - , CLOCK_TIMESTAMP() AS migration_time - FROM JSON_ARRAY_ELEMENTS($1) - `, [ namesJson ]); - - log('Committing migrations...'); - await client.query('COMMIT'); - log('Migrations committed.'); - } catch (err) { - log('Caught error; rolling back', err); - await client.query('ROLLBACK'); - throw err; - } finally { - log('Ending client...'); - await client.end(); - log('Client ended.'); - } + }); }; // Checks for pending migrations and returns an exit code of 1 if any are @@ -205,15 +207,10 @@ const checkPostKnexMigrations = async config => { const log = (...args) => console.log('[checkPostKnexMigrations]', ...args); // eslint-disable-line no-console log('ENTRY'); - const client = await getPostKnexClient(config); - try { + await withPg(config, async client => { const toRun = await getPostKnexMigrationsToRun(client); if (toRun.length) process.exitCode = 1; - } finally { - log('Ending client...'); - await client.end(); - log('Client ended.'); - } + }); }; module.exports = { checkKnexMigrations, checkPostKnexMigrations, initKnex, withKnex, knexMigrations, postKnexMigrations }; From 2e42824456ce02994a88c71afcc3d8e8cef94008 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 14 Jan 2025 10:50:45 +0000 Subject: [PATCH 013/133] run migrations in tests another way --- lib/model/migrate.js | 2 +- test/integration/setup.js | 21 ++++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/model/migrate.js b/lib/model/migrate.js index d940771f1..79444538b 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -213,4 +213,4 @@ const checkPostKnexMigrations = async config => { }); }; -module.exports = { checkKnexMigrations, checkPostKnexMigrations, initKnex, withKnex, knexMigrations, postKnexMigrations }; +module.exports = { checkKnexMigrations, checkPostKnexMigrations, initKnex, withKnex, withPg, knexMigrations, postKnexMigrations }; diff --git a/test/integration/setup.js b/test/integration/setup.js index 883ebeeeb..5db664093 100644 --- a/test/integration/setup.js +++ b/test/integration/setup.js @@ -1,3 +1,4 @@ +const { execSync } = require('node:child_process'); const { readFileSync } = require('fs'); const appRoot = require('app-root-path'); const { mergeRight } = require('ramda'); @@ -5,18 +6,18 @@ const { sql } = require('slonik'); const { readdirSync } = require('fs'); const { join } = require('path'); const request = require('supertest'); -const { noop } = require(appRoot + '/lib/util/util'); const { task } = require(appRoot + '/lib/task/task'); const authenticateUser = require('../util/authenticate-user'); const testData = require('../data/xml'); // knex things. const config = require('config'); -const { connect } = require(appRoot + '/lib/model/migrate'); +const { withPg } = require(appRoot + '/lib/model/migrate'); // slonik connection pool const { slonikPool } = require(appRoot + '/lib/external/slonik'); -const db = slonikPool(config.get('test.database')); +const dbConfig = config.get('test.database'); +const db = slonikPool(dbConfig); // set up our mailer. const env = config.get('default.env'); @@ -72,18 +73,8 @@ const populate = (container, [ head, ...tail ] = fixtures) => // this hook won't run if `test-unit` is called, as this directory is skipped // in that case. const initialize = async () => { - const migrator = connect(config.get('test.database')); - const { log } = console; - try { - await migrator.raw('drop owned by current_user'); - // Silence logging from migrations. - console.log = noop; // eslint-disable-line no-console - await migrator.migrate.latest({ directory: appRoot + '/lib/model/migrations' }); - } finally { - console.log = log; // eslint-disable-line no-console - await migrator.destroy(); - } - + await withPg(dbConfig, client => client.query('DROP OWNED BY CURRENT_USER')); + execSync('make migrations', { env: { ...process.env, NODE_CONFIG: JSON.stringify({ default: { database: dbConfig } }) } }); return withDefaults({ db, context, enketo, env, s3 }).transacting(populate); }; From 0821bdde1ba52d3c8b11b5ff5019229ecd001186 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 05:53:23 +0000 Subject: [PATCH 014/133] rename knexConnection in line with master changes --- lib/model/knexfile.js | 4 ++-- lib/model/migrate.js | 4 ++-- lib/util/db.js | 4 ++-- test/unit/util/db.js | 18 +++++++++--------- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/model/knexfile.js b/lib/model/knexfile.js index 511584825..9de8069fd 100644 --- a/lib/model/knexfile.js +++ b/lib/model/knexfile.js @@ -28,10 +28,10 @@ NODE_CONFIG_DIR=../../config DEBUG=knex:query,knex:bindings npx knex migrate:up */ const config = require('config'); -const { knexConfig } = require('../util/db'); +const { knexConnection } = require('../util/db'); module.exports = { client: 'pg', - connection: knexConfig(config.get('default.database')) + connection: knexConnection(config.get('default.database')) }; diff --git a/lib/model/migrate.js b/lib/model/migrate.js index 79444538b..63d48eb10 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -15,10 +15,10 @@ const { lstatSync, readdirSync } = require('node:fs'); const _ = require('lodash'); // eslint-disable-line import/no-extraneous-dependencies const knex = require('knex'); const pg = require('pg'); -const { knexConfig } = require('../util/db'); +const { knexConnection } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. -const initKnex = (config) => knex({ client: 'pg', connection: knexConfig(config) }); +const initKnex = (config) => knex({ client: 'pg', connection: knexConnection(config) }); const legacyPath = `${__dirname}/migrations/legacy`; const postKnexPath = `${__dirname}/migrations`; diff --git a/lib/util/db.js b/lib/util/db.js index b85e6b9e3..a095fa400 100644 --- a/lib/util/db.js +++ b/lib/util/db.js @@ -48,7 +48,7 @@ const connectionString = (config) => { }; // Returns an object that Knex will use to connect to the database. -const knexConfig = (config) => { +const knexConnection = (config) => { const problem = validateConfig(config); if (problem != null) throw problem; // We ignore maximumPoolSize when using Knex. @@ -588,7 +588,7 @@ const postgresErrorToProblem = (x) => { }; module.exports = { - connectionString, knexConfig, + connectionString, knexConnection, unjoiner, extender, sqlEquals, page, queryFuncs, insert, insertMany, updater, markDeleted, markUndeleted, QueryOptions, diff --git a/test/unit/util/db.js b/test/unit/util/db.js index 2bed332fe..21742afb6 100644 --- a/test/unit/util/db.js +++ b/test/unit/util/db.js @@ -97,11 +97,11 @@ describe('util/db', () => { }); }); - describe('knexConfig', () => { - const { knexConfig } = util; + describe('knexConnection', () => { + const { knexConnection } = util; it('should return an object with the required options', () => { - const result = knexConfig({ + const result = knexConnection({ host: 'localhost', database: 'foo', user: 'bar', @@ -116,7 +116,7 @@ describe('util/db', () => { }); it('should include the port if one is specified', () => { - const result = knexConfig({ + const result = knexConnection({ host: 'localhost', database: 'foo', user: 'bar', @@ -133,7 +133,7 @@ describe('util/db', () => { }); it('should return the correct object if ssl is true', () => { - const result = knexConfig({ + const result = knexConnection({ host: 'localhost', database: 'foo', user: 'bar', @@ -150,7 +150,7 @@ describe('util/db', () => { }); it('should throw if ssl is false', () => { - const result = () => knexConfig({ + const result = () => knexConnection({ host: 'localhost', database: 'foo', user: 'bar', @@ -161,7 +161,7 @@ describe('util/db', () => { }); it('should throw if ssl is an object', () => { - const result = () => knexConfig({ + const result = () => knexConnection({ host: 'localhost', database: 'foo', user: 'bar', @@ -172,7 +172,7 @@ describe('util/db', () => { }); it('should allow (but ignore) maximumPoolSize', () => { - const result = knexConfig({ + const result = knexConnection({ host: 'localhost', database: 'foo', user: 'bar', @@ -188,7 +188,7 @@ describe('util/db', () => { }); it('should throw for an unsupported option', () => { - const result = () => knexConfig({ + const result = () => knexConnection({ host: 'localhost', database: 'foo', user: 'bar', From 100c424af77c87f1ac19794f8eb9c48873ec5dd7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:19:20 +0000 Subject: [PATCH 015/133] Change in line with #1371 --- Makefile | 3 +-- lib/model/migrations/.eslintrc.js | 11 +++++++++++ lib/model/migrations/.eslintrc.json | 9 --------- lib/model/migrations/legacy/.eslintrc.json | 9 --------- .../migrations/legacy/20180727-02-add-md5-to-blobs.js | 2 +- .../legacy/20180727-03-add-form-attachments-table.js | 2 +- .../legacy/20190520-01-add-form-versioning.js | 2 +- .../legacy/20191007-01-backfill-client-audits.js | 6 +++--- .../legacy/20191231-02-add-schema-storage.js | 4 ++-- .../legacy/20200220-01-repair-submission-parsing.js | 2 +- .../migrations/legacy/20210120-01-instance-names.js | 2 +- .../legacy/20211008-01-track-select-many-options.js | 8 ++++---- .../migrations/legacy/20230109-01-add-form-schema.js | 2 +- 13 files changed, 27 insertions(+), 35 deletions(-) create mode 100644 lib/model/migrations/.eslintrc.js delete mode 100644 lib/model/migrations/.eslintrc.json delete mode 100644 lib/model/migrations/legacy/.eslintrc.json diff --git a/Makefile b/Makefile index 22921d682..8760c350e 100644 --- a/Makefile +++ b/Makefile @@ -131,8 +131,7 @@ test-coverage: node_version .PHONY: lint lint: node_version - # max-warnings set to take account of legacy database migrations - npx eslint --cache --max-warnings 15 . + npx eslint --cache --max-warnings 0 . ################################################################################ diff --git a/lib/model/migrations/.eslintrc.js b/lib/model/migrations/.eslintrc.js new file mode 100644 index 000000000..ed8ad55c1 --- /dev/null +++ b/lib/model/migrations/.eslintrc.js @@ -0,0 +1,11 @@ +module.exports = { + extends: '../../../.eslintrc.json', + rules: { + // Prevent migrations from including application code. + // + // Mixing application code into database migrations removes assurances that + // the same migration will mutate the same postgresql data identically when + // upgrading from/to different versions of the application. + 'no-restricted-modules': [ 'error', { patterns: [ '../*' ] } ], + }, +}; diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/.eslintrc.json deleted file mode 100644 index f34c5819a..000000000 --- a/lib/model/migrations/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../.eslintrc.json", - "rules": { - "no-restricted-modules": [ - "error", - { "patterns": [ "../*" ] } - ] - } -} diff --git a/lib/model/migrations/legacy/.eslintrc.json b/lib/model/migrations/legacy/.eslintrc.json deleted file mode 100644 index 4fe3ba4a9..000000000 --- a/lib/model/migrations/legacy/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../../.eslintrc.json", - "rules": { - "no-restricted-modules": [ - "warn", - { "patterns": [ "../*" ] } - ] - } -} diff --git a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js index 8c487f7ae..5fa121135 100644 --- a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js +++ b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. // -const { md5sum } = require('../../../util/crypto'); +const { md5sum } = require('../../../util/crypto'); // eslint-disable-line no-restricted-modules const up = (knex) => knex.schema.table('blobs', (blobs) => { blobs.string('md5', 32); }) diff --git a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js index 1633829ae..c48ceb758 100644 --- a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js +++ b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js @@ -23,7 +23,7 @@ const up = (knex) => fa.index([ 'formId' ]); }).then(() => { - const { expectedFormAttachments } = require('../../../data/schema'); + const { expectedFormAttachments } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules const { uniq, pluck } = require('ramda'); // now add all expected attachments on extant forms. diff --git a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js index 8b8e9c490..623e966c9 100644 --- a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js +++ b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { shasum, sha256sum } = require('../../../util/crypto'); +const { shasum, sha256sum } = require('../../../util/crypto'); // eslint-disable-line no-restricted-modules const assert = require('assert').strict; const check = (message, query) => diff --git a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js index 9067ccc06..5f79a3821 100644 --- a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js +++ b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js @@ -7,9 +7,9 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { parseClientAudits } = require('../../../data/client-audits'); -const { getFormFields } = require('../../../data/schema'); -const { traverseXml, findOne, root, node, text } = require('../../../util/xml'); +const { parseClientAudits } = require('../../../data/client-audits'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules +const { traverseXml, findOne, root, node, text } = require('../../../util/xml'); // eslint-disable-line no-restricted-modules const up = (db) => new Promise((resolve, reject) => { const work = []; diff --git a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js index f331a1eaa..da84931f6 100644 --- a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields } = require('../../../data/schema'); +const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules const up = async (db) => { await db.schema.createTable('form_fields', (fields) => { @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../../migrate').connect(config); + const db2 = require('../../migrate').connect(config); // eslint-disable-line no-restricted-modules return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js index f6f671ef3..d4020bc25 100644 --- a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js +++ b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../../frames'); +const { Submission } = require('../../frames'); // eslint-disable-line no-restricted-modules const up = async (db) => { const work = []; diff --git a/lib/model/migrations/legacy/20210120-01-instance-names.js b/lib/model/migrations/legacy/20210120-01-instance-names.js index 36c625343..6c6cde9d9 100644 --- a/lib/model/migrations/legacy/20210120-01-instance-names.js +++ b/lib/model/migrations/legacy/20210120-01-instance-names.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../../frames'); +const { Submission } = require('../../frames'); // eslint-disable-line no-restricted-modules const up = async (db) => { await db.schema.table('submission_defs', (sds) => { diff --git a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js index caa466186..09f1efa92 100644 --- a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js +++ b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const { map } = require('ramda'); -const { getFormFields } = require('../../../data/schema'); -const { getSelectMultipleResponses } = require('../../../data/submission'); -const { Form } = require('../../frames'); -const { construct } = require('../../../util/util'); +const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules +const { getSelectMultipleResponses } = require('../../../data/submission'); // eslint-disable-line no-restricted-modules +const { Form } = require('../../frames'); // eslint-disable-line no-restricted-modules +const { construct } = require('../../../util/util'); // eslint-disable-line no-restricted-modules const up = async (db) => { // add select many flag, options field to fields diff --git a/lib/model/migrations/legacy/20230109-01-add-form-schema.js b/lib/model/migrations/legacy/20230109-01-add-form-schema.js index 40013f840..63c2cd903 100644 --- a/lib/model/migrations/legacy/20230109-01-add-form-schema.js +++ b/lib/model/migrations/legacy/20230109-01-add-form-schema.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields, compare } = require('../../../data/schema'); +const { getFormFields, compare } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules /* Steps of this migration 1. remove check field collision trigger From bb0d883af410f616ac8645286fe62019f4a896db Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:24:11 +0000 Subject: [PATCH 016/133] js -> json --- lib/model/migrations/.eslintrc.js | 11 ----------- lib/model/migrations/.eslintrc.json | 6 ++++++ 2 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 lib/model/migrations/.eslintrc.js create mode 100644 lib/model/migrations/.eslintrc.json diff --git a/lib/model/migrations/.eslintrc.js b/lib/model/migrations/.eslintrc.js deleted file mode 100644 index ed8ad55c1..000000000 --- a/lib/model/migrations/.eslintrc.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - extends: '../../../.eslintrc.json', - rules: { - // Prevent migrations from including application code. - // - // Mixing application code into database migrations removes assurances that - // the same migration will mutate the same postgresql data identically when - // upgrading from/to different versions of the application. - 'no-restricted-modules': [ 'error', { patterns: [ '../*' ] } ], - }, -}; diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/.eslintrc.json new file mode 100644 index 000000000..93a99d9dd --- /dev/null +++ b/lib/model/migrations/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "../../../.eslintrc.json", + "rules": { + "no-restricted-modules": [ "error", { "patterns": [ "../*" ] } ] + } +} From e2d64cc2352fe6e600d6c00bf8f9def507ef6e49 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:26:54 +0000 Subject: [PATCH 017/133] reduce changes by renaming migration dirs --- lib/model/migrate.js | 4 ++-- lib/model/migrations-post-knex/.eslintrc.json | 6 ++++++ .../20250113-01-disable-nullable-blob-content-types.js | 0 lib/model/migrations/{legacy => }/20170920-01-initial.js | 0 lib/model/migrations/{legacy => }/20171010-01-auth.js | 0 .../migrations/{legacy => }/20171023-01-authz-forms.js | 0 .../{legacy => }/20171030-01-add-default-authz-records.js | 0 .../20171106-01-remove-user-update-timestamp.js | 0 .../{legacy => }/20171121-01-add-submissions-constraint.js | 0 .../migrations/{legacy => }/20171121-02-add-submitter.js | 0 .../{legacy => }/20171213-01-unrequire-display-name.js | 0 .../migrations/{legacy => }/20180108-01-expiring-actors.js | 0 .../migrations/{legacy => }/20180108-02-enum-to-varchar.js | 0 .../migrations/{legacy => }/20180112-01-audit-table.js | 0 .../migrations/{legacy => }/20180112-02-add-field-keys.js | 0 .../{legacy => }/20180118-01-rerequire-display-name.js | 0 .../{legacy => }/20180125-01-add-form-detail-fields.js | 0 .../{legacy => }/20180125-02-more-field-key-grants.js | 0 .../migrations/{legacy => }/20180125-03-add-blob-tables.js | 0 .../migrations/{legacy => }/20180301-01-configuration.js | 0 .../{legacy => }/20180322-01-additional-form-options.js | 0 .../{legacy => }/20180327-01-update-form-constraints.js | 0 .../{legacy => }/20180501-01-add-configs-timestamp.js | 0 .../migrations/{legacy => }/20180501-02-fix-date-columns.js | 0 .../20180515-01-enforce-nonnull-form-version.js | 0 .../{legacy => }/20180727-01-rename-attachments-table.js | 0 .../migrations/{legacy => }/20180727-02-add-md5-to-blobs.js | 0 .../{legacy => }/20180727-03-add-form-attachments-table.js | 0 .../{legacy => }/20181011-make-email-case-insensitive.js | 0 .../20181012-01-add-submissions-createdat-index.js | 0 .../migrations/{legacy => }/20181206-01-add-projects.js | 0 .../{legacy => }/20181207-01-grant-verbs-to-text.js | 0 .../{legacy => }/20181207-02-rename-grant-verbs.js | 0 .../{legacy => }/20181211-01-audit-verbs-to-text.js | 0 .../{legacy => }/20181211-02-rename-audit-actions.js | 0 .../migrations/{legacy => }/20181212-00-fix-user-type.js | 0 lib/model/migrations/{legacy => }/20181212-01-add-roles.js | 0 .../migrations/{legacy => }/20181212-02-remove-groups.js | 0 .../{legacy => }/20181212-03-add-single-use-roles.js | 0 .../{legacy => }/20181219-01-add-submission-update-verb.js | 0 .../{legacy => }/20181221-01-nullable-submission-blobs.js | 0 .../{legacy => }/20181230-01-add-device-id-to-submission.js | 0 .../{legacy => }/20190225-01-add-actor-trigram-indices.js | 0 .../migrations/{legacy => }/20190225-02-add-role-grants.js | 0 .../{legacy => }/20190226-01-convert-verbs-to-jsonb.js | 0 .../{legacy => }/20190226-02-add-role-actee-species.js | 0 .../{legacy => }/20190226-03-add-assignment-verbs.js | 0 .../20190226-04-add-assignment-actee-species.js | 0 .../{legacy => }/20190227-01-add-project-manager-role.js | 0 .../{legacy => }/20190405-01-add-project-archival-flag.js | 0 .../migrations/{legacy => }/20190416-01-email-uniqueness.js | 0 .../{legacy => }/20190416-02-add-user-delete-verb.js | 0 .../{legacy => }/20190520-01-add-form-versioning.js | 0 .../{legacy => }/20190523-01-add-form-state-constraint.js | 0 .../migrations/{legacy => }/20190605-01-reformat-audits.js | 0 .../20190607-01-convert-audit-details-to-jsonb.js | 0 .../20190607-02-standardize-attachment-actees.js | 0 .../20190607-03-rename-sub-attachment-audits.js | 0 .../migrations/{legacy => }/20190610-01-add-audits-verbs.js | 0 .../20190610-02-backfill-submission-audit-instanceids.js | 0 .../20190611-01-add-updatedat-to-form-attachments.js | 0 .../migrations/{legacy => }/20190618-01-add-csrf-token.js | 0 .../{legacy => }/20190618-01-add-encryption-tracking.js | 0 .../20190701-01-add-managed-encryption-key-check.js | 0 .../20190916-01-granularize-app-user-permissions.js | 0 .../{legacy => }/20190917-01-cleanup-app-user-role.js | 0 .../{legacy => }/20190923-01-add-project-viewer-role.js | 0 .../{legacy => }/20190925-01-add-client-audits.js | 0 .../{legacy => }/20191007-01-backfill-client-audits.js | 0 .../{legacy => }/20191010-01-add-excel-blob-reference.js | 0 .../20191023-01-add-worker-columns-to-audits.js | 0 .../migrations/{legacy => }/20191025-01-add-id-to-audits.js | 0 .../20191106-01-remove-deleted-actor-assignments.js | 0 .../{legacy => }/20191231-01-remove-transformations.js | 0 .../{legacy => }/20191231-02-add-schema-storage.js | 0 lib/model/migrations/{legacy => }/20200110-01-add-drafts.js | 0 .../{legacy => }/20200112-01-check-field-collisions.js | 0 .../20200114-01-remove-formid-sha256-constraint.js | 0 .../{legacy => }/20200117-01-draft-test-submissions.js | 0 .../migrations/{legacy => }/20200121-01-add-draft-keys.js | 0 .../{legacy => }/20200122-01-remove-draft-form-state.js | 0 .../{legacy => }/20200129-01-cascade-submission-deletes.js | 0 .../{legacy => }/20200220-01-repair-submission-parsing.js | 0 .../{legacy => }/20200403-01-add-performance-indices.js | 0 .../20200407-01-allow-actorless-submission-defs.js | 0 .../20200423-01-fix-field-insert-performance.js | 0 .../{legacy => }/20200428-01-allow-string-downcast.js | 0 .../migrations/{legacy => }/20200519-01-add-enketo-id.js | 0 .../{legacy => }/20200519-02-add-form-viewer-role.js | 0 .../migrations/{legacy => }/20200520-01-backfill-enketo.js | 0 .../{legacy => }/20200715-01-add-data-collector-role.js | 0 .../migrations/{legacy => }/20200721-01-add-public-links.js | 0 .../20200728-01-add-enketo-single-token-to-forms.js | 0 .../20200731-01-allow-project-managers-to-end-sessions.js | 0 .../20200810-01-reschedule-enketo-processing.js | 0 .../{legacy => }/20200918-01-repair-publishedat-dates.js | 0 .../{legacy => }/20200930-01-add-backup-run-verb.js | 0 .../20201117-01-remove-deleted-actor-assignments-again.js | 0 .../20201207-01-harmonize-submitter-id-columns.js | 0 .../20210118-01-add-current-flag-to-submission-defs.js | 0 .../migrations/{legacy => }/20210120-01-instance-names.js | 0 .../{legacy => }/20210203-01-add-hierarchy-to-actees.js | 0 .../20210210-01-add-instanceid-to-submission-defs.js | 0 .../{legacy => }/20210218-01-add-submission-edit-verbs.js | 0 .../20210218-02-add-draft-to-submissions-unique.js | 0 .../migrations/{legacy => }/20210219-01-add-review-state.js | 0 .../20210219-02-add-notes-and-index-to-audits.js | 0 .../20210324-01-add-submission-edit-verbs-to-managers.js | 0 .../{legacy => }/20210325-01-remove-project.list-verb.js | 0 .../{legacy => }/20210408-01-drop-public-link-createdat.js | 0 .../20210408-02-backfill-specialized-actor-audits.js | 0 .../migrations/{legacy => }/20210409-01-add-comments.js | 0 .../{legacy => }/20210409-02-update-review-states.js | 0 .../{legacy => }/20210423-01-add-name-to-form-def.js | 0 .../migrations/{legacy => }/20210423-02-drop-form-name.js | 0 .../{legacy => }/20210716-01-config-value-jsonb.js | 0 .../{legacy => }/20210721-01-add-config-set-verb.js | 0 .../20210817-01-disallow-structure-downcast-to-string.js | 0 .../{legacy => }/20210825-01-add-analytics-read-verb.js | 0 .../20210903-01-backfill-encrypted-client-audits.js | 0 .../20210927-01-revert-disallow-structure-downcast.js | 0 .../{legacy => }/20211008-01-track-select-many-options.js | 0 .../{legacy => }/20211021-remove-hashes-from-audits.js | 0 .../20211109-01-add-user-agent-to-submissions.js | 0 .../{legacy => }/20211114-01-flag-initial-submission-def.js | 0 .../{legacy => }/20211117-01-add-form-restore-verb.js | 0 .../20211129-01-add-purged-details-to-actees.js | 0 .../{legacy => }/20220121-01-form-cascade-delete.js | 0 .../{legacy => }/20220121-02-purge-deleted-forms.js | 0 .../{legacy => }/20220209-01-purge-unneeded-drafts.js | 0 .../{legacy => }/20220309-01-add-project-description.js | 0 .../{legacy => }/20220803-01-create-entities-schema.js | 0 .../{legacy => }/20221003-01-add-dataset-verbs.js | 0 .../{legacy => }/20221114-01-explict-dataset-publish.js | 0 ...20221117-01-check-datasetId-is-null-for-non-file-type.js | 0 .../20221118-01-make-entities-columns-not-null.js | 0 .../{legacy => }/20221208-01-reduce-tz-precision.js | 0 .../{legacy => }/20230106-01-remove-revision-number.js | 0 .../migrations/{legacy => }/20230109-01-add-form-schema.js | 0 .../{legacy => }/20230123-01-remove-google-backups.js | 0 .../{legacy => }/20230126-01-add-entity-indices.js | 0 .../{legacy => }/20230127-01-rename-entity-created-by.js | 0 .../{legacy => }/20230324-01-edit-dataset-verbs.js | 0 .../{legacy => }/20230406-01-add-entity-def-fields.js | 0 .../20230406-02-move-entity-label-add-deletedAt.js | 0 .../{legacy => }/20230414-01-remove-user-mfa-secret.js | 0 .../{legacy => }/20230419-01-optimize-indices-sub-defs.js | 0 .../{legacy => }/20230509-01-dataset-approval-flag.js | 0 .../migrations/{legacy => }/20230512-01-add-entity-root.js | 0 .../{legacy => }/20230512-02-backfill-entity-id.js | 0 .../{legacy => }/20230512-03-add-entity-source.js | 0 .../{legacy => }/20230518-01-add-entity-index-to-audits.js | 0 .../{legacy => }/20230802-01-delete-orphan-submissions.js | 0 .../20230818-01-remove-schemaId-from-dsPropertyFields.js | 0 .../{legacy => }/20230824-01-add-entity-version.js | 0 .../20230830-01-remove-entity-label-from-audits.js | 0 .../migrations/{legacy => }/20230907-01-opened-form-verb.js | 0 .../{legacy => }/20231002-01-add-conflict-details.js | 0 .../{legacy => }/20231013-01-change-entity-error-action.js | 0 .../{legacy => }/20231208-01-dataset-form-def-actions.js | 0 .../{legacy => }/20240215-01-entity-delete-verb.js | 0 .../migrations/{legacy => }/20240215-02-dedupe-verbs.js | 0 .../{legacy => }/20240312-01-add-dataset-create-verb.js | 0 .../20240322-01-add-entity-source-index-to-audits.js | 0 .../{legacy => }/20240515-01-entity-tz-precision.js | 0 .../20240607-01-add-offline-entity-branch-trunk-info.js | 0 .../{legacy => }/20240607-02-add-submission-backlog.js | 0 .../20240715-01-backlog-add-event-entityuuid.js | 0 .../migrations/{legacy => }/20240913-01-add-blob-s3.js | 0 .../{legacy => }/20240914-01-add-submission-delete-verb.js | 0 .../20240914-02-remove-orphaned-client-audits.js | 0 .../{legacy => }/20241001-01-index-on-session-table.js | 0 .../{legacy => }/20241008-01-add-user_preferences.js | 0 .../20241010-01-schedule-entity-form-upgrade.js | 0 ...20241029-01-schedule-entity-form-upgrade-create-forms.js | 0 .../{legacy => }/20241030-01-add-force-entity-def-source.js | 0 176 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 lib/model/migrations-post-knex/.eslintrc.json rename lib/model/{migrations => migrations-post-knex}/20250113-01-disable-nullable-blob-content-types.js (100%) rename lib/model/migrations/{legacy => }/20170920-01-initial.js (100%) rename lib/model/migrations/{legacy => }/20171010-01-auth.js (100%) rename lib/model/migrations/{legacy => }/20171023-01-authz-forms.js (100%) rename lib/model/migrations/{legacy => }/20171030-01-add-default-authz-records.js (100%) rename lib/model/migrations/{legacy => }/20171106-01-remove-user-update-timestamp.js (100%) rename lib/model/migrations/{legacy => }/20171121-01-add-submissions-constraint.js (100%) rename lib/model/migrations/{legacy => }/20171121-02-add-submitter.js (100%) rename lib/model/migrations/{legacy => }/20171213-01-unrequire-display-name.js (100%) rename lib/model/migrations/{legacy => }/20180108-01-expiring-actors.js (100%) rename lib/model/migrations/{legacy => }/20180108-02-enum-to-varchar.js (100%) rename lib/model/migrations/{legacy => }/20180112-01-audit-table.js (100%) rename lib/model/migrations/{legacy => }/20180112-02-add-field-keys.js (100%) rename lib/model/migrations/{legacy => }/20180118-01-rerequire-display-name.js (100%) rename lib/model/migrations/{legacy => }/20180125-01-add-form-detail-fields.js (100%) rename lib/model/migrations/{legacy => }/20180125-02-more-field-key-grants.js (100%) rename lib/model/migrations/{legacy => }/20180125-03-add-blob-tables.js (100%) rename lib/model/migrations/{legacy => }/20180301-01-configuration.js (100%) rename lib/model/migrations/{legacy => }/20180322-01-additional-form-options.js (100%) rename lib/model/migrations/{legacy => }/20180327-01-update-form-constraints.js (100%) rename lib/model/migrations/{legacy => }/20180501-01-add-configs-timestamp.js (100%) rename lib/model/migrations/{legacy => }/20180501-02-fix-date-columns.js (100%) rename lib/model/migrations/{legacy => }/20180515-01-enforce-nonnull-form-version.js (100%) rename lib/model/migrations/{legacy => }/20180727-01-rename-attachments-table.js (100%) rename lib/model/migrations/{legacy => }/20180727-02-add-md5-to-blobs.js (100%) rename lib/model/migrations/{legacy => }/20180727-03-add-form-attachments-table.js (100%) rename lib/model/migrations/{legacy => }/20181011-make-email-case-insensitive.js (100%) rename lib/model/migrations/{legacy => }/20181012-01-add-submissions-createdat-index.js (100%) rename lib/model/migrations/{legacy => }/20181206-01-add-projects.js (100%) rename lib/model/migrations/{legacy => }/20181207-01-grant-verbs-to-text.js (100%) rename lib/model/migrations/{legacy => }/20181207-02-rename-grant-verbs.js (100%) rename lib/model/migrations/{legacy => }/20181211-01-audit-verbs-to-text.js (100%) rename lib/model/migrations/{legacy => }/20181211-02-rename-audit-actions.js (100%) rename lib/model/migrations/{legacy => }/20181212-00-fix-user-type.js (100%) rename lib/model/migrations/{legacy => }/20181212-01-add-roles.js (100%) rename lib/model/migrations/{legacy => }/20181212-02-remove-groups.js (100%) rename lib/model/migrations/{legacy => }/20181212-03-add-single-use-roles.js (100%) rename lib/model/migrations/{legacy => }/20181219-01-add-submission-update-verb.js (100%) rename lib/model/migrations/{legacy => }/20181221-01-nullable-submission-blobs.js (100%) rename lib/model/migrations/{legacy => }/20181230-01-add-device-id-to-submission.js (100%) rename lib/model/migrations/{legacy => }/20190225-01-add-actor-trigram-indices.js (100%) rename lib/model/migrations/{legacy => }/20190225-02-add-role-grants.js (100%) rename lib/model/migrations/{legacy => }/20190226-01-convert-verbs-to-jsonb.js (100%) rename lib/model/migrations/{legacy => }/20190226-02-add-role-actee-species.js (100%) rename lib/model/migrations/{legacy => }/20190226-03-add-assignment-verbs.js (100%) rename lib/model/migrations/{legacy => }/20190226-04-add-assignment-actee-species.js (100%) rename lib/model/migrations/{legacy => }/20190227-01-add-project-manager-role.js (100%) rename lib/model/migrations/{legacy => }/20190405-01-add-project-archival-flag.js (100%) rename lib/model/migrations/{legacy => }/20190416-01-email-uniqueness.js (100%) rename lib/model/migrations/{legacy => }/20190416-02-add-user-delete-verb.js (100%) rename lib/model/migrations/{legacy => }/20190520-01-add-form-versioning.js (100%) rename lib/model/migrations/{legacy => }/20190523-01-add-form-state-constraint.js (100%) rename lib/model/migrations/{legacy => }/20190605-01-reformat-audits.js (100%) rename lib/model/migrations/{legacy => }/20190607-01-convert-audit-details-to-jsonb.js (100%) rename lib/model/migrations/{legacy => }/20190607-02-standardize-attachment-actees.js (100%) rename lib/model/migrations/{legacy => }/20190607-03-rename-sub-attachment-audits.js (100%) rename lib/model/migrations/{legacy => }/20190610-01-add-audits-verbs.js (100%) rename lib/model/migrations/{legacy => }/20190610-02-backfill-submission-audit-instanceids.js (100%) rename lib/model/migrations/{legacy => }/20190611-01-add-updatedat-to-form-attachments.js (100%) rename lib/model/migrations/{legacy => }/20190618-01-add-csrf-token.js (100%) rename lib/model/migrations/{legacy => }/20190618-01-add-encryption-tracking.js (100%) rename lib/model/migrations/{legacy => }/20190701-01-add-managed-encryption-key-check.js (100%) rename lib/model/migrations/{legacy => }/20190916-01-granularize-app-user-permissions.js (100%) rename lib/model/migrations/{legacy => }/20190917-01-cleanup-app-user-role.js (100%) rename lib/model/migrations/{legacy => }/20190923-01-add-project-viewer-role.js (100%) rename lib/model/migrations/{legacy => }/20190925-01-add-client-audits.js (100%) rename lib/model/migrations/{legacy => }/20191007-01-backfill-client-audits.js (100%) rename lib/model/migrations/{legacy => }/20191010-01-add-excel-blob-reference.js (100%) rename lib/model/migrations/{legacy => }/20191023-01-add-worker-columns-to-audits.js (100%) rename lib/model/migrations/{legacy => }/20191025-01-add-id-to-audits.js (100%) rename lib/model/migrations/{legacy => }/20191106-01-remove-deleted-actor-assignments.js (100%) rename lib/model/migrations/{legacy => }/20191231-01-remove-transformations.js (100%) rename lib/model/migrations/{legacy => }/20191231-02-add-schema-storage.js (100%) rename lib/model/migrations/{legacy => }/20200110-01-add-drafts.js (100%) rename lib/model/migrations/{legacy => }/20200112-01-check-field-collisions.js (100%) rename lib/model/migrations/{legacy => }/20200114-01-remove-formid-sha256-constraint.js (100%) rename lib/model/migrations/{legacy => }/20200117-01-draft-test-submissions.js (100%) rename lib/model/migrations/{legacy => }/20200121-01-add-draft-keys.js (100%) rename lib/model/migrations/{legacy => }/20200122-01-remove-draft-form-state.js (100%) rename lib/model/migrations/{legacy => }/20200129-01-cascade-submission-deletes.js (100%) rename lib/model/migrations/{legacy => }/20200220-01-repair-submission-parsing.js (100%) rename lib/model/migrations/{legacy => }/20200403-01-add-performance-indices.js (100%) rename lib/model/migrations/{legacy => }/20200407-01-allow-actorless-submission-defs.js (100%) rename lib/model/migrations/{legacy => }/20200423-01-fix-field-insert-performance.js (100%) rename lib/model/migrations/{legacy => }/20200428-01-allow-string-downcast.js (100%) rename lib/model/migrations/{legacy => }/20200519-01-add-enketo-id.js (100%) rename lib/model/migrations/{legacy => }/20200519-02-add-form-viewer-role.js (100%) rename lib/model/migrations/{legacy => }/20200520-01-backfill-enketo.js (100%) rename lib/model/migrations/{legacy => }/20200715-01-add-data-collector-role.js (100%) rename lib/model/migrations/{legacy => }/20200721-01-add-public-links.js (100%) rename lib/model/migrations/{legacy => }/20200728-01-add-enketo-single-token-to-forms.js (100%) rename lib/model/migrations/{legacy => }/20200731-01-allow-project-managers-to-end-sessions.js (100%) rename lib/model/migrations/{legacy => }/20200810-01-reschedule-enketo-processing.js (100%) rename lib/model/migrations/{legacy => }/20200918-01-repair-publishedat-dates.js (100%) rename lib/model/migrations/{legacy => }/20200930-01-add-backup-run-verb.js (100%) rename lib/model/migrations/{legacy => }/20201117-01-remove-deleted-actor-assignments-again.js (100%) rename lib/model/migrations/{legacy => }/20201207-01-harmonize-submitter-id-columns.js (100%) rename lib/model/migrations/{legacy => }/20210118-01-add-current-flag-to-submission-defs.js (100%) rename lib/model/migrations/{legacy => }/20210120-01-instance-names.js (100%) rename lib/model/migrations/{legacy => }/20210203-01-add-hierarchy-to-actees.js (100%) rename lib/model/migrations/{legacy => }/20210210-01-add-instanceid-to-submission-defs.js (100%) rename lib/model/migrations/{legacy => }/20210218-01-add-submission-edit-verbs.js (100%) rename lib/model/migrations/{legacy => }/20210218-02-add-draft-to-submissions-unique.js (100%) rename lib/model/migrations/{legacy => }/20210219-01-add-review-state.js (100%) rename lib/model/migrations/{legacy => }/20210219-02-add-notes-and-index-to-audits.js (100%) rename lib/model/migrations/{legacy => }/20210324-01-add-submission-edit-verbs-to-managers.js (100%) rename lib/model/migrations/{legacy => }/20210325-01-remove-project.list-verb.js (100%) rename lib/model/migrations/{legacy => }/20210408-01-drop-public-link-createdat.js (100%) rename lib/model/migrations/{legacy => }/20210408-02-backfill-specialized-actor-audits.js (100%) rename lib/model/migrations/{legacy => }/20210409-01-add-comments.js (100%) rename lib/model/migrations/{legacy => }/20210409-02-update-review-states.js (100%) rename lib/model/migrations/{legacy => }/20210423-01-add-name-to-form-def.js (100%) rename lib/model/migrations/{legacy => }/20210423-02-drop-form-name.js (100%) rename lib/model/migrations/{legacy => }/20210716-01-config-value-jsonb.js (100%) rename lib/model/migrations/{legacy => }/20210721-01-add-config-set-verb.js (100%) rename lib/model/migrations/{legacy => }/20210817-01-disallow-structure-downcast-to-string.js (100%) rename lib/model/migrations/{legacy => }/20210825-01-add-analytics-read-verb.js (100%) rename lib/model/migrations/{legacy => }/20210903-01-backfill-encrypted-client-audits.js (100%) rename lib/model/migrations/{legacy => }/20210927-01-revert-disallow-structure-downcast.js (100%) rename lib/model/migrations/{legacy => }/20211008-01-track-select-many-options.js (100%) rename lib/model/migrations/{legacy => }/20211021-remove-hashes-from-audits.js (100%) rename lib/model/migrations/{legacy => }/20211109-01-add-user-agent-to-submissions.js (100%) rename lib/model/migrations/{legacy => }/20211114-01-flag-initial-submission-def.js (100%) rename lib/model/migrations/{legacy => }/20211117-01-add-form-restore-verb.js (100%) rename lib/model/migrations/{legacy => }/20211129-01-add-purged-details-to-actees.js (100%) rename lib/model/migrations/{legacy => }/20220121-01-form-cascade-delete.js (100%) rename lib/model/migrations/{legacy => }/20220121-02-purge-deleted-forms.js (100%) rename lib/model/migrations/{legacy => }/20220209-01-purge-unneeded-drafts.js (100%) rename lib/model/migrations/{legacy => }/20220309-01-add-project-description.js (100%) rename lib/model/migrations/{legacy => }/20220803-01-create-entities-schema.js (100%) rename lib/model/migrations/{legacy => }/20221003-01-add-dataset-verbs.js (100%) rename lib/model/migrations/{legacy => }/20221114-01-explict-dataset-publish.js (100%) rename lib/model/migrations/{legacy => }/20221117-01-check-datasetId-is-null-for-non-file-type.js (100%) rename lib/model/migrations/{legacy => }/20221118-01-make-entities-columns-not-null.js (100%) rename lib/model/migrations/{legacy => }/20221208-01-reduce-tz-precision.js (100%) rename lib/model/migrations/{legacy => }/20230106-01-remove-revision-number.js (100%) rename lib/model/migrations/{legacy => }/20230109-01-add-form-schema.js (100%) rename lib/model/migrations/{legacy => }/20230123-01-remove-google-backups.js (100%) rename lib/model/migrations/{legacy => }/20230126-01-add-entity-indices.js (100%) rename lib/model/migrations/{legacy => }/20230127-01-rename-entity-created-by.js (100%) rename lib/model/migrations/{legacy => }/20230324-01-edit-dataset-verbs.js (100%) rename lib/model/migrations/{legacy => }/20230406-01-add-entity-def-fields.js (100%) rename lib/model/migrations/{legacy => }/20230406-02-move-entity-label-add-deletedAt.js (100%) rename lib/model/migrations/{legacy => }/20230414-01-remove-user-mfa-secret.js (100%) rename lib/model/migrations/{legacy => }/20230419-01-optimize-indices-sub-defs.js (100%) rename lib/model/migrations/{legacy => }/20230509-01-dataset-approval-flag.js (100%) rename lib/model/migrations/{legacy => }/20230512-01-add-entity-root.js (100%) rename lib/model/migrations/{legacy => }/20230512-02-backfill-entity-id.js (100%) rename lib/model/migrations/{legacy => }/20230512-03-add-entity-source.js (100%) rename lib/model/migrations/{legacy => }/20230518-01-add-entity-index-to-audits.js (100%) rename lib/model/migrations/{legacy => }/20230802-01-delete-orphan-submissions.js (100%) rename lib/model/migrations/{legacy => }/20230818-01-remove-schemaId-from-dsPropertyFields.js (100%) rename lib/model/migrations/{legacy => }/20230824-01-add-entity-version.js (100%) rename lib/model/migrations/{legacy => }/20230830-01-remove-entity-label-from-audits.js (100%) rename lib/model/migrations/{legacy => }/20230907-01-opened-form-verb.js (100%) rename lib/model/migrations/{legacy => }/20231002-01-add-conflict-details.js (100%) rename lib/model/migrations/{legacy => }/20231013-01-change-entity-error-action.js (100%) rename lib/model/migrations/{legacy => }/20231208-01-dataset-form-def-actions.js (100%) rename lib/model/migrations/{legacy => }/20240215-01-entity-delete-verb.js (100%) rename lib/model/migrations/{legacy => }/20240215-02-dedupe-verbs.js (100%) rename lib/model/migrations/{legacy => }/20240312-01-add-dataset-create-verb.js (100%) rename lib/model/migrations/{legacy => }/20240322-01-add-entity-source-index-to-audits.js (100%) rename lib/model/migrations/{legacy => }/20240515-01-entity-tz-precision.js (100%) rename lib/model/migrations/{legacy => }/20240607-01-add-offline-entity-branch-trunk-info.js (100%) rename lib/model/migrations/{legacy => }/20240607-02-add-submission-backlog.js (100%) rename lib/model/migrations/{legacy => }/20240715-01-backlog-add-event-entityuuid.js (100%) rename lib/model/migrations/{legacy => }/20240913-01-add-blob-s3.js (100%) rename lib/model/migrations/{legacy => }/20240914-01-add-submission-delete-verb.js (100%) rename lib/model/migrations/{legacy => }/20240914-02-remove-orphaned-client-audits.js (100%) rename lib/model/migrations/{legacy => }/20241001-01-index-on-session-table.js (100%) rename lib/model/migrations/{legacy => }/20241008-01-add-user_preferences.js (100%) rename lib/model/migrations/{legacy => }/20241010-01-schedule-entity-form-upgrade.js (100%) rename lib/model/migrations/{legacy => }/20241029-01-schedule-entity-form-upgrade-create-forms.js (100%) rename lib/model/migrations/{legacy => }/20241030-01-add-force-entity-def-source.js (100%) diff --git a/lib/model/migrate.js b/lib/model/migrate.js index 63d48eb10..6e25cfa3b 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -20,8 +20,8 @@ const { knexConnection } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. const initKnex = (config) => knex({ client: 'pg', connection: knexConnection(config) }); -const legacyPath = `${__dirname}/migrations/legacy`; -const postKnexPath = `${__dirname}/migrations`; +const legacyPath = `${__dirname}/migrations`; +const postKnexPath = `${__dirname}/migrations-post-knex`; // Connects to a database, passes it to a function for operations, then ensures its closure. const withKnex = (config) => (mutator) => { diff --git a/lib/model/migrations-post-knex/.eslintrc.json b/lib/model/migrations-post-knex/.eslintrc.json new file mode 100644 index 000000000..93a99d9dd --- /dev/null +++ b/lib/model/migrations-post-knex/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "../../../.eslintrc.json", + "rules": { + "no-restricted-modules": [ "error", { "patterns": [ "../*" ] } ] + } +} diff --git a/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js b/lib/model/migrations-post-knex/20250113-01-disable-nullable-blob-content-types.js similarity index 100% rename from lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js rename to lib/model/migrations-post-knex/20250113-01-disable-nullable-blob-content-types.js diff --git a/lib/model/migrations/legacy/20170920-01-initial.js b/lib/model/migrations/20170920-01-initial.js similarity index 100% rename from lib/model/migrations/legacy/20170920-01-initial.js rename to lib/model/migrations/20170920-01-initial.js diff --git a/lib/model/migrations/legacy/20171010-01-auth.js b/lib/model/migrations/20171010-01-auth.js similarity index 100% rename from lib/model/migrations/legacy/20171010-01-auth.js rename to lib/model/migrations/20171010-01-auth.js diff --git a/lib/model/migrations/legacy/20171023-01-authz-forms.js b/lib/model/migrations/20171023-01-authz-forms.js similarity index 100% rename from lib/model/migrations/legacy/20171023-01-authz-forms.js rename to lib/model/migrations/20171023-01-authz-forms.js diff --git a/lib/model/migrations/legacy/20171030-01-add-default-authz-records.js b/lib/model/migrations/20171030-01-add-default-authz-records.js similarity index 100% rename from lib/model/migrations/legacy/20171030-01-add-default-authz-records.js rename to lib/model/migrations/20171030-01-add-default-authz-records.js diff --git a/lib/model/migrations/legacy/20171106-01-remove-user-update-timestamp.js b/lib/model/migrations/20171106-01-remove-user-update-timestamp.js similarity index 100% rename from lib/model/migrations/legacy/20171106-01-remove-user-update-timestamp.js rename to lib/model/migrations/20171106-01-remove-user-update-timestamp.js diff --git a/lib/model/migrations/legacy/20171121-01-add-submissions-constraint.js b/lib/model/migrations/20171121-01-add-submissions-constraint.js similarity index 100% rename from lib/model/migrations/legacy/20171121-01-add-submissions-constraint.js rename to lib/model/migrations/20171121-01-add-submissions-constraint.js diff --git a/lib/model/migrations/legacy/20171121-02-add-submitter.js b/lib/model/migrations/20171121-02-add-submitter.js similarity index 100% rename from lib/model/migrations/legacy/20171121-02-add-submitter.js rename to lib/model/migrations/20171121-02-add-submitter.js diff --git a/lib/model/migrations/legacy/20171213-01-unrequire-display-name.js b/lib/model/migrations/20171213-01-unrequire-display-name.js similarity index 100% rename from lib/model/migrations/legacy/20171213-01-unrequire-display-name.js rename to lib/model/migrations/20171213-01-unrequire-display-name.js diff --git a/lib/model/migrations/legacy/20180108-01-expiring-actors.js b/lib/model/migrations/20180108-01-expiring-actors.js similarity index 100% rename from lib/model/migrations/legacy/20180108-01-expiring-actors.js rename to lib/model/migrations/20180108-01-expiring-actors.js diff --git a/lib/model/migrations/legacy/20180108-02-enum-to-varchar.js b/lib/model/migrations/20180108-02-enum-to-varchar.js similarity index 100% rename from lib/model/migrations/legacy/20180108-02-enum-to-varchar.js rename to lib/model/migrations/20180108-02-enum-to-varchar.js diff --git a/lib/model/migrations/legacy/20180112-01-audit-table.js b/lib/model/migrations/20180112-01-audit-table.js similarity index 100% rename from lib/model/migrations/legacy/20180112-01-audit-table.js rename to lib/model/migrations/20180112-01-audit-table.js diff --git a/lib/model/migrations/legacy/20180112-02-add-field-keys.js b/lib/model/migrations/20180112-02-add-field-keys.js similarity index 100% rename from lib/model/migrations/legacy/20180112-02-add-field-keys.js rename to lib/model/migrations/20180112-02-add-field-keys.js diff --git a/lib/model/migrations/legacy/20180118-01-rerequire-display-name.js b/lib/model/migrations/20180118-01-rerequire-display-name.js similarity index 100% rename from lib/model/migrations/legacy/20180118-01-rerequire-display-name.js rename to lib/model/migrations/20180118-01-rerequire-display-name.js diff --git a/lib/model/migrations/legacy/20180125-01-add-form-detail-fields.js b/lib/model/migrations/20180125-01-add-form-detail-fields.js similarity index 100% rename from lib/model/migrations/legacy/20180125-01-add-form-detail-fields.js rename to lib/model/migrations/20180125-01-add-form-detail-fields.js diff --git a/lib/model/migrations/legacy/20180125-02-more-field-key-grants.js b/lib/model/migrations/20180125-02-more-field-key-grants.js similarity index 100% rename from lib/model/migrations/legacy/20180125-02-more-field-key-grants.js rename to lib/model/migrations/20180125-02-more-field-key-grants.js diff --git a/lib/model/migrations/legacy/20180125-03-add-blob-tables.js b/lib/model/migrations/20180125-03-add-blob-tables.js similarity index 100% rename from lib/model/migrations/legacy/20180125-03-add-blob-tables.js rename to lib/model/migrations/20180125-03-add-blob-tables.js diff --git a/lib/model/migrations/legacy/20180301-01-configuration.js b/lib/model/migrations/20180301-01-configuration.js similarity index 100% rename from lib/model/migrations/legacy/20180301-01-configuration.js rename to lib/model/migrations/20180301-01-configuration.js diff --git a/lib/model/migrations/legacy/20180322-01-additional-form-options.js b/lib/model/migrations/20180322-01-additional-form-options.js similarity index 100% rename from lib/model/migrations/legacy/20180322-01-additional-form-options.js rename to lib/model/migrations/20180322-01-additional-form-options.js diff --git a/lib/model/migrations/legacy/20180327-01-update-form-constraints.js b/lib/model/migrations/20180327-01-update-form-constraints.js similarity index 100% rename from lib/model/migrations/legacy/20180327-01-update-form-constraints.js rename to lib/model/migrations/20180327-01-update-form-constraints.js diff --git a/lib/model/migrations/legacy/20180501-01-add-configs-timestamp.js b/lib/model/migrations/20180501-01-add-configs-timestamp.js similarity index 100% rename from lib/model/migrations/legacy/20180501-01-add-configs-timestamp.js rename to lib/model/migrations/20180501-01-add-configs-timestamp.js diff --git a/lib/model/migrations/legacy/20180501-02-fix-date-columns.js b/lib/model/migrations/20180501-02-fix-date-columns.js similarity index 100% rename from lib/model/migrations/legacy/20180501-02-fix-date-columns.js rename to lib/model/migrations/20180501-02-fix-date-columns.js diff --git a/lib/model/migrations/legacy/20180515-01-enforce-nonnull-form-version.js b/lib/model/migrations/20180515-01-enforce-nonnull-form-version.js similarity index 100% rename from lib/model/migrations/legacy/20180515-01-enforce-nonnull-form-version.js rename to lib/model/migrations/20180515-01-enforce-nonnull-form-version.js diff --git a/lib/model/migrations/legacy/20180727-01-rename-attachments-table.js b/lib/model/migrations/20180727-01-rename-attachments-table.js similarity index 100% rename from lib/model/migrations/legacy/20180727-01-rename-attachments-table.js rename to lib/model/migrations/20180727-01-rename-attachments-table.js diff --git a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/20180727-02-add-md5-to-blobs.js similarity index 100% rename from lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js rename to lib/model/migrations/20180727-02-add-md5-to-blobs.js diff --git a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js b/lib/model/migrations/20180727-03-add-form-attachments-table.js similarity index 100% rename from lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js rename to lib/model/migrations/20180727-03-add-form-attachments-table.js diff --git a/lib/model/migrations/legacy/20181011-make-email-case-insensitive.js b/lib/model/migrations/20181011-make-email-case-insensitive.js similarity index 100% rename from lib/model/migrations/legacy/20181011-make-email-case-insensitive.js rename to lib/model/migrations/20181011-make-email-case-insensitive.js diff --git a/lib/model/migrations/legacy/20181012-01-add-submissions-createdat-index.js b/lib/model/migrations/20181012-01-add-submissions-createdat-index.js similarity index 100% rename from lib/model/migrations/legacy/20181012-01-add-submissions-createdat-index.js rename to lib/model/migrations/20181012-01-add-submissions-createdat-index.js diff --git a/lib/model/migrations/legacy/20181206-01-add-projects.js b/lib/model/migrations/20181206-01-add-projects.js similarity index 100% rename from lib/model/migrations/legacy/20181206-01-add-projects.js rename to lib/model/migrations/20181206-01-add-projects.js diff --git a/lib/model/migrations/legacy/20181207-01-grant-verbs-to-text.js b/lib/model/migrations/20181207-01-grant-verbs-to-text.js similarity index 100% rename from lib/model/migrations/legacy/20181207-01-grant-verbs-to-text.js rename to lib/model/migrations/20181207-01-grant-verbs-to-text.js diff --git a/lib/model/migrations/legacy/20181207-02-rename-grant-verbs.js b/lib/model/migrations/20181207-02-rename-grant-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20181207-02-rename-grant-verbs.js rename to lib/model/migrations/20181207-02-rename-grant-verbs.js diff --git a/lib/model/migrations/legacy/20181211-01-audit-verbs-to-text.js b/lib/model/migrations/20181211-01-audit-verbs-to-text.js similarity index 100% rename from lib/model/migrations/legacy/20181211-01-audit-verbs-to-text.js rename to lib/model/migrations/20181211-01-audit-verbs-to-text.js diff --git a/lib/model/migrations/legacy/20181211-02-rename-audit-actions.js b/lib/model/migrations/20181211-02-rename-audit-actions.js similarity index 100% rename from lib/model/migrations/legacy/20181211-02-rename-audit-actions.js rename to lib/model/migrations/20181211-02-rename-audit-actions.js diff --git a/lib/model/migrations/legacy/20181212-00-fix-user-type.js b/lib/model/migrations/20181212-00-fix-user-type.js similarity index 100% rename from lib/model/migrations/legacy/20181212-00-fix-user-type.js rename to lib/model/migrations/20181212-00-fix-user-type.js diff --git a/lib/model/migrations/legacy/20181212-01-add-roles.js b/lib/model/migrations/20181212-01-add-roles.js similarity index 100% rename from lib/model/migrations/legacy/20181212-01-add-roles.js rename to lib/model/migrations/20181212-01-add-roles.js diff --git a/lib/model/migrations/legacy/20181212-02-remove-groups.js b/lib/model/migrations/20181212-02-remove-groups.js similarity index 100% rename from lib/model/migrations/legacy/20181212-02-remove-groups.js rename to lib/model/migrations/20181212-02-remove-groups.js diff --git a/lib/model/migrations/legacy/20181212-03-add-single-use-roles.js b/lib/model/migrations/20181212-03-add-single-use-roles.js similarity index 100% rename from lib/model/migrations/legacy/20181212-03-add-single-use-roles.js rename to lib/model/migrations/20181212-03-add-single-use-roles.js diff --git a/lib/model/migrations/legacy/20181219-01-add-submission-update-verb.js b/lib/model/migrations/20181219-01-add-submission-update-verb.js similarity index 100% rename from lib/model/migrations/legacy/20181219-01-add-submission-update-verb.js rename to lib/model/migrations/20181219-01-add-submission-update-verb.js diff --git a/lib/model/migrations/legacy/20181221-01-nullable-submission-blobs.js b/lib/model/migrations/20181221-01-nullable-submission-blobs.js similarity index 100% rename from lib/model/migrations/legacy/20181221-01-nullable-submission-blobs.js rename to lib/model/migrations/20181221-01-nullable-submission-blobs.js diff --git a/lib/model/migrations/legacy/20181230-01-add-device-id-to-submission.js b/lib/model/migrations/20181230-01-add-device-id-to-submission.js similarity index 100% rename from lib/model/migrations/legacy/20181230-01-add-device-id-to-submission.js rename to lib/model/migrations/20181230-01-add-device-id-to-submission.js diff --git a/lib/model/migrations/legacy/20190225-01-add-actor-trigram-indices.js b/lib/model/migrations/20190225-01-add-actor-trigram-indices.js similarity index 100% rename from lib/model/migrations/legacy/20190225-01-add-actor-trigram-indices.js rename to lib/model/migrations/20190225-01-add-actor-trigram-indices.js diff --git a/lib/model/migrations/legacy/20190225-02-add-role-grants.js b/lib/model/migrations/20190225-02-add-role-grants.js similarity index 100% rename from lib/model/migrations/legacy/20190225-02-add-role-grants.js rename to lib/model/migrations/20190225-02-add-role-grants.js diff --git a/lib/model/migrations/legacy/20190226-01-convert-verbs-to-jsonb.js b/lib/model/migrations/20190226-01-convert-verbs-to-jsonb.js similarity index 100% rename from lib/model/migrations/legacy/20190226-01-convert-verbs-to-jsonb.js rename to lib/model/migrations/20190226-01-convert-verbs-to-jsonb.js diff --git a/lib/model/migrations/legacy/20190226-02-add-role-actee-species.js b/lib/model/migrations/20190226-02-add-role-actee-species.js similarity index 100% rename from lib/model/migrations/legacy/20190226-02-add-role-actee-species.js rename to lib/model/migrations/20190226-02-add-role-actee-species.js diff --git a/lib/model/migrations/legacy/20190226-03-add-assignment-verbs.js b/lib/model/migrations/20190226-03-add-assignment-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20190226-03-add-assignment-verbs.js rename to lib/model/migrations/20190226-03-add-assignment-verbs.js diff --git a/lib/model/migrations/legacy/20190226-04-add-assignment-actee-species.js b/lib/model/migrations/20190226-04-add-assignment-actee-species.js similarity index 100% rename from lib/model/migrations/legacy/20190226-04-add-assignment-actee-species.js rename to lib/model/migrations/20190226-04-add-assignment-actee-species.js diff --git a/lib/model/migrations/legacy/20190227-01-add-project-manager-role.js b/lib/model/migrations/20190227-01-add-project-manager-role.js similarity index 100% rename from lib/model/migrations/legacy/20190227-01-add-project-manager-role.js rename to lib/model/migrations/20190227-01-add-project-manager-role.js diff --git a/lib/model/migrations/legacy/20190405-01-add-project-archival-flag.js b/lib/model/migrations/20190405-01-add-project-archival-flag.js similarity index 100% rename from lib/model/migrations/legacy/20190405-01-add-project-archival-flag.js rename to lib/model/migrations/20190405-01-add-project-archival-flag.js diff --git a/lib/model/migrations/legacy/20190416-01-email-uniqueness.js b/lib/model/migrations/20190416-01-email-uniqueness.js similarity index 100% rename from lib/model/migrations/legacy/20190416-01-email-uniqueness.js rename to lib/model/migrations/20190416-01-email-uniqueness.js diff --git a/lib/model/migrations/legacy/20190416-02-add-user-delete-verb.js b/lib/model/migrations/20190416-02-add-user-delete-verb.js similarity index 100% rename from lib/model/migrations/legacy/20190416-02-add-user-delete-verb.js rename to lib/model/migrations/20190416-02-add-user-delete-verb.js diff --git a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js b/lib/model/migrations/20190520-01-add-form-versioning.js similarity index 100% rename from lib/model/migrations/legacy/20190520-01-add-form-versioning.js rename to lib/model/migrations/20190520-01-add-form-versioning.js diff --git a/lib/model/migrations/legacy/20190523-01-add-form-state-constraint.js b/lib/model/migrations/20190523-01-add-form-state-constraint.js similarity index 100% rename from lib/model/migrations/legacy/20190523-01-add-form-state-constraint.js rename to lib/model/migrations/20190523-01-add-form-state-constraint.js diff --git a/lib/model/migrations/legacy/20190605-01-reformat-audits.js b/lib/model/migrations/20190605-01-reformat-audits.js similarity index 100% rename from lib/model/migrations/legacy/20190605-01-reformat-audits.js rename to lib/model/migrations/20190605-01-reformat-audits.js diff --git a/lib/model/migrations/legacy/20190607-01-convert-audit-details-to-jsonb.js b/lib/model/migrations/20190607-01-convert-audit-details-to-jsonb.js similarity index 100% rename from lib/model/migrations/legacy/20190607-01-convert-audit-details-to-jsonb.js rename to lib/model/migrations/20190607-01-convert-audit-details-to-jsonb.js diff --git a/lib/model/migrations/legacy/20190607-02-standardize-attachment-actees.js b/lib/model/migrations/20190607-02-standardize-attachment-actees.js similarity index 100% rename from lib/model/migrations/legacy/20190607-02-standardize-attachment-actees.js rename to lib/model/migrations/20190607-02-standardize-attachment-actees.js diff --git a/lib/model/migrations/legacy/20190607-03-rename-sub-attachment-audits.js b/lib/model/migrations/20190607-03-rename-sub-attachment-audits.js similarity index 100% rename from lib/model/migrations/legacy/20190607-03-rename-sub-attachment-audits.js rename to lib/model/migrations/20190607-03-rename-sub-attachment-audits.js diff --git a/lib/model/migrations/legacy/20190610-01-add-audits-verbs.js b/lib/model/migrations/20190610-01-add-audits-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20190610-01-add-audits-verbs.js rename to lib/model/migrations/20190610-01-add-audits-verbs.js diff --git a/lib/model/migrations/legacy/20190610-02-backfill-submission-audit-instanceids.js b/lib/model/migrations/20190610-02-backfill-submission-audit-instanceids.js similarity index 100% rename from lib/model/migrations/legacy/20190610-02-backfill-submission-audit-instanceids.js rename to lib/model/migrations/20190610-02-backfill-submission-audit-instanceids.js diff --git a/lib/model/migrations/legacy/20190611-01-add-updatedat-to-form-attachments.js b/lib/model/migrations/20190611-01-add-updatedat-to-form-attachments.js similarity index 100% rename from lib/model/migrations/legacy/20190611-01-add-updatedat-to-form-attachments.js rename to lib/model/migrations/20190611-01-add-updatedat-to-form-attachments.js diff --git a/lib/model/migrations/legacy/20190618-01-add-csrf-token.js b/lib/model/migrations/20190618-01-add-csrf-token.js similarity index 100% rename from lib/model/migrations/legacy/20190618-01-add-csrf-token.js rename to lib/model/migrations/20190618-01-add-csrf-token.js diff --git a/lib/model/migrations/legacy/20190618-01-add-encryption-tracking.js b/lib/model/migrations/20190618-01-add-encryption-tracking.js similarity index 100% rename from lib/model/migrations/legacy/20190618-01-add-encryption-tracking.js rename to lib/model/migrations/20190618-01-add-encryption-tracking.js diff --git a/lib/model/migrations/legacy/20190701-01-add-managed-encryption-key-check.js b/lib/model/migrations/20190701-01-add-managed-encryption-key-check.js similarity index 100% rename from lib/model/migrations/legacy/20190701-01-add-managed-encryption-key-check.js rename to lib/model/migrations/20190701-01-add-managed-encryption-key-check.js diff --git a/lib/model/migrations/legacy/20190916-01-granularize-app-user-permissions.js b/lib/model/migrations/20190916-01-granularize-app-user-permissions.js similarity index 100% rename from lib/model/migrations/legacy/20190916-01-granularize-app-user-permissions.js rename to lib/model/migrations/20190916-01-granularize-app-user-permissions.js diff --git a/lib/model/migrations/legacy/20190917-01-cleanup-app-user-role.js b/lib/model/migrations/20190917-01-cleanup-app-user-role.js similarity index 100% rename from lib/model/migrations/legacy/20190917-01-cleanup-app-user-role.js rename to lib/model/migrations/20190917-01-cleanup-app-user-role.js diff --git a/lib/model/migrations/legacy/20190923-01-add-project-viewer-role.js b/lib/model/migrations/20190923-01-add-project-viewer-role.js similarity index 100% rename from lib/model/migrations/legacy/20190923-01-add-project-viewer-role.js rename to lib/model/migrations/20190923-01-add-project-viewer-role.js diff --git a/lib/model/migrations/legacy/20190925-01-add-client-audits.js b/lib/model/migrations/20190925-01-add-client-audits.js similarity index 100% rename from lib/model/migrations/legacy/20190925-01-add-client-audits.js rename to lib/model/migrations/20190925-01-add-client-audits.js diff --git a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js b/lib/model/migrations/20191007-01-backfill-client-audits.js similarity index 100% rename from lib/model/migrations/legacy/20191007-01-backfill-client-audits.js rename to lib/model/migrations/20191007-01-backfill-client-audits.js diff --git a/lib/model/migrations/legacy/20191010-01-add-excel-blob-reference.js b/lib/model/migrations/20191010-01-add-excel-blob-reference.js similarity index 100% rename from lib/model/migrations/legacy/20191010-01-add-excel-blob-reference.js rename to lib/model/migrations/20191010-01-add-excel-blob-reference.js diff --git a/lib/model/migrations/legacy/20191023-01-add-worker-columns-to-audits.js b/lib/model/migrations/20191023-01-add-worker-columns-to-audits.js similarity index 100% rename from lib/model/migrations/legacy/20191023-01-add-worker-columns-to-audits.js rename to lib/model/migrations/20191023-01-add-worker-columns-to-audits.js diff --git a/lib/model/migrations/legacy/20191025-01-add-id-to-audits.js b/lib/model/migrations/20191025-01-add-id-to-audits.js similarity index 100% rename from lib/model/migrations/legacy/20191025-01-add-id-to-audits.js rename to lib/model/migrations/20191025-01-add-id-to-audits.js diff --git a/lib/model/migrations/legacy/20191106-01-remove-deleted-actor-assignments.js b/lib/model/migrations/20191106-01-remove-deleted-actor-assignments.js similarity index 100% rename from lib/model/migrations/legacy/20191106-01-remove-deleted-actor-assignments.js rename to lib/model/migrations/20191106-01-remove-deleted-actor-assignments.js diff --git a/lib/model/migrations/legacy/20191231-01-remove-transformations.js b/lib/model/migrations/20191231-01-remove-transformations.js similarity index 100% rename from lib/model/migrations/legacy/20191231-01-remove-transformations.js rename to lib/model/migrations/20191231-01-remove-transformations.js diff --git a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js b/lib/model/migrations/20191231-02-add-schema-storage.js similarity index 100% rename from lib/model/migrations/legacy/20191231-02-add-schema-storage.js rename to lib/model/migrations/20191231-02-add-schema-storage.js diff --git a/lib/model/migrations/legacy/20200110-01-add-drafts.js b/lib/model/migrations/20200110-01-add-drafts.js similarity index 100% rename from lib/model/migrations/legacy/20200110-01-add-drafts.js rename to lib/model/migrations/20200110-01-add-drafts.js diff --git a/lib/model/migrations/legacy/20200112-01-check-field-collisions.js b/lib/model/migrations/20200112-01-check-field-collisions.js similarity index 100% rename from lib/model/migrations/legacy/20200112-01-check-field-collisions.js rename to lib/model/migrations/20200112-01-check-field-collisions.js diff --git a/lib/model/migrations/legacy/20200114-01-remove-formid-sha256-constraint.js b/lib/model/migrations/20200114-01-remove-formid-sha256-constraint.js similarity index 100% rename from lib/model/migrations/legacy/20200114-01-remove-formid-sha256-constraint.js rename to lib/model/migrations/20200114-01-remove-formid-sha256-constraint.js diff --git a/lib/model/migrations/legacy/20200117-01-draft-test-submissions.js b/lib/model/migrations/20200117-01-draft-test-submissions.js similarity index 100% rename from lib/model/migrations/legacy/20200117-01-draft-test-submissions.js rename to lib/model/migrations/20200117-01-draft-test-submissions.js diff --git a/lib/model/migrations/legacy/20200121-01-add-draft-keys.js b/lib/model/migrations/20200121-01-add-draft-keys.js similarity index 100% rename from lib/model/migrations/legacy/20200121-01-add-draft-keys.js rename to lib/model/migrations/20200121-01-add-draft-keys.js diff --git a/lib/model/migrations/legacy/20200122-01-remove-draft-form-state.js b/lib/model/migrations/20200122-01-remove-draft-form-state.js similarity index 100% rename from lib/model/migrations/legacy/20200122-01-remove-draft-form-state.js rename to lib/model/migrations/20200122-01-remove-draft-form-state.js diff --git a/lib/model/migrations/legacy/20200129-01-cascade-submission-deletes.js b/lib/model/migrations/20200129-01-cascade-submission-deletes.js similarity index 100% rename from lib/model/migrations/legacy/20200129-01-cascade-submission-deletes.js rename to lib/model/migrations/20200129-01-cascade-submission-deletes.js diff --git a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js b/lib/model/migrations/20200220-01-repair-submission-parsing.js similarity index 100% rename from lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js rename to lib/model/migrations/20200220-01-repair-submission-parsing.js diff --git a/lib/model/migrations/legacy/20200403-01-add-performance-indices.js b/lib/model/migrations/20200403-01-add-performance-indices.js similarity index 100% rename from lib/model/migrations/legacy/20200403-01-add-performance-indices.js rename to lib/model/migrations/20200403-01-add-performance-indices.js diff --git a/lib/model/migrations/legacy/20200407-01-allow-actorless-submission-defs.js b/lib/model/migrations/20200407-01-allow-actorless-submission-defs.js similarity index 100% rename from lib/model/migrations/legacy/20200407-01-allow-actorless-submission-defs.js rename to lib/model/migrations/20200407-01-allow-actorless-submission-defs.js diff --git a/lib/model/migrations/legacy/20200423-01-fix-field-insert-performance.js b/lib/model/migrations/20200423-01-fix-field-insert-performance.js similarity index 100% rename from lib/model/migrations/legacy/20200423-01-fix-field-insert-performance.js rename to lib/model/migrations/20200423-01-fix-field-insert-performance.js diff --git a/lib/model/migrations/legacy/20200428-01-allow-string-downcast.js b/lib/model/migrations/20200428-01-allow-string-downcast.js similarity index 100% rename from lib/model/migrations/legacy/20200428-01-allow-string-downcast.js rename to lib/model/migrations/20200428-01-allow-string-downcast.js diff --git a/lib/model/migrations/legacy/20200519-01-add-enketo-id.js b/lib/model/migrations/20200519-01-add-enketo-id.js similarity index 100% rename from lib/model/migrations/legacy/20200519-01-add-enketo-id.js rename to lib/model/migrations/20200519-01-add-enketo-id.js diff --git a/lib/model/migrations/legacy/20200519-02-add-form-viewer-role.js b/lib/model/migrations/20200519-02-add-form-viewer-role.js similarity index 100% rename from lib/model/migrations/legacy/20200519-02-add-form-viewer-role.js rename to lib/model/migrations/20200519-02-add-form-viewer-role.js diff --git a/lib/model/migrations/legacy/20200520-01-backfill-enketo.js b/lib/model/migrations/20200520-01-backfill-enketo.js similarity index 100% rename from lib/model/migrations/legacy/20200520-01-backfill-enketo.js rename to lib/model/migrations/20200520-01-backfill-enketo.js diff --git a/lib/model/migrations/legacy/20200715-01-add-data-collector-role.js b/lib/model/migrations/20200715-01-add-data-collector-role.js similarity index 100% rename from lib/model/migrations/legacy/20200715-01-add-data-collector-role.js rename to lib/model/migrations/20200715-01-add-data-collector-role.js diff --git a/lib/model/migrations/legacy/20200721-01-add-public-links.js b/lib/model/migrations/20200721-01-add-public-links.js similarity index 100% rename from lib/model/migrations/legacy/20200721-01-add-public-links.js rename to lib/model/migrations/20200721-01-add-public-links.js diff --git a/lib/model/migrations/legacy/20200728-01-add-enketo-single-token-to-forms.js b/lib/model/migrations/20200728-01-add-enketo-single-token-to-forms.js similarity index 100% rename from lib/model/migrations/legacy/20200728-01-add-enketo-single-token-to-forms.js rename to lib/model/migrations/20200728-01-add-enketo-single-token-to-forms.js diff --git a/lib/model/migrations/legacy/20200731-01-allow-project-managers-to-end-sessions.js b/lib/model/migrations/20200731-01-allow-project-managers-to-end-sessions.js similarity index 100% rename from lib/model/migrations/legacy/20200731-01-allow-project-managers-to-end-sessions.js rename to lib/model/migrations/20200731-01-allow-project-managers-to-end-sessions.js diff --git a/lib/model/migrations/legacy/20200810-01-reschedule-enketo-processing.js b/lib/model/migrations/20200810-01-reschedule-enketo-processing.js similarity index 100% rename from lib/model/migrations/legacy/20200810-01-reschedule-enketo-processing.js rename to lib/model/migrations/20200810-01-reschedule-enketo-processing.js diff --git a/lib/model/migrations/legacy/20200918-01-repair-publishedat-dates.js b/lib/model/migrations/20200918-01-repair-publishedat-dates.js similarity index 100% rename from lib/model/migrations/legacy/20200918-01-repair-publishedat-dates.js rename to lib/model/migrations/20200918-01-repair-publishedat-dates.js diff --git a/lib/model/migrations/legacy/20200930-01-add-backup-run-verb.js b/lib/model/migrations/20200930-01-add-backup-run-verb.js similarity index 100% rename from lib/model/migrations/legacy/20200930-01-add-backup-run-verb.js rename to lib/model/migrations/20200930-01-add-backup-run-verb.js diff --git a/lib/model/migrations/legacy/20201117-01-remove-deleted-actor-assignments-again.js b/lib/model/migrations/20201117-01-remove-deleted-actor-assignments-again.js similarity index 100% rename from lib/model/migrations/legacy/20201117-01-remove-deleted-actor-assignments-again.js rename to lib/model/migrations/20201117-01-remove-deleted-actor-assignments-again.js diff --git a/lib/model/migrations/legacy/20201207-01-harmonize-submitter-id-columns.js b/lib/model/migrations/20201207-01-harmonize-submitter-id-columns.js similarity index 100% rename from lib/model/migrations/legacy/20201207-01-harmonize-submitter-id-columns.js rename to lib/model/migrations/20201207-01-harmonize-submitter-id-columns.js diff --git a/lib/model/migrations/legacy/20210118-01-add-current-flag-to-submission-defs.js b/lib/model/migrations/20210118-01-add-current-flag-to-submission-defs.js similarity index 100% rename from lib/model/migrations/legacy/20210118-01-add-current-flag-to-submission-defs.js rename to lib/model/migrations/20210118-01-add-current-flag-to-submission-defs.js diff --git a/lib/model/migrations/legacy/20210120-01-instance-names.js b/lib/model/migrations/20210120-01-instance-names.js similarity index 100% rename from lib/model/migrations/legacy/20210120-01-instance-names.js rename to lib/model/migrations/20210120-01-instance-names.js diff --git a/lib/model/migrations/legacy/20210203-01-add-hierarchy-to-actees.js b/lib/model/migrations/20210203-01-add-hierarchy-to-actees.js similarity index 100% rename from lib/model/migrations/legacy/20210203-01-add-hierarchy-to-actees.js rename to lib/model/migrations/20210203-01-add-hierarchy-to-actees.js diff --git a/lib/model/migrations/legacy/20210210-01-add-instanceid-to-submission-defs.js b/lib/model/migrations/20210210-01-add-instanceid-to-submission-defs.js similarity index 100% rename from lib/model/migrations/legacy/20210210-01-add-instanceid-to-submission-defs.js rename to lib/model/migrations/20210210-01-add-instanceid-to-submission-defs.js diff --git a/lib/model/migrations/legacy/20210218-01-add-submission-edit-verbs.js b/lib/model/migrations/20210218-01-add-submission-edit-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20210218-01-add-submission-edit-verbs.js rename to lib/model/migrations/20210218-01-add-submission-edit-verbs.js diff --git a/lib/model/migrations/legacy/20210218-02-add-draft-to-submissions-unique.js b/lib/model/migrations/20210218-02-add-draft-to-submissions-unique.js similarity index 100% rename from lib/model/migrations/legacy/20210218-02-add-draft-to-submissions-unique.js rename to lib/model/migrations/20210218-02-add-draft-to-submissions-unique.js diff --git a/lib/model/migrations/legacy/20210219-01-add-review-state.js b/lib/model/migrations/20210219-01-add-review-state.js similarity index 100% rename from lib/model/migrations/legacy/20210219-01-add-review-state.js rename to lib/model/migrations/20210219-01-add-review-state.js diff --git a/lib/model/migrations/legacy/20210219-02-add-notes-and-index-to-audits.js b/lib/model/migrations/20210219-02-add-notes-and-index-to-audits.js similarity index 100% rename from lib/model/migrations/legacy/20210219-02-add-notes-and-index-to-audits.js rename to lib/model/migrations/20210219-02-add-notes-and-index-to-audits.js diff --git a/lib/model/migrations/legacy/20210324-01-add-submission-edit-verbs-to-managers.js b/lib/model/migrations/20210324-01-add-submission-edit-verbs-to-managers.js similarity index 100% rename from lib/model/migrations/legacy/20210324-01-add-submission-edit-verbs-to-managers.js rename to lib/model/migrations/20210324-01-add-submission-edit-verbs-to-managers.js diff --git a/lib/model/migrations/legacy/20210325-01-remove-project.list-verb.js b/lib/model/migrations/20210325-01-remove-project.list-verb.js similarity index 100% rename from lib/model/migrations/legacy/20210325-01-remove-project.list-verb.js rename to lib/model/migrations/20210325-01-remove-project.list-verb.js diff --git a/lib/model/migrations/legacy/20210408-01-drop-public-link-createdat.js b/lib/model/migrations/20210408-01-drop-public-link-createdat.js similarity index 100% rename from lib/model/migrations/legacy/20210408-01-drop-public-link-createdat.js rename to lib/model/migrations/20210408-01-drop-public-link-createdat.js diff --git a/lib/model/migrations/legacy/20210408-02-backfill-specialized-actor-audits.js b/lib/model/migrations/20210408-02-backfill-specialized-actor-audits.js similarity index 100% rename from lib/model/migrations/legacy/20210408-02-backfill-specialized-actor-audits.js rename to lib/model/migrations/20210408-02-backfill-specialized-actor-audits.js diff --git a/lib/model/migrations/legacy/20210409-01-add-comments.js b/lib/model/migrations/20210409-01-add-comments.js similarity index 100% rename from lib/model/migrations/legacy/20210409-01-add-comments.js rename to lib/model/migrations/20210409-01-add-comments.js diff --git a/lib/model/migrations/legacy/20210409-02-update-review-states.js b/lib/model/migrations/20210409-02-update-review-states.js similarity index 100% rename from lib/model/migrations/legacy/20210409-02-update-review-states.js rename to lib/model/migrations/20210409-02-update-review-states.js diff --git a/lib/model/migrations/legacy/20210423-01-add-name-to-form-def.js b/lib/model/migrations/20210423-01-add-name-to-form-def.js similarity index 100% rename from lib/model/migrations/legacy/20210423-01-add-name-to-form-def.js rename to lib/model/migrations/20210423-01-add-name-to-form-def.js diff --git a/lib/model/migrations/legacy/20210423-02-drop-form-name.js b/lib/model/migrations/20210423-02-drop-form-name.js similarity index 100% rename from lib/model/migrations/legacy/20210423-02-drop-form-name.js rename to lib/model/migrations/20210423-02-drop-form-name.js diff --git a/lib/model/migrations/legacy/20210716-01-config-value-jsonb.js b/lib/model/migrations/20210716-01-config-value-jsonb.js similarity index 100% rename from lib/model/migrations/legacy/20210716-01-config-value-jsonb.js rename to lib/model/migrations/20210716-01-config-value-jsonb.js diff --git a/lib/model/migrations/legacy/20210721-01-add-config-set-verb.js b/lib/model/migrations/20210721-01-add-config-set-verb.js similarity index 100% rename from lib/model/migrations/legacy/20210721-01-add-config-set-verb.js rename to lib/model/migrations/20210721-01-add-config-set-verb.js diff --git a/lib/model/migrations/legacy/20210817-01-disallow-structure-downcast-to-string.js b/lib/model/migrations/20210817-01-disallow-structure-downcast-to-string.js similarity index 100% rename from lib/model/migrations/legacy/20210817-01-disallow-structure-downcast-to-string.js rename to lib/model/migrations/20210817-01-disallow-structure-downcast-to-string.js diff --git a/lib/model/migrations/legacy/20210825-01-add-analytics-read-verb.js b/lib/model/migrations/20210825-01-add-analytics-read-verb.js similarity index 100% rename from lib/model/migrations/legacy/20210825-01-add-analytics-read-verb.js rename to lib/model/migrations/20210825-01-add-analytics-read-verb.js diff --git a/lib/model/migrations/legacy/20210903-01-backfill-encrypted-client-audits.js b/lib/model/migrations/20210903-01-backfill-encrypted-client-audits.js similarity index 100% rename from lib/model/migrations/legacy/20210903-01-backfill-encrypted-client-audits.js rename to lib/model/migrations/20210903-01-backfill-encrypted-client-audits.js diff --git a/lib/model/migrations/legacy/20210927-01-revert-disallow-structure-downcast.js b/lib/model/migrations/20210927-01-revert-disallow-structure-downcast.js similarity index 100% rename from lib/model/migrations/legacy/20210927-01-revert-disallow-structure-downcast.js rename to lib/model/migrations/20210927-01-revert-disallow-structure-downcast.js diff --git a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js b/lib/model/migrations/20211008-01-track-select-many-options.js similarity index 100% rename from lib/model/migrations/legacy/20211008-01-track-select-many-options.js rename to lib/model/migrations/20211008-01-track-select-many-options.js diff --git a/lib/model/migrations/legacy/20211021-remove-hashes-from-audits.js b/lib/model/migrations/20211021-remove-hashes-from-audits.js similarity index 100% rename from lib/model/migrations/legacy/20211021-remove-hashes-from-audits.js rename to lib/model/migrations/20211021-remove-hashes-from-audits.js diff --git a/lib/model/migrations/legacy/20211109-01-add-user-agent-to-submissions.js b/lib/model/migrations/20211109-01-add-user-agent-to-submissions.js similarity index 100% rename from lib/model/migrations/legacy/20211109-01-add-user-agent-to-submissions.js rename to lib/model/migrations/20211109-01-add-user-agent-to-submissions.js diff --git a/lib/model/migrations/legacy/20211114-01-flag-initial-submission-def.js b/lib/model/migrations/20211114-01-flag-initial-submission-def.js similarity index 100% rename from lib/model/migrations/legacy/20211114-01-flag-initial-submission-def.js rename to lib/model/migrations/20211114-01-flag-initial-submission-def.js diff --git a/lib/model/migrations/legacy/20211117-01-add-form-restore-verb.js b/lib/model/migrations/20211117-01-add-form-restore-verb.js similarity index 100% rename from lib/model/migrations/legacy/20211117-01-add-form-restore-verb.js rename to lib/model/migrations/20211117-01-add-form-restore-verb.js diff --git a/lib/model/migrations/legacy/20211129-01-add-purged-details-to-actees.js b/lib/model/migrations/20211129-01-add-purged-details-to-actees.js similarity index 100% rename from lib/model/migrations/legacy/20211129-01-add-purged-details-to-actees.js rename to lib/model/migrations/20211129-01-add-purged-details-to-actees.js diff --git a/lib/model/migrations/legacy/20220121-01-form-cascade-delete.js b/lib/model/migrations/20220121-01-form-cascade-delete.js similarity index 100% rename from lib/model/migrations/legacy/20220121-01-form-cascade-delete.js rename to lib/model/migrations/20220121-01-form-cascade-delete.js diff --git a/lib/model/migrations/legacy/20220121-02-purge-deleted-forms.js b/lib/model/migrations/20220121-02-purge-deleted-forms.js similarity index 100% rename from lib/model/migrations/legacy/20220121-02-purge-deleted-forms.js rename to lib/model/migrations/20220121-02-purge-deleted-forms.js diff --git a/lib/model/migrations/legacy/20220209-01-purge-unneeded-drafts.js b/lib/model/migrations/20220209-01-purge-unneeded-drafts.js similarity index 100% rename from lib/model/migrations/legacy/20220209-01-purge-unneeded-drafts.js rename to lib/model/migrations/20220209-01-purge-unneeded-drafts.js diff --git a/lib/model/migrations/legacy/20220309-01-add-project-description.js b/lib/model/migrations/20220309-01-add-project-description.js similarity index 100% rename from lib/model/migrations/legacy/20220309-01-add-project-description.js rename to lib/model/migrations/20220309-01-add-project-description.js diff --git a/lib/model/migrations/legacy/20220803-01-create-entities-schema.js b/lib/model/migrations/20220803-01-create-entities-schema.js similarity index 100% rename from lib/model/migrations/legacy/20220803-01-create-entities-schema.js rename to lib/model/migrations/20220803-01-create-entities-schema.js diff --git a/lib/model/migrations/legacy/20221003-01-add-dataset-verbs.js b/lib/model/migrations/20221003-01-add-dataset-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20221003-01-add-dataset-verbs.js rename to lib/model/migrations/20221003-01-add-dataset-verbs.js diff --git a/lib/model/migrations/legacy/20221114-01-explict-dataset-publish.js b/lib/model/migrations/20221114-01-explict-dataset-publish.js similarity index 100% rename from lib/model/migrations/legacy/20221114-01-explict-dataset-publish.js rename to lib/model/migrations/20221114-01-explict-dataset-publish.js diff --git a/lib/model/migrations/legacy/20221117-01-check-datasetId-is-null-for-non-file-type.js b/lib/model/migrations/20221117-01-check-datasetId-is-null-for-non-file-type.js similarity index 100% rename from lib/model/migrations/legacy/20221117-01-check-datasetId-is-null-for-non-file-type.js rename to lib/model/migrations/20221117-01-check-datasetId-is-null-for-non-file-type.js diff --git a/lib/model/migrations/legacy/20221118-01-make-entities-columns-not-null.js b/lib/model/migrations/20221118-01-make-entities-columns-not-null.js similarity index 100% rename from lib/model/migrations/legacy/20221118-01-make-entities-columns-not-null.js rename to lib/model/migrations/20221118-01-make-entities-columns-not-null.js diff --git a/lib/model/migrations/legacy/20221208-01-reduce-tz-precision.js b/lib/model/migrations/20221208-01-reduce-tz-precision.js similarity index 100% rename from lib/model/migrations/legacy/20221208-01-reduce-tz-precision.js rename to lib/model/migrations/20221208-01-reduce-tz-precision.js diff --git a/lib/model/migrations/legacy/20230106-01-remove-revision-number.js b/lib/model/migrations/20230106-01-remove-revision-number.js similarity index 100% rename from lib/model/migrations/legacy/20230106-01-remove-revision-number.js rename to lib/model/migrations/20230106-01-remove-revision-number.js diff --git a/lib/model/migrations/legacy/20230109-01-add-form-schema.js b/lib/model/migrations/20230109-01-add-form-schema.js similarity index 100% rename from lib/model/migrations/legacy/20230109-01-add-form-schema.js rename to lib/model/migrations/20230109-01-add-form-schema.js diff --git a/lib/model/migrations/legacy/20230123-01-remove-google-backups.js b/lib/model/migrations/20230123-01-remove-google-backups.js similarity index 100% rename from lib/model/migrations/legacy/20230123-01-remove-google-backups.js rename to lib/model/migrations/20230123-01-remove-google-backups.js diff --git a/lib/model/migrations/legacy/20230126-01-add-entity-indices.js b/lib/model/migrations/20230126-01-add-entity-indices.js similarity index 100% rename from lib/model/migrations/legacy/20230126-01-add-entity-indices.js rename to lib/model/migrations/20230126-01-add-entity-indices.js diff --git a/lib/model/migrations/legacy/20230127-01-rename-entity-created-by.js b/lib/model/migrations/20230127-01-rename-entity-created-by.js similarity index 100% rename from lib/model/migrations/legacy/20230127-01-rename-entity-created-by.js rename to lib/model/migrations/20230127-01-rename-entity-created-by.js diff --git a/lib/model/migrations/legacy/20230324-01-edit-dataset-verbs.js b/lib/model/migrations/20230324-01-edit-dataset-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20230324-01-edit-dataset-verbs.js rename to lib/model/migrations/20230324-01-edit-dataset-verbs.js diff --git a/lib/model/migrations/legacy/20230406-01-add-entity-def-fields.js b/lib/model/migrations/20230406-01-add-entity-def-fields.js similarity index 100% rename from lib/model/migrations/legacy/20230406-01-add-entity-def-fields.js rename to lib/model/migrations/20230406-01-add-entity-def-fields.js diff --git a/lib/model/migrations/legacy/20230406-02-move-entity-label-add-deletedAt.js b/lib/model/migrations/20230406-02-move-entity-label-add-deletedAt.js similarity index 100% rename from lib/model/migrations/legacy/20230406-02-move-entity-label-add-deletedAt.js rename to lib/model/migrations/20230406-02-move-entity-label-add-deletedAt.js diff --git a/lib/model/migrations/legacy/20230414-01-remove-user-mfa-secret.js b/lib/model/migrations/20230414-01-remove-user-mfa-secret.js similarity index 100% rename from lib/model/migrations/legacy/20230414-01-remove-user-mfa-secret.js rename to lib/model/migrations/20230414-01-remove-user-mfa-secret.js diff --git a/lib/model/migrations/legacy/20230419-01-optimize-indices-sub-defs.js b/lib/model/migrations/20230419-01-optimize-indices-sub-defs.js similarity index 100% rename from lib/model/migrations/legacy/20230419-01-optimize-indices-sub-defs.js rename to lib/model/migrations/20230419-01-optimize-indices-sub-defs.js diff --git a/lib/model/migrations/legacy/20230509-01-dataset-approval-flag.js b/lib/model/migrations/20230509-01-dataset-approval-flag.js similarity index 100% rename from lib/model/migrations/legacy/20230509-01-dataset-approval-flag.js rename to lib/model/migrations/20230509-01-dataset-approval-flag.js diff --git a/lib/model/migrations/legacy/20230512-01-add-entity-root.js b/lib/model/migrations/20230512-01-add-entity-root.js similarity index 100% rename from lib/model/migrations/legacy/20230512-01-add-entity-root.js rename to lib/model/migrations/20230512-01-add-entity-root.js diff --git a/lib/model/migrations/legacy/20230512-02-backfill-entity-id.js b/lib/model/migrations/20230512-02-backfill-entity-id.js similarity index 100% rename from lib/model/migrations/legacy/20230512-02-backfill-entity-id.js rename to lib/model/migrations/20230512-02-backfill-entity-id.js diff --git a/lib/model/migrations/legacy/20230512-03-add-entity-source.js b/lib/model/migrations/20230512-03-add-entity-source.js similarity index 100% rename from lib/model/migrations/legacy/20230512-03-add-entity-source.js rename to lib/model/migrations/20230512-03-add-entity-source.js diff --git a/lib/model/migrations/legacy/20230518-01-add-entity-index-to-audits.js b/lib/model/migrations/20230518-01-add-entity-index-to-audits.js similarity index 100% rename from lib/model/migrations/legacy/20230518-01-add-entity-index-to-audits.js rename to lib/model/migrations/20230518-01-add-entity-index-to-audits.js diff --git a/lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js b/lib/model/migrations/20230802-01-delete-orphan-submissions.js similarity index 100% rename from lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js rename to lib/model/migrations/20230802-01-delete-orphan-submissions.js diff --git a/lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js b/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js similarity index 100% rename from lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js rename to lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js diff --git a/lib/model/migrations/legacy/20230824-01-add-entity-version.js b/lib/model/migrations/20230824-01-add-entity-version.js similarity index 100% rename from lib/model/migrations/legacy/20230824-01-add-entity-version.js rename to lib/model/migrations/20230824-01-add-entity-version.js diff --git a/lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js b/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js similarity index 100% rename from lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js rename to lib/model/migrations/20230830-01-remove-entity-label-from-audits.js diff --git a/lib/model/migrations/legacy/20230907-01-opened-form-verb.js b/lib/model/migrations/20230907-01-opened-form-verb.js similarity index 100% rename from lib/model/migrations/legacy/20230907-01-opened-form-verb.js rename to lib/model/migrations/20230907-01-opened-form-verb.js diff --git a/lib/model/migrations/legacy/20231002-01-add-conflict-details.js b/lib/model/migrations/20231002-01-add-conflict-details.js similarity index 100% rename from lib/model/migrations/legacy/20231002-01-add-conflict-details.js rename to lib/model/migrations/20231002-01-add-conflict-details.js diff --git a/lib/model/migrations/legacy/20231013-01-change-entity-error-action.js b/lib/model/migrations/20231013-01-change-entity-error-action.js similarity index 100% rename from lib/model/migrations/legacy/20231013-01-change-entity-error-action.js rename to lib/model/migrations/20231013-01-change-entity-error-action.js diff --git a/lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js b/lib/model/migrations/20231208-01-dataset-form-def-actions.js similarity index 100% rename from lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js rename to lib/model/migrations/20231208-01-dataset-form-def-actions.js diff --git a/lib/model/migrations/legacy/20240215-01-entity-delete-verb.js b/lib/model/migrations/20240215-01-entity-delete-verb.js similarity index 100% rename from lib/model/migrations/legacy/20240215-01-entity-delete-verb.js rename to lib/model/migrations/20240215-01-entity-delete-verb.js diff --git a/lib/model/migrations/legacy/20240215-02-dedupe-verbs.js b/lib/model/migrations/20240215-02-dedupe-verbs.js similarity index 100% rename from lib/model/migrations/legacy/20240215-02-dedupe-verbs.js rename to lib/model/migrations/20240215-02-dedupe-verbs.js diff --git a/lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js b/lib/model/migrations/20240312-01-add-dataset-create-verb.js similarity index 100% rename from lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js rename to lib/model/migrations/20240312-01-add-dataset-create-verb.js diff --git a/lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js b/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js similarity index 100% rename from lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js rename to lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js diff --git a/lib/model/migrations/legacy/20240515-01-entity-tz-precision.js b/lib/model/migrations/20240515-01-entity-tz-precision.js similarity index 100% rename from lib/model/migrations/legacy/20240515-01-entity-tz-precision.js rename to lib/model/migrations/20240515-01-entity-tz-precision.js diff --git a/lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js b/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js similarity index 100% rename from lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js rename to lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js diff --git a/lib/model/migrations/legacy/20240607-02-add-submission-backlog.js b/lib/model/migrations/20240607-02-add-submission-backlog.js similarity index 100% rename from lib/model/migrations/legacy/20240607-02-add-submission-backlog.js rename to lib/model/migrations/20240607-02-add-submission-backlog.js diff --git a/lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js b/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js similarity index 100% rename from lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js rename to lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js diff --git a/lib/model/migrations/legacy/20240913-01-add-blob-s3.js b/lib/model/migrations/20240913-01-add-blob-s3.js similarity index 100% rename from lib/model/migrations/legacy/20240913-01-add-blob-s3.js rename to lib/model/migrations/20240913-01-add-blob-s3.js diff --git a/lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js b/lib/model/migrations/20240914-01-add-submission-delete-verb.js similarity index 100% rename from lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js rename to lib/model/migrations/20240914-01-add-submission-delete-verb.js diff --git a/lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js similarity index 100% rename from lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js rename to lib/model/migrations/20240914-02-remove-orphaned-client-audits.js diff --git a/lib/model/migrations/legacy/20241001-01-index-on-session-table.js b/lib/model/migrations/20241001-01-index-on-session-table.js similarity index 100% rename from lib/model/migrations/legacy/20241001-01-index-on-session-table.js rename to lib/model/migrations/20241001-01-index-on-session-table.js diff --git a/lib/model/migrations/legacy/20241008-01-add-user_preferences.js b/lib/model/migrations/20241008-01-add-user_preferences.js similarity index 100% rename from lib/model/migrations/legacy/20241008-01-add-user_preferences.js rename to lib/model/migrations/20241008-01-add-user_preferences.js diff --git a/lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js similarity index 100% rename from lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js rename to lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js diff --git a/lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js b/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js similarity index 100% rename from lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js rename to lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js diff --git a/lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js b/lib/model/migrations/20241030-01-add-force-entity-def-source.js similarity index 100% rename from lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js rename to lib/model/migrations/20241030-01-add-force-entity-def-source.js From de1e5d78c54a4a4c14184716c785963d8018e59c Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:28:02 +0000 Subject: [PATCH 018/133] Add TODOs --- lib/model/migrate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/model/migrate.js b/lib/model/migrate.js index 6e25cfa3b..27d84ffe8 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -20,8 +20,8 @@ const { knexConnection } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. const initKnex = (config) => knex({ client: 'pg', connection: knexConnection(config) }); -const legacyPath = `${__dirname}/migrations`; -const postKnexPath = `${__dirname}/migrations-post-knex`; +const legacyPath = `${__dirname}/migrations`; // TODO rename to /migrations/legacy +const postKnexPath = `${__dirname}/migrations-post-knex`; // TODO rename to /migrations/current // Connects to a database, passes it to a function for operations, then ensures its closure. const withKnex = (config) => (mutator) => { From 887c492c6fbf9e5baf0cea20ff23b3cbacf33f94 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:30:26 +0000 Subject: [PATCH 019/133] remove lint changes to legacy migrations --- lib/model/migrations/.eslintrc.json | 6 ------ lib/model/migrations/20180727-02-add-md5-to-blobs.js | 2 +- .../migrations/20180727-03-add-form-attachments-table.js | 2 +- lib/model/migrations/20190520-01-add-form-versioning.js | 2 +- .../migrations/20191007-01-backfill-client-audits.js | 6 +++--- lib/model/migrations/20191231-02-add-schema-storage.js | 4 ++-- .../migrations/20200220-01-repair-submission-parsing.js | 2 +- lib/model/migrations/20210120-01-instance-names.js | 2 +- .../migrations/20211008-01-track-select-many-options.js | 8 ++++---- lib/model/migrations/20230109-01-add-form-schema.js | 2 +- 10 files changed, 15 insertions(+), 21 deletions(-) delete mode 100644 lib/model/migrations/.eslintrc.json diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/.eslintrc.json deleted file mode 100644 index 93a99d9dd..000000000 --- a/lib/model/migrations/.eslintrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../../../.eslintrc.json", - "rules": { - "no-restricted-modules": [ "error", { "patterns": [ "../*" ] } ] - } -} diff --git a/lib/model/migrations/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/20180727-02-add-md5-to-blobs.js index 5fa121135..de05f99a4 100644 --- a/lib/model/migrations/20180727-02-add-md5-to-blobs.js +++ b/lib/model/migrations/20180727-02-add-md5-to-blobs.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. // -const { md5sum } = require('../../../util/crypto'); // eslint-disable-line no-restricted-modules +const { md5sum } = require('../../util/crypto'); const up = (knex) => knex.schema.table('blobs', (blobs) => { blobs.string('md5', 32); }) diff --git a/lib/model/migrations/20180727-03-add-form-attachments-table.js b/lib/model/migrations/20180727-03-add-form-attachments-table.js index c48ceb758..80aea61ab 100644 --- a/lib/model/migrations/20180727-03-add-form-attachments-table.js +++ b/lib/model/migrations/20180727-03-add-form-attachments-table.js @@ -23,7 +23,7 @@ const up = (knex) => fa.index([ 'formId' ]); }).then(() => { - const { expectedFormAttachments } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules + const { expectedFormAttachments } = require('../../data/schema'); const { uniq, pluck } = require('ramda'); // now add all expected attachments on extant forms. diff --git a/lib/model/migrations/20190520-01-add-form-versioning.js b/lib/model/migrations/20190520-01-add-form-versioning.js index 623e966c9..2d11c8ce3 100644 --- a/lib/model/migrations/20190520-01-add-form-versioning.js +++ b/lib/model/migrations/20190520-01-add-form-versioning.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { shasum, sha256sum } = require('../../../util/crypto'); // eslint-disable-line no-restricted-modules +const { shasum, sha256sum } = require('../../util/crypto'); const assert = require('assert').strict; const check = (message, query) => diff --git a/lib/model/migrations/20191007-01-backfill-client-audits.js b/lib/model/migrations/20191007-01-backfill-client-audits.js index 5f79a3821..c6551c255 100644 --- a/lib/model/migrations/20191007-01-backfill-client-audits.js +++ b/lib/model/migrations/20191007-01-backfill-client-audits.js @@ -7,9 +7,9 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { parseClientAudits } = require('../../../data/client-audits'); // eslint-disable-line no-restricted-modules -const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules -const { traverseXml, findOne, root, node, text } = require('../../../util/xml'); // eslint-disable-line no-restricted-modules +const { parseClientAudits } = require('../../data/client-audits'); +const { getFormFields } = require('../../data/schema'); +const { traverseXml, findOne, root, node, text } = require('../../util/xml'); const up = (db) => new Promise((resolve, reject) => { const work = []; diff --git a/lib/model/migrations/20191231-02-add-schema-storage.js b/lib/model/migrations/20191231-02-add-schema-storage.js index da84931f6..ec317539e 100644 --- a/lib/model/migrations/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/20191231-02-add-schema-storage.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../data/schema'); const up = async (db) => { await db.schema.createTable('form_fields', (fields) => { @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../../migrate').connect(config); // eslint-disable-line no-restricted-modules + const db2 = require('../migrate').connect(config); return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/lib/model/migrations/20200220-01-repair-submission-parsing.js b/lib/model/migrations/20200220-01-repair-submission-parsing.js index d4020bc25..d1bd9e0ee 100644 --- a/lib/model/migrations/20200220-01-repair-submission-parsing.js +++ b/lib/model/migrations/20200220-01-repair-submission-parsing.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../../frames'); // eslint-disable-line no-restricted-modules +const { Submission } = require('../frames'); const up = async (db) => { const work = []; diff --git a/lib/model/migrations/20210120-01-instance-names.js b/lib/model/migrations/20210120-01-instance-names.js index 6c6cde9d9..832407dfc 100644 --- a/lib/model/migrations/20210120-01-instance-names.js +++ b/lib/model/migrations/20210120-01-instance-names.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../../frames'); // eslint-disable-line no-restricted-modules +const { Submission } = require('../frames'); const up = async (db) => { await db.schema.table('submission_defs', (sds) => { diff --git a/lib/model/migrations/20211008-01-track-select-many-options.js b/lib/model/migrations/20211008-01-track-select-many-options.js index 09f1efa92..413e0f1aa 100644 --- a/lib/model/migrations/20211008-01-track-select-many-options.js +++ b/lib/model/migrations/20211008-01-track-select-many-options.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const { map } = require('ramda'); -const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules -const { getSelectMultipleResponses } = require('../../../data/submission'); // eslint-disable-line no-restricted-modules -const { Form } = require('../../frames'); // eslint-disable-line no-restricted-modules -const { construct } = require('../../../util/util'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../data/schema'); +const { getSelectMultipleResponses } = require('../../data/submission'); +const { Form } = require('../frames'); +const { construct } = require('../../util/util'); const up = async (db) => { // add select many flag, options field to fields diff --git a/lib/model/migrations/20230109-01-add-form-schema.js b/lib/model/migrations/20230109-01-add-form-schema.js index 63c2cd903..3f591473e 100644 --- a/lib/model/migrations/20230109-01-add-form-schema.js +++ b/lib/model/migrations/20230109-01-add-form-schema.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields, compare } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules +const { getFormFields, compare } = require('../../data/schema'); /* Steps of this migration 1. remove check field collision trigger From ed41ada82be991c2c39383ea349e26041fb140e8 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:31:49 +0000 Subject: [PATCH 020/133] revert debug --- lib/task/task.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/task/task.js b/lib/task/task.js index 6f9a1eb13..516e6c29d 100644 --- a/lib/task/task.js +++ b/lib/task/task.js @@ -75,7 +75,6 @@ const writeTo = (output) => (x) => output.write(`${x}\n`); const writeToStderr = writeTo(process.stderr); /* istanbul ignore next */ const fault = (error) => { - console.log('fault()', error); // eslint-disable-line no-console // first print our error. if ((error != null) && (error.isProblem === true) && (error.httpCode < 500)) { writeToStderr(error.message); @@ -106,7 +105,7 @@ const auditing = (action, t) => ((typeof t === 'function') return Promise.resolve(result); }) )), - ((error) => console.log('auditing() error', error) || auditLog(action, false, Option.of(error).map(Problem.serializable).orNull()).then( // eslint-disable-line no-console + ((error) => auditLog(action, false, Option.of(error).map(Problem.serializable).orNull()).then( (() => Promise.reject(error)), ((auditError) => { writeToStderr('Failed to audit-log task failure message!'); From 0769356d494f2a39b3f61d6caa989350af29908c Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Thu, 16 Jan 2025 06:32:36 +0000 Subject: [PATCH 021/133] revert knexConfig name change --- lib/util/db.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/util/db.js b/lib/util/db.js index a095fa400..e6afa12ad 100644 --- a/lib/util/db.js +++ b/lib/util/db.js @@ -52,16 +52,16 @@ const knexConnection = (config) => { const problem = validateConfig(config); if (problem != null) throw problem; // We ignore maximumPoolSize when using Knex. - const { maximumPoolSize, ...rest } = config; - if (rest.ssl === true) { + const { maximumPoolSize, ...knexConfig } = config; + if (knexConfig.ssl === true) { // Slonik seems to specify `false` for `rejectUnauthorized` whenever SSL is // specified: // https://github.com/gajus/slonik/issues/159#issuecomment-891089466. We do // the same here so that Knex will connect to the database in the same way // as Slonik. - rest.ssl = { rejectUnauthorized: false }; + knexConfig.ssl = { rejectUnauthorized: false }; } - return rest; + return knexConfig; }; From c95cec673707e17aa887ed39fb538a3150180392 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Sat, 18 Jan 2025 06:40:33 +0000 Subject: [PATCH 022/133] renames to be less knexy --- lib/bin/check-migrations.js | 7 +-- lib/bin/check-open-db-queries.js | 2 +- lib/bin/run-migrations.js | 10 ++-- lib/model/legacy-knex-migrator.js | 38 ++++++++++++++ .../20191231-02-add-schema-storage.js | 2 +- lib/model/{migrate.js => pg-migrator.js} | 49 +++++-------------- test/integration/other/knex-migrations.js | 2 +- test/integration/setup.js | 2 +- 8 files changed, 60 insertions(+), 52 deletions(-) create mode 100644 lib/model/legacy-knex-migrator.js rename lib/model/{migrate.js => pg-migrator.js} (77%) diff --git a/lib/bin/check-migrations.js b/lib/bin/check-migrations.js index 2119c203d..cc83feeca 100644 --- a/lib/bin/check-migrations.js +++ b/lib/bin/check-migrations.js @@ -7,15 +7,16 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex, checkKnexMigrations, checkPostKnexMigrations } = require('../model/migrate'); +const { withKnex, checkMigrations } = require('../model/legacy-knex-migrator'); +const { checkPgMigrations } = require('../model/pg-migrator'); // REVIEW why is check-migrations required in the first place? (async () => { try { const config = require('config').get('default.database'); - await withKnex(config)(checkKnexMigrations); - await checkPostKnexMigrations(config); + await withKnex(config)(checkMigrations); + await checkPgMigrations(config); } catch (err) { console.error('Error:', err.message); process.exit(1); diff --git a/lib/bin/check-open-db-queries.js b/lib/bin/check-open-db-queries.js index 3299f839a..89b952cef 100644 --- a/lib/bin/check-open-db-queries.js +++ b/lib/bin/check-open-db-queries.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex } = require('../model/migrate'); +const { withKnex } = require('../model/legacy-knex-migrator'); (async () => { try { diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index 10e9d3edd..6c0f59232 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -7,18 +7,14 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { // eslint-disable-line object-curly-newline - withKnex, - knexMigrations, - - postKnexMigrations, -} = require('../model/migrate'); // eslint-disable-line object-curly-newline +const { withKnex, knexMigrations } = require('../model/legacy-knex-migrator'); +const { pgMigrations } = require('../model/pg-migrator'); (async () => { try { const config = require('config').get('default.database'); await withKnex(config)(knexMigrations); - await postKnexMigrations(config); + await pgMigrations(config); } catch (err) { console.error(err); process.exit(1); diff --git a/lib/model/legacy-knex-migrator.js b/lib/model/legacy-knex-migrator.js new file mode 100644 index 000000000..c021b0653 --- /dev/null +++ b/lib/model/legacy-knex-migrator.js @@ -0,0 +1,38 @@ +// Copyright 2017 ODK Central Developers +// See the NOTICE file at the top-level directory of this distribution and at +// https://github.com/getodk/central-backend/blob/master/NOTICE. +// This file is part of ODK Central. It is subject to the license terms in +// the LICENSE file found in the top-level directory of this distribution and at +// https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, +// including this file, may be copied, modified, propagated, or distributed +// except according to the terms contained in the LICENSE file. +// +// This is a variety of functions helpful for connecting to and performing +// top-level operations with a database, like migrations. + +const knex = require('knex'); +const { knexConnection } = require('../util/db'); + +// Connects to the postgres database specified in configuration and returns it. +const knexConnect = (config) => knex({ client: 'pg', connection: knexConnection(config) }); + +const legacyPath = `${__dirname}/migrations`; // TODO rename to /migrations/legacy + +// Connects to a database, passes it to a function for operations, then ensures its closure. +const withKnex = (config) => (mutator) => { + const db = knexConnect(config); + return mutator(db).finally(() => db.destroy()); +}; + +// Given a database, initiates migrations on it. +const knexMigrations = (db) => db.migrate.latest({ directory: legacyPath }); + +// Checks for pending migrations and returns an exit code of 1 if any are +// still pending/unapplied (e.g. automatically running migrations just failed). +const checkMigrations = (db) => db.migrate.list({ directory: legacyPath }) + .then((res) => { + if (res[1].length > 0) + process.exitCode = 1; + }); + +module.exports = { checkMigrations, knexConnect, withKnex, knexMigrations }; diff --git a/lib/model/migrations/20191231-02-add-schema-storage.js b/lib/model/migrations/20191231-02-add-schema-storage.js index d71604530..d04bd6049 100644 --- a/lib/model/migrations/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/20191231-02-add-schema-storage.js @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../migrate').knexConnect(config); + const db2 = require('../legacy-knex-migrator').knexConnect(config); return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/lib/model/migrate.js b/lib/model/pg-migrator.js similarity index 77% rename from lib/model/migrate.js rename to lib/model/pg-migrator.js index 33bba706d..eb936b7be 100644 --- a/lib/model/migrate.js +++ b/lib/model/pg-migrator.js @@ -1,4 +1,4 @@ -// Copyright 2017 ODK Central Developers +// Copyright 2025 ODK Central Developers // See the NOTICE file at the top-level directory of this distribution and at // https://github.com/getodk/central-backend/blob/master/NOTICE. // This file is part of ODK Central. It is subject to the license terms in @@ -6,31 +6,13 @@ // https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -// -// This is a variety of functions helpful for connecting to and performing -// top-level operations with a database, like migrations. const { lstatSync, readdirSync } = require('node:fs'); const _ = require('lodash'); // eslint-disable-line import/no-extraneous-dependencies -const knex = require('knex'); const pg = require('pg'); -const { knexConnection } = require('../util/db'); -// Connects to the postgres database specified in configuration and returns it. -const knexConnect = (config) => knex({ client: 'pg', connection: knexConnection(config) }); - -const legacyPath = `${__dirname}/migrations`; // TODO rename to /migrations/legacy -const postKnexPath = `${__dirname}/migrations-post-knex`; // TODO rename to /migrations/current - -// Connects to a database, passes it to a function for operations, then ensures its closure. -const withKnex = (config) => (mutator) => { - const db = knexConnect(config); - return mutator(db).finally(() => db.destroy()); -}; - -// Given a database, initiates migrations on it. -const knexMigrations = (db) => db.migrate.latest({ directory: legacyPath }); +const migrationsDir = `${__dirname}/migrations-post-knex`; // TODO rename to /migrations/current or something const withPg = async (config, fn) => { const log = (...args) => console.log('[withPg]', ...args); // eslint-disable-line no-console @@ -54,11 +36,10 @@ const withPg = async (config, fn) => { } }; -const getPostKnexMigrationsToRun = async client => { - const log = (...args) => console.log('[getPostKnexMigrationsToRun]', ...args); // eslint-disable-line no-console +const getMigrationsToRun = async client => { + const log = (...args) => console.log('[getMigrationsToRun]', ...args); // eslint-disable-line no-console log('ENTRY'); - const migrationsDir = postKnexPath; const allMigrations = readdirSync(migrationsDir) .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) .sort(); @@ -80,8 +61,8 @@ const getPostKnexMigrationsToRun = async client => { return toRun; }; -const postKnexMigrations = async (config) => { - const log = (...args) => console.log('[postKnexMigrations]', ...args); // eslint-disable-line no-console +const pgMigrations = async (config) => { + const log = (...args) => console.log('[pgMigrations]', ...args); // eslint-disable-line no-console log('ENTRY'); // In the main, this migrator is written to behave similarly to knex's: @@ -126,7 +107,7 @@ const postKnexMigrations = async (config) => { await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); log('Lock acquired.'); - const toRun = await getPostKnexMigrationsToRun(client); + const toRun = await getMigrationsToRun(client); if (!toRun.length) { log('No migrations to run - exiting.'); @@ -195,22 +176,14 @@ const postKnexMigrations = async (config) => { // Checks for pending migrations and returns an exit code of 1 if any are // still pending/unapplied (e.g. automatically running migrations just failed). -const checkKnexMigrations = (db) => db.migrate.list({ directory: legacyPath }) - .then((res) => { - if (res[1].length > 0) - process.exitCode = 1; - }); - -// Checks for pending migrations and returns an exit code of 1 if any are -// still pending/unapplied (e.g. automatically running migrations just failed). -const checkPostKnexMigrations = async config => { - const log = (...args) => console.log('[checkPostKnexMigrations]', ...args); // eslint-disable-line no-console +const checkPgMigrations = async config => { + const log = (...args) => console.log('[checkPgMigrations]', ...args); // eslint-disable-line no-console log('ENTRY'); await withPg(config, async client => { - const toRun = await getPostKnexMigrationsToRun(client); + const toRun = await getMigrationsToRun(client); if (toRun.length) process.exitCode = 1; }); }; -module.exports = { checkKnexMigrations, checkPostKnexMigrations, knexConnect, withKnex, withPg, knexMigrations, postKnexMigrations }; +module.exports = { checkPgMigrations, withPg, pgMigrations }; diff --git a/test/integration/other/knex-migrations.js b/test/integration/other/knex-migrations.js index 29b1c5a84..870a58b5b 100644 --- a/test/integration/other/knex-migrations.js +++ b/test/integration/other/knex-migrations.js @@ -6,7 +6,7 @@ const { testContainerFullTrx, testServiceFullTrx } = require('../setup'); const { sql } = require('slonik'); const { createReadStream } = require('fs'); const { Actor, Config } = require(appRoot + '/lib/model/frames'); -const { withKnex } = require(appRoot + '/lib/model/migrate'); +const { withKnex } = require(appRoot + '/lib/model/legacy-knex-migrator'); const { exhaust } = require(appRoot + '/lib/worker/worker'); const testData = require('../../data/xml'); diff --git a/test/integration/setup.js b/test/integration/setup.js index 5db664093..586eccfc8 100644 --- a/test/integration/setup.js +++ b/test/integration/setup.js @@ -12,7 +12,7 @@ const testData = require('../data/xml'); // knex things. const config = require('config'); -const { withPg } = require(appRoot + '/lib/model/migrate'); +const { withPg } = require(appRoot + '/lib/model/pg-migrator'); // slonik connection pool const { slonikPool } = require(appRoot + '/lib/external/slonik'); From 322c5ba4aa848958150b9681d989b72ceeabc3d1 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Sat, 18 Jan 2025 08:13:55 +0000 Subject: [PATCH 023/133] reduce changeset --- lib/bin/check-migrations.js | 7 +++---- lib/bin/check-open-db-queries.js | 2 +- lib/bin/run-migrations.js | 9 ++++----- lib/model/{legacy-knex-migrator.js => migrate.js} | 11 ++++++----- .../migrations/20191231-02-add-schema-storage.js | 2 +- .../other/{knex-migrations.js => migrations.js} | 5 +++-- 6 files changed, 18 insertions(+), 18 deletions(-) rename lib/model/{legacy-knex-migrator.js => migrate.js} (80%) rename test/integration/other/{knex-migrations.js => migrations.js} (99%) diff --git a/lib/bin/check-migrations.js b/lib/bin/check-migrations.js index cc83feeca..19919672a 100644 --- a/lib/bin/check-migrations.js +++ b/lib/bin/check-migrations.js @@ -7,16 +7,15 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex, checkMigrations } = require('../model/legacy-knex-migrator'); +const { withKnex, checkMigrations } = require('../model/migrate'); const { checkPgMigrations } = require('../model/pg-migrator'); // REVIEW why is check-migrations required in the first place? (async () => { try { - const config = require('config').get('default.database'); - await withKnex(config)(checkMigrations); - await checkPgMigrations(config); + await withKnex(require('config').get('default.database'))(checkMigrations); + await checkPgMigrations(require('config').get('default.database')); } catch (err) { console.error('Error:', err.message); process.exit(1); diff --git a/lib/bin/check-open-db-queries.js b/lib/bin/check-open-db-queries.js index 89b952cef..3299f839a 100644 --- a/lib/bin/check-open-db-queries.js +++ b/lib/bin/check-open-db-queries.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex } = require('../model/legacy-knex-migrator'); +const { withKnex } = require('../model/migrate'); (async () => { try { diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index 6c0f59232..09141f4f4 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -7,16 +7,15 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex, knexMigrations } = require('../model/legacy-knex-migrator'); +const { withKnex, migrate } = require('../model/migrate'); const { pgMigrations } = require('../model/pg-migrator'); (async () => { try { - const config = require('config').get('default.database'); - await withKnex(config)(knexMigrations); - await pgMigrations(config); + await withKnex(require('config').get('default.database'))(migrate); + await pgMigrations(require('config').get('default.database')); } catch (err) { - console.error(err); + console.error('Error:', err.message); process.exit(1); } })(); diff --git a/lib/model/legacy-knex-migrator.js b/lib/model/migrate.js similarity index 80% rename from lib/model/legacy-knex-migrator.js rename to lib/model/migrate.js index c021b0653..0e494df8e 100644 --- a/lib/model/legacy-knex-migrator.js +++ b/lib/model/migrate.js @@ -10,14 +10,15 @@ // This is a variety of functions helpful for connecting to and performing // top-level operations with a database, like migrations. +// TODO rename e.g. legacy-knex-migrator +// TODO move migration files to e.g. /migrations/legacy + const knex = require('knex'); const { knexConnection } = require('../util/db'); // Connects to the postgres database specified in configuration and returns it. const knexConnect = (config) => knex({ client: 'pg', connection: knexConnection(config) }); -const legacyPath = `${__dirname}/migrations`; // TODO rename to /migrations/legacy - // Connects to a database, passes it to a function for operations, then ensures its closure. const withKnex = (config) => (mutator) => { const db = knexConnect(config); @@ -25,14 +26,14 @@ const withKnex = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -const knexMigrations = (db) => db.migrate.latest({ directory: legacyPath }); +const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations` }); // Checks for pending migrations and returns an exit code of 1 if any are // still pending/unapplied (e.g. automatically running migrations just failed). -const checkMigrations = (db) => db.migrate.list({ directory: legacyPath }) +const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migrations` }) .then((res) => { if (res[1].length > 0) process.exitCode = 1; }); -module.exports = { checkMigrations, knexConnect, withKnex, knexMigrations }; +module.exports = { checkMigrations, knexConnect, withKnex, migrate }; diff --git a/lib/model/migrations/20191231-02-add-schema-storage.js b/lib/model/migrations/20191231-02-add-schema-storage.js index d04bd6049..d71604530 100644 --- a/lib/model/migrations/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/20191231-02-add-schema-storage.js @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../legacy-knex-migrator').knexConnect(config); + const db2 = require('../migrate').knexConnect(config); return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/test/integration/other/knex-migrations.js b/test/integration/other/migrations.js similarity index 99% rename from test/integration/other/knex-migrations.js rename to test/integration/other/migrations.js index 870a58b5b..1775696f3 100644 --- a/test/integration/other/knex-migrations.js +++ b/test/integration/other/migrations.js @@ -1,3 +1,4 @@ +// TODO rename e.g. legacy-knex-migrations const { readFileSync } = require('fs'); const appRoot = require('app-root-path'); const uuid = require('uuid').v4; @@ -6,7 +7,7 @@ const { testContainerFullTrx, testServiceFullTrx } = require('../setup'); const { sql } = require('slonik'); const { createReadStream } = require('fs'); const { Actor, Config } = require(appRoot + '/lib/model/frames'); -const { withKnex } = require(appRoot + '/lib/model/legacy-knex-migrator'); +const { withKnex } = require(appRoot + '/lib/model/migrate'); const { exhaust } = require(appRoot + '/lib/worker/worker'); const testData = require('../../data/xml'); @@ -59,7 +60,7 @@ testMigration.skip = (filename, tests) => // column to projects and forms, it is not possible to migrate part way // (before the new column) and populate the data when frames expect the // new column to exist. -describe.skip('legacy (knex) database migrations', function() { +describe.skip('database migrations', function() { this.timeout(8000); it('should purge deleted forms via migration', testServiceFullTrx(async (service, container) => { From 6c1a62b18ad21c716c6d6bc9a65670e57dbe871a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Sat, 18 Jan 2025 08:14:52 +0000 Subject: [PATCH 024/133] revert whitespace change --- lib/model/migrate.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/model/migrate.js b/lib/model/migrate.js index 0e494df8e..2d5b04ee6 100644 --- a/lib/model/migrate.js +++ b/lib/model/migrate.js @@ -37,3 +37,4 @@ const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migra }); module.exports = { checkMigrations, knexConnect, withKnex, migrate }; + From a415a70df6c6547720edb025e685616fe486489f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:05:30 +0000 Subject: [PATCH 025/133] import fixes for null content types --- lib/model/query/blobs.js | 2 +- lib/model/query/submission-attachments.js | 6 +++--- lib/model/query/submissions.js | 22 +++++----------------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/lib/model/query/blobs.js b/lib/model/query/blobs.js index 6808cce58..81e476089 100644 --- a/lib/model/query/blobs.js +++ b/lib/model/query/blobs.js @@ -22,7 +22,7 @@ const { construct } = require('../../util/util'); const ensure = (blob) => ({ oneFirst }) => oneFirst(sql` with ensured as (insert into blobs (sha, md5, content, "contentType") values - (${blob.sha}, ${blob.md5}, ${sql.binary(blob.content)}, ${blob.contentType || null}) + (${blob.sha}, ${blob.md5}, ${sql.binary(blob.content)}, ${blob.contentType || sql`DEFAULT`}) on conflict (sha) do update set sha = ${blob.sha} returning id) select id from ensured`); diff --git a/lib/model/query/submission-attachments.js b/lib/model/query/submission-attachments.js index aaf5657fc..8a2901b8f 100644 --- a/lib/model/query/submission-attachments.js +++ b/lib/model/query/submission-attachments.js @@ -107,12 +107,12 @@ const upsert = (def, files) => ({ Blobs, SubmissionAttachments }) => const present = files.filter((file) => lookup.has(file.fieldname)); return Promise.all(present .map((file) => Blobs.ensure(Blob.fromBuffer(file.buffer, file.mimetype)) - .then((blobId) => SubmissionAttachments.attach(def.id, file.fieldname, blobId)))); + .then((blobId) => SubmissionAttachments.attach(def, file.fieldname, blobId)))); }); -const attach = (defId, name, blobId) => ({ run }) => run(sql` +const attach = (def, name, blobId) => ({ run }) => run(sql` update submission_attachments set "blobId"=${blobId} -where "submissionDefId"=${defId} and name=${name}`); +where "submissionDefId"=${def.id} and name=${name}`); // TODO: this is currently audit logged in resource/submissions. probably deal w it here instead. diff --git a/lib/model/query/submissions.js b/lib/model/query/submissions.js index 40d6630af..ef7a07e31 100644 --- a/lib/model/query/submissions.js +++ b/lib/model/query/submissions.js @@ -18,7 +18,6 @@ const { unjoiner, extender, sqlEquals, page, updater, QueryOptions, insertMany, const { blankStringToNull, construct } = require('../../util/util'); const Problem = require('../../util/problem'); const { streamEncBlobs } = require('../../util/blob'); -const Option = require('../../util/option'); //////////////////////////////////////////////////////////////////////////////// @@ -270,8 +269,8 @@ where submissions."instanceId"=${instanceId} and submission_defs.current=true`) .then(map((row) => new Submission(row, { def: new Submission.Def({ id: row.defId }) }))); -const _buildGetCurrentSql = (cols, projectId, xmlFormId, instanceId, draft) => sql` -select ${cols} from submission_defs +const getCurrentDefByIds = (projectId, xmlFormId, instanceId, draft) => ({ maybeOne }) => maybeOne(sql` +select submission_defs.* from submission_defs inner join (select submissions.id, "instanceId" from submissions inner join @@ -281,19 +280,8 @@ inner join where submissions."deletedAt" is null and draft=${draft}) as submissions on submissions.id=submission_defs."submissionId" where submissions."instanceId"=${instanceId} and current=true -limit 1`; - -const getCurrentDefColByIds = (col, projectId, xmlFormId, instanceId, draft) => ({ maybeOneFirst }) => - maybeOneFirst(_buildGetCurrentSql(sql.identifier(['submission_defs', col]), projectId, xmlFormId, instanceId, draft)) - .then(map(Option.of)); - -const getCurrentDefColsByIds = (cols, projectId, xmlFormId, instanceId, draft) => ({ maybeOne }) => - maybeOne(_buildGetCurrentSql(sql.join(cols.map(col => sql.identifier(['submission_defs', col])), sql`,`), projectId, xmlFormId, instanceId, draft)) - .then(map(Option.of)); - -const getCurrentDefByIds = (projectId, xmlFormId, instanceId, draft) => ({ maybeOne }) => - maybeOne(_buildGetCurrentSql(sql`submission_defs.*`, projectId, xmlFormId, instanceId, draft)) - .then(map(construct(Submission.Def))); +limit 1`) + .then(map(construct(Submission.Def))); const getDefById = (submissionDefId) => ({ maybeOne }) => maybeOne(sql` select submission_defs.* from submission_defs @@ -492,7 +480,7 @@ module.exports = { setSelectMultipleValues, getSelectMultipleValuesForExport, getByIdsWithDef, getSubAndDefById, getByIds, getAllForFormByIds, getById, countByFormId, verifyVersion, - getDefById, getCurrentDefByIds, getCurrentDefColByIds, getCurrentDefColsByIds, getAnyDefByFormAndInstanceId, getDefsByFormAndLogicalId, getDefBySubmissionAndInstanceId, getRootForInstanceId, + getDefById, getCurrentDefByIds, getAnyDefByFormAndInstanceId, getDefsByFormAndLogicalId, getDefBySubmissionAndInstanceId, getRootForInstanceId, getDeleted, streamForExport, getForExport }; From 5d6218bbcad659aa6700709ee4b6d0f3423d67de Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:06:21 +0000 Subject: [PATCH 026/133] import query changes --- lib/model/query/submission-attachments.js | 6 +++--- lib/model/query/submissions.js | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/model/query/submission-attachments.js b/lib/model/query/submission-attachments.js index 8a2901b8f..aaf5657fc 100644 --- a/lib/model/query/submission-attachments.js +++ b/lib/model/query/submission-attachments.js @@ -107,12 +107,12 @@ const upsert = (def, files) => ({ Blobs, SubmissionAttachments }) => const present = files.filter((file) => lookup.has(file.fieldname)); return Promise.all(present .map((file) => Blobs.ensure(Blob.fromBuffer(file.buffer, file.mimetype)) - .then((blobId) => SubmissionAttachments.attach(def, file.fieldname, blobId)))); + .then((blobId) => SubmissionAttachments.attach(def.id, file.fieldname, blobId)))); }); -const attach = (def, name, blobId) => ({ run }) => run(sql` +const attach = (defId, name, blobId) => ({ run }) => run(sql` update submission_attachments set "blobId"=${blobId} -where "submissionDefId"=${def.id} and name=${name}`); +where "submissionDefId"=${defId} and name=${name}`); // TODO: this is currently audit logged in resource/submissions. probably deal w it here instead. diff --git a/lib/model/query/submissions.js b/lib/model/query/submissions.js index ef7a07e31..40d6630af 100644 --- a/lib/model/query/submissions.js +++ b/lib/model/query/submissions.js @@ -18,6 +18,7 @@ const { unjoiner, extender, sqlEquals, page, updater, QueryOptions, insertMany, const { blankStringToNull, construct } = require('../../util/util'); const Problem = require('../../util/problem'); const { streamEncBlobs } = require('../../util/blob'); +const Option = require('../../util/option'); //////////////////////////////////////////////////////////////////////////////// @@ -269,8 +270,8 @@ where submissions."instanceId"=${instanceId} and submission_defs.current=true`) .then(map((row) => new Submission(row, { def: new Submission.Def({ id: row.defId }) }))); -const getCurrentDefByIds = (projectId, xmlFormId, instanceId, draft) => ({ maybeOne }) => maybeOne(sql` -select submission_defs.* from submission_defs +const _buildGetCurrentSql = (cols, projectId, xmlFormId, instanceId, draft) => sql` +select ${cols} from submission_defs inner join (select submissions.id, "instanceId" from submissions inner join @@ -280,8 +281,19 @@ inner join where submissions."deletedAt" is null and draft=${draft}) as submissions on submissions.id=submission_defs."submissionId" where submissions."instanceId"=${instanceId} and current=true -limit 1`) - .then(map(construct(Submission.Def))); +limit 1`; + +const getCurrentDefColByIds = (col, projectId, xmlFormId, instanceId, draft) => ({ maybeOneFirst }) => + maybeOneFirst(_buildGetCurrentSql(sql.identifier(['submission_defs', col]), projectId, xmlFormId, instanceId, draft)) + .then(map(Option.of)); + +const getCurrentDefColsByIds = (cols, projectId, xmlFormId, instanceId, draft) => ({ maybeOne }) => + maybeOne(_buildGetCurrentSql(sql.join(cols.map(col => sql.identifier(['submission_defs', col])), sql`,`), projectId, xmlFormId, instanceId, draft)) + .then(map(Option.of)); + +const getCurrentDefByIds = (projectId, xmlFormId, instanceId, draft) => ({ maybeOne }) => + maybeOne(_buildGetCurrentSql(sql`submission_defs.*`, projectId, xmlFormId, instanceId, draft)) + .then(map(construct(Submission.Def))); const getDefById = (submissionDefId) => ({ maybeOne }) => maybeOne(sql` select submission_defs.* from submission_defs @@ -480,7 +492,7 @@ module.exports = { setSelectMultipleValues, getSelectMultipleValuesForExport, getByIdsWithDef, getSubAndDefById, getByIds, getAllForFormByIds, getById, countByFormId, verifyVersion, - getDefById, getCurrentDefByIds, getAnyDefByFormAndInstanceId, getDefsByFormAndLogicalId, getDefBySubmissionAndInstanceId, getRootForInstanceId, + getDefById, getCurrentDefByIds, getCurrentDefColByIds, getCurrentDefColsByIds, getAnyDefByFormAndInstanceId, getDefsByFormAndLogicalId, getDefBySubmissionAndInstanceId, getRootForInstanceId, getDeleted, streamForExport, getForExport }; From fafc6fb8af27229d220f49ddd841080d9a1fb023 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:06:54 +0000 Subject: [PATCH 027/133] e2e test fix? --- test/e2e/s3/test.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/e2e/s3/test.js b/test/e2e/s3/test.js index b94c2e75c..c599a44bb 100644 --- a/test/e2e/s3/test.js +++ b/test/e2e/s3/test.js @@ -379,9 +379,7 @@ describe('s3 support', () => { const filepath = `${attDir}/${name}`; - // "null" is a questionable content-type, but matches current central behaviour - // See: https://github.com/getodk/central-backend/pull/1352 - const expectedContentType = mimetypeFor(name) ?? 'null'; + const expectedContentType = mimetypeFor(name) ?? 'application/octet-stream'; const actualContentType = res.headers.get('content-type'); should.equal(actualContentType, expectedContentType); From 8c6cf2910ab79be8339d4a7a9fd4208b1dc186c0 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:07:58 +0000 Subject: [PATCH 028/133] import test changes --- test/integration/api/submissions.js | 18 ++++++++---------- test/integration/task/s3.js | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/test/integration/api/submissions.js b/test/integration/api/submissions.js index 6a9580c0b..0c21d0076 100644 --- a/test/integration/api/submissions.js +++ b/test/integration/api/submissions.js @@ -4377,8 +4377,7 @@ one,h,/data/h,2000-01-01T00:06,2000-01-01T00:07,-5,-6,,ee,ff body.toString().should.equal('testvideo'); }))))))); - // Ref https://github.com/getodk/central-backend/issues/1351 - it('should attach a given file with empty Content-Type', testService((service) => + it('should attach a given file with empty Content-Type and serve it with default mime type', testService((service) => service.login('alice', (asAlice) => asAlice.post('/v1/projects/1/forms?publish=true') .set('Content-Type', 'application/xml') @@ -4394,13 +4393,12 @@ one,h,/data/h,2000-01-01T00:06,2000-01-01T00:07,-5,-6,,ee,ff .expect(200) .then(() => asAlice.get('/v1/projects/1/forms/binaryType/submissions/both/attachments/my_file1.mp4') .expect(200) - .then(({ headers, text }) => { - headers['content-type'].should.equal('null'); - text.toString().should.equal('testvideo'); // use 'text' instead of 'body' to avoid supertest response parsing + .then(({ headers, body }) => { + headers['content-type'].should.equal('application/octet-stream'); + body.toString().should.equal('testvideo'); }))))))); - // Ref https://github.com/getodk/central-backend/issues/1351 - it('should attach a given file with missing Content-Type', testService((service) => + it('should attach a given file with missing Content-Type and serve it with default mime type', testService((service) => service.login('alice', (asAlice) => asAlice.post('/v1/projects/1/forms?publish=true') .set('Content-Type', 'application/xml') @@ -4416,9 +4414,9 @@ one,h,/data/h,2000-01-01T00:06,2000-01-01T00:07,-5,-6,,ee,ff .expect(200) .then(() => asAlice.get('/v1/projects/1/forms/binaryType/submissions/both/attachments/my_file1.mp4') .expect(200) - .then(({ headers, text }) => { - headers['content-type'].should.equal('null'); - text.toString().should.equal('testvideo'); // use 'text' instead of 'body' to avoid supertest response parsing + .then(({ headers, body }) => { + headers['content-type'].should.equal('application/octet-stream'); + body.toString().should.equal('testvideo'); }))))))); it('should log an audit entry about initial attachment', testService((service, { Audits, Forms, Submissions, SubmissionAttachments }) => diff --git a/test/integration/task/s3.js b/test/integration/task/s3.js index 0c3b07285..f9d58d874 100644 --- a/test/integration/task/s3.js +++ b/test/integration/task/s3.js @@ -11,7 +11,7 @@ const aBlobExistsWith = async (container, { status }) => { const blob = await Blob.fromBuffer(crypto.randomBytes(100)); await container.run(sql` INSERT INTO BLOBS (sha, md5, content, "contentType", s3_status) - VALUES (${blob.sha}, ${blob.md5}, ${sql.binary(blob.content)}, ${blob.contentType || null}, ${status}) + VALUES (${blob.sha}, ${blob.md5}, ${sql.binary(blob.content)}, ${blob.contentType || sql`DEFAULT`}, ${status}) `); }; From b264a83b37e302fff1fa63de4e011030154ed031 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:12:19 +0000 Subject: [PATCH 029/133] ci/db-migrations: add new path --- .github/workflows/db-migrations.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/db-migrations.yml b/.github/workflows/db-migrations.yml index 8b6594c9c..4a33bf04a 100644 --- a/.github/workflows/db-migrations.yml +++ b/.github/workflows/db-migrations.yml @@ -6,6 +6,7 @@ on: - .github/workflows/db-migrations.yml - lib/bin/create-docker-databases.js - lib/model/migrations/** + - lib/model/migrations-post-knex/** - test/db-migrations/** - package.json - package-lock.json @@ -15,6 +16,7 @@ on: - .github/workflows/db-migrations.yml - lib/bin/create-docker-databases.js - lib/model/migrations/** + - lib/model/migrations-post-knex/** - test/db-migrations/** - package.json - package-lock.json From 9a1db566367abb07e8b349a4b08ce37db0ec7df2 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:28:37 +0000 Subject: [PATCH 030/133] Make migration tests pass? --- .../20241008-01-add-user_preferences.spec.js | 4 +- ...isable-nullable-blob-content-types.spec.js | 4 +- test/db-migrations/migrator.js | 147 +++++++++--------- test/db-migrations/utils.js | 50 ++++-- 4 files changed, 122 insertions(+), 83 deletions(-) diff --git a/test/db-migrations/20241008-01-add-user_preferences.spec.js b/test/db-migrations/20241008-01-add-user_preferences.spec.js index 8a89e1eea..74a70dd20 100644 --- a/test/db-migrations/20241008-01-add-user_preferences.spec.js +++ b/test/db-migrations/20241008-01-add-user_preferences.spec.js @@ -2,10 +2,10 @@ const { // eslint-disable-line object-curly-newline assertIndexExists, assertTableDoesNotExist, assertTableSchema, - describeMigration, + describeLegacyMigration, } = require('./utils'); // eslint-disable-line object-curly-newline -describeMigration('20241008-01-add-user_preferences', ({ runMigrationBeingTested }) => { +describeLegacyMigration('20241008-01-add-user_preferences', ({ runMigrationBeingTested }) => { before(async () => { await assertTableDoesNotExist('user_site_preferences'); await assertTableDoesNotExist('user_project_preferences'); diff --git a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js index e3fb41c03..c8b307e56 100644 --- a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js +++ b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js @@ -3,11 +3,11 @@ const { hash, randomBytes } = require('node:crypto'); const { // eslint-disable-line object-curly-newline assertTableContents, - describeMigration, + describeNewMigration, rowsExistFor, } = require('./utils'); // eslint-disable-line object-curly-newline -describeMigration('20250113-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { +describeNewMigration('20250113-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { const aBlobWith = props => { const randomContent = randomBytes(100); const md5 = hash('md5', randomContent); // eslint-disable-line no-multi-spaces diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 739b8d971..73353679b 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -15,94 +15,101 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); -const migrationsDir = './lib/model/migrations'; -const holdingPen = './test/db-migrations/.holding-pen'; +const legacy = createMigrator('./lib/model/migrations', './test/db-migrations/.holding-pen/legacy'); +const postKnex = createMigrator('./lib/model/migrations-post-knex', './test/db-migrations/.holding-pen/post-knex', legacy); -fs.mkdirSync(holdingPen, { recursive: true }); +module.exports = { legacy, postKnex }; -restoreMigrations(); // eslint-disable-line no-use-before-define -const allMigrations = loadMigrationsList(); // eslint-disable-line no-use-before-define -moveMigrationsToHoldingPen(); // eslint-disable-line no-use-before-define +function createMigrator(migrationsDir, holdingPen, previousMigrator) { + fs.mkdirSync(holdingPen, { recursive: true }); -let lastRunIdx = -1; + restoreMigrations(); // eslint-disable-line no-use-before-define + const allMigrations = loadMigrationsList(); // eslint-disable-line no-use-before-define + moveMigrationsToHoldingPen(); // eslint-disable-line no-use-before-define -function runBefore(migrationName) { - const idx = getIndex(migrationName); // eslint-disable-line no-use-before-define - if (idx === 0) return; + let lastRunIdx = -1; - const previousMigration = allMigrations[idx - 1]; + return { + exists, + hasRun, + runBefore, + runIncluding, + restoreMigrations, + }; - return runIncluding(previousMigration); // eslint-disable-line no-use-before-define -} + function runBefore(migrationName) { + const idx = getIndex(migrationName); // eslint-disable-line no-use-before-define + if (idx === 0) return; -function runIncluding(lastMigrationToRun) { - const finalIdx = getIndex(lastMigrationToRun); // eslint-disable-line no-use-before-define + const previousMigration = allMigrations[idx - 1]; - for (let restoreIdx=lastRunIdx+1; restoreIdx<=finalIdx; ++restoreIdx) { // eslint-disable-line no-plusplus - const f = allMigrations[restoreIdx] + '.js'; - fs.renameSync(`${holdingPen}/${f}`, `${migrationsDir}/${f}`); + return runIncluding(previousMigration); // eslint-disable-line no-use-before-define } - log('Running migrations until:', lastMigrationToRun, '...'); - const res = execSync(`node ./lib/bin/run-migrations.js`, { encoding: 'utf8' }); + function runIncluding(lastMigrationToRun) { + if(previousMigrator) previousMigrator.restoreMigrations(); - lastRunIdx = finalIdx; + const finalIdx = getIndex(lastMigrationToRun); // eslint-disable-line no-use-before-define - log(`Ran migrations up-to-and-including ${lastMigrationToRun}:\n`, res); -} + for (let restoreIdx=lastRunIdx+1; restoreIdx<=finalIdx; ++restoreIdx) { // eslint-disable-line no-plusplus + const f = allMigrations[restoreIdx] + '.js'; + fs.renameSync(`${holdingPen}/${f}`, `${migrationsDir}/${f}`); + } -function getIndex(migrationName) { - const idx = allMigrations.indexOf(migrationName); - log('getIndex()', migrationName, 'found at', idx); - if (idx === -1) throw new Error(`Unknown migration: ${migrationName}`); - return idx; -} + log('Running migrations until:', lastMigrationToRun, '...'); + const res = execSync(`node ./lib/bin/run-migrations.js`, { encoding: 'utf8' }); -function restoreMigrations() { - moveAll(holdingPen, migrationsDir); // eslint-disable-line no-use-before-define -} + lastRunIdx = finalIdx; -function moveMigrationsToHoldingPen() { - moveAll(migrationsDir, holdingPen); // eslint-disable-line no-use-before-define -} + log(`Ran migrations up-to-and-including ${lastMigrationToRun}:\n`, res); + } -function moveAll(src, tgt) { - fs.readdirSync(src) - .forEach(f => fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); -} + function getIndex(migrationName) { + const idx = allMigrations.indexOf(migrationName); + log('getIndex()', migrationName, 'found at', idx); + if (idx === -1) throw new Error(`Unknown migration: ${migrationName}`); + return idx; + } -function loadMigrationsList() { - const migrations = fs.readdirSync(migrationsDir) - .filter(f => f.endsWith('.js')) - .map(f => f.replace(/\.js$/, '')) - .sort(); // TODO check that this is how knex sorts migration files - log(); - log('All migrations:'); - log(); - migrations.forEach(m => log('*', m)); - log(); - log('Total:', migrations.length); - log(); - return migrations; -} + function restoreMigrations() { + moveAll(holdingPen, migrationsDir); // eslint-disable-line no-use-before-define + } -function exists(migrationName) { - try { - getIndex(migrationName); - return true; - } catch (err) { - return false; + function moveMigrationsToHoldingPen() { + moveAll(migrationsDir, holdingPen); // eslint-disable-line no-use-before-define } -} -function hasRun(migrationName) { - return lastRunIdx >= getIndex(migrationName); -} + function moveAll(src, tgt) { + fs.readdirSync(src) + .forEach(f => fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); + } + + function loadMigrationsList() { + const migrations = fs.readdirSync(migrationsDir) + .filter(f => f.endsWith('.js')) + .map(f => f.replace(/\.js$/, '')) + .sort(); // TODO check that this is how knex sorts migration files + log(); + log('All migrations:'); + log(); + migrations.forEach(m => log('*', m)); + log(); + log('Total:', migrations.length); + log(); + return migrations; + } -module.exports = { - exists, - hasRun, - runBefore, - runIncluding, - restoreMigrations, -}; + function exists(migrationName) { + console.log('migrator.exists()', migrationName, { allMigrations }); + try { + getIndex(migrationName); + return true; + } catch (err) { + return false; + } + } + + function hasRun(migrationName) { + return lastRunIdx >= getIndex(migrationName); + } +} diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index ad382e9fd..8f799ac52 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -2,13 +2,13 @@ const assert = require('node:assert/strict'); const _ = require('lodash'); const migrator = require('./migrator'); -function _describeMigration(describeFn, migrationName, fn) { +function _describeLegacyMigration(describeFn, migrationName, fn) { assert.strictEqual(arguments.length, 3, 'Incorrect argument count.'); assert.strictEqual(typeof describeFn, 'function'); - assert.ok(migrator.exists(migrationName), `Migration '${migrationName}' does not exist.`); - assert.ok(!migrator.hasRun(migrationName), `Migration '${migrationName}' has already been run.`); + assert.ok(migrator.legacy.exists(migrationName), `Migration '${migrationName}' does not exist.`); + assert.ok(!migrator.legacy.hasRun(migrationName), `Migration '${migrationName}' has already been run.`); assert.strictEqual(typeof fn, 'function'); assert.strictEqual(fn.length, 1); @@ -18,20 +18,51 @@ function _describeMigration(describeFn, migrationName, fn) { return () => { if (alreadyRun) throw new Error('Migration has already run! Check your test structure.'); alreadyRun = true; - migrator.runIncluding(migrationName); + migrator.legacy.runIncluding(migrationName); }; })(); return describeFn(`database migration: ${migrationName}`, () => { before(() => { - migrator.runBefore(migrationName); + migrator.legacy.runBefore(migrationName); }); return fn({ runMigrationBeingTested }); }); } -function describeMigration(...args) { return _describeMigration(describe, ...args); } -describeMigration.only = (...args) => _describeMigration(describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces -describeMigration.skip = (...args) => _describeMigration(describe.skip, ...args); // eslint-disable-line no-multi-spaces +function describeLegacyMigration(...args) { return _describeLegacyMigration(describe, ...args); } +describeLegacyMigration.only = (...args) => _describeLegacyMigration(describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces +describeLegacyMigration.skip = (...args) => _describeLegacyMigration(describe.skip, ...args); // eslint-disable-line no-multi-spaces + +function _describeNewMigration(describeFn, migrationName, fn) { + assert.strictEqual(arguments.length, 3, 'Incorrect argument count.'); + + assert.strictEqual(typeof describeFn, 'function'); + + assert.ok(migrator.postKnex.exists(migrationName), `Migration '${migrationName}' does not exist.`); + assert.ok(!migrator.postKnex.hasRun(migrationName), `Migration '${migrationName}' has already been run.`); + + assert.strictEqual(typeof fn, 'function'); + assert.strictEqual(fn.length, 1); + + const runMigrationBeingTested = (() => { + let alreadyRun; + return () => { + if (alreadyRun) throw new Error('Migration has already run! Check your test structure.'); + alreadyRun = true; + migrator.postKnex.runIncluding(migrationName); + }; + })(); + + return describeFn(`database migration: ${migrationName}`, () => { + before(() => { + migrator.postKnex.runBefore(migrationName); + }); + return fn({ runMigrationBeingTested }); + }); +} +function describeNewMigration(...args) { return _describeNewMigration(describe, ...args); } +describeNewMigration.only = (...args) => _describeNewMigration(describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces +describeNewMigration.skip = (...args) => _describeNewMigration(describe.skip, ...args); // eslint-disable-line no-multi-spaces async function assertIndexExists(tableName, expected) { if (arguments.length !== 2) throw new Error('Incorrect arg count.'); @@ -180,7 +211,8 @@ module.exports = { assertTableDoesNotExist, assertTableSchema, - describeMigration, + describeLegacyMigration, + describeNewMigration, // TODO rename to simply describeMigration rowsExistFor, }; From 9987704bd54728fa00028a49c506c5024a562133 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:29:27 +0000 Subject: [PATCH 031/133] only move js? --- test/db-migrations/migrator.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 73353679b..346db9fe4 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -81,6 +81,7 @@ function createMigrator(migrationsDir, holdingPen, previousMigrator) { function moveAll(src, tgt) { fs.readdirSync(src) + .filter(f => f.endsWith('.js')) .forEach(f => fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); } From f20dad47c1f4704257a8af13f86c0d8c01b3fc5a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:32:01 +0000 Subject: [PATCH 032/133] lint --- test/db-migrations/migrator.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 346db9fe4..bc4ee14c0 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -15,8 +15,8 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); -const legacy = createMigrator('./lib/model/migrations', './test/db-migrations/.holding-pen/legacy'); -const postKnex = createMigrator('./lib/model/migrations-post-knex', './test/db-migrations/.holding-pen/post-knex', legacy); +const legacy = createMigrator('./lib/model/migrations', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces +const postKnex = createMigrator('./lib/model/migrations-post-knex', './test/db-migrations/.holding-pen/post-knex', legacy); // eslint-disable-line no-use-before-define module.exports = { legacy, postKnex }; @@ -30,11 +30,11 @@ function createMigrator(migrationsDir, holdingPen, previousMigrator) { let lastRunIdx = -1; return { - exists, - hasRun, - runBefore, - runIncluding, - restoreMigrations, + exists, // eslint-disable-line no-use-before-define, no-multi-spaces + hasRun, // eslint-disable-line no-use-before-define, no-multi-spaces + runBefore, // eslint-disable-line no-use-before-define, no-multi-spaces + runIncluding, // eslint-disable-line no-use-before-define, no-multi-spaces + restoreMigrations, // eslint-disable-line no-use-before-define }; function runBefore(migrationName) { @@ -47,7 +47,7 @@ function createMigrator(migrationsDir, holdingPen, previousMigrator) { } function runIncluding(lastMigrationToRun) { - if(previousMigrator) previousMigrator.restoreMigrations(); + if (previousMigrator) previousMigrator.restoreMigrations(); const finalIdx = getIndex(lastMigrationToRun); // eslint-disable-line no-use-before-define @@ -101,7 +101,6 @@ function createMigrator(migrationsDir, holdingPen, previousMigrator) { } function exists(migrationName) { - console.log('migrator.exists()', migrationName, { allMigrations }); try { getIndex(migrationName); return true; From 8aa22863fcb6a445666f68cd8da11611dfa2eb1f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:43:46 +0000 Subject: [PATCH 033/133] wip --- test/db-migrations/utils.js | 48 +++++++++---------------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index 8f799ac52..dd54ba1d2 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -2,13 +2,13 @@ const assert = require('node:assert/strict'); const _ = require('lodash'); const migrator = require('./migrator'); -function _describeLegacyMigration(describeFn, migrationName, fn) { +function _describeMigration(migrator, describeFn, migrationName, fn) { // eslint-disable-line no-shadow assert.strictEqual(arguments.length, 3, 'Incorrect argument count.'); assert.strictEqual(typeof describeFn, 'function'); - assert.ok(migrator.legacy.exists(migrationName), `Migration '${migrationName}' does not exist.`); - assert.ok(!migrator.legacy.hasRun(migrationName), `Migration '${migrationName}' has already been run.`); + assert.ok(migrator.exists(migrationName), `Migration '${migrationName}' does not exist.`); + assert.ok(!migrator.hasRun(migrationName), `Migration '${migrationName}' has already been run.`); assert.strictEqual(typeof fn, 'function'); assert.strictEqual(fn.length, 1); @@ -18,51 +18,25 @@ function _describeLegacyMigration(describeFn, migrationName, fn) { return () => { if (alreadyRun) throw new Error('Migration has already run! Check your test structure.'); alreadyRun = true; - migrator.legacy.runIncluding(migrationName); + migrator.runIncluding(migrationName); }; })(); return describeFn(`database migration: ${migrationName}`, () => { before(() => { - migrator.legacy.runBefore(migrationName); + migrator.runBefore(migrationName); }); return fn({ runMigrationBeingTested }); }); } -function describeLegacyMigration(...args) { return _describeLegacyMigration(describe, ...args); } -describeLegacyMigration.only = (...args) => _describeLegacyMigration(describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces -describeLegacyMigration.skip = (...args) => _describeLegacyMigration(describe.skip, ...args); // eslint-disable-line no-multi-spaces -function _describeNewMigration(describeFn, migrationName, fn) { - assert.strictEqual(arguments.length, 3, 'Incorrect argument count.'); - - assert.strictEqual(typeof describeFn, 'function'); +function describeLegacyMigration(...args) { return _describeMigration(migrator.legacy, describe, ...args); } // eslint-disable-line no-multi-spaces +describeLegacyMigration.only = (...args) => _describeMigration(migrator.legacy, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces +describeLegacyMigration.skip = (...args) => _describeMigration(migrator.legacy, describe.skip, ...args); // eslint-disable-line no-multi-spaces - assert.ok(migrator.postKnex.exists(migrationName), `Migration '${migrationName}' does not exist.`); - assert.ok(!migrator.postKnex.hasRun(migrationName), `Migration '${migrationName}' has already been run.`); - - assert.strictEqual(typeof fn, 'function'); - assert.strictEqual(fn.length, 1); - - const runMigrationBeingTested = (() => { - let alreadyRun; - return () => { - if (alreadyRun) throw new Error('Migration has already run! Check your test structure.'); - alreadyRun = true; - migrator.postKnex.runIncluding(migrationName); - }; - })(); - - return describeFn(`database migration: ${migrationName}`, () => { - before(() => { - migrator.postKnex.runBefore(migrationName); - }); - return fn({ runMigrationBeingTested }); - }); -} -function describeNewMigration(...args) { return _describeNewMigration(describe, ...args); } -describeNewMigration.only = (...args) => _describeNewMigration(describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces -describeNewMigration.skip = (...args) => _describeNewMigration(describe.skip, ...args); // eslint-disable-line no-multi-spaces +function describeNewMigration(...args) { return _describeMigration(migrator.postKnex, describe, ...args); } // eslint-disable-line no-multi-spaces +describeNewMigration.only = (...args) => _describeMigration(migrator.postKnex, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces +describeNewMigration.skip = (...args) => _describeMigration(migrator.postKnex, describe.skip, ...args); // eslint-disable-line no-multi-spaces async function assertIndexExists(tableName, expected) { if (arguments.length !== 2) throw new Error('Incorrect arg count.'); From 62f043df4693fab5c8b5761f65946600083ea8a1 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:45:44 +0000 Subject: [PATCH 034/133] add migrator name --- test/db-migrations/migrator.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index bc4ee14c0..16527f9e5 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -15,12 +15,12 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); -const legacy = createMigrator('./lib/model/migrations', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces -const postKnex = createMigrator('./lib/model/migrations-post-knex', './test/db-migrations/.holding-pen/post-knex', legacy); // eslint-disable-line no-use-before-define +const legacy = createMigrator('Legacy', './lib/model/migrations', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces +const postKnex = createMigrator('Post-knex', './lib/model/migrations-post-knex', './test/db-migrations/.holding-pen/post-knex', legacy); // eslint-disable-line no-use-before-define module.exports = { legacy, postKnex }; -function createMigrator(migrationsDir, holdingPen, previousMigrator) { +function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { fs.mkdirSync(holdingPen, { recursive: true }); restoreMigrations(); // eslint-disable-line no-use-before-define @@ -91,7 +91,7 @@ function createMigrator(migrationsDir, holdingPen, previousMigrator) { .map(f => f.replace(/\.js$/, '')) .sort(); // TODO check that this is how knex sorts migration files log(); - log('All migrations:'); + log(`${name} migrations:`); log(); migrations.forEach(m => log('*', m)); log(); From ec35f7c2d3857cfa173b90151abd05cc79943585 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 21 Jan 2025 14:46:26 +0000 Subject: [PATCH 035/133] correct arg count --- test/db-migrations/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index dd54ba1d2..841f3f9fc 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -3,7 +3,7 @@ const _ = require('lodash'); const migrator = require('./migrator'); function _describeMigration(migrator, describeFn, migrationName, fn) { // eslint-disable-line no-shadow - assert.strictEqual(arguments.length, 3, 'Incorrect argument count.'); + assert.strictEqual(arguments.length, 4, 'Incorrect argument count.'); assert.strictEqual(typeof describeFn, 'function'); From 08f235c029067fd02049263cacef91f45d1ccd2b Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 05:53:23 +0000 Subject: [PATCH 036/133] add check --- .../20250113-01-disable-nullable-blob-content-types.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js index 922102f38..b96715448 100644 --- a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js +++ b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js @@ -22,6 +22,8 @@ describeNewMigration('20250113-01-disable-nullable-blob-content-types', ({ runMi before(async () => { await rowsExistFor('blobs', blob1, blob2); + await assertTableContents('blobs', blob1, blob2); // TODO should fail if old migration still exists + await runMigrationBeingTested(); }); From 3f8aa1277f265e0b9a00fa63061d9d30e3338c8b Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 05:55:15 +0000 Subject: [PATCH 037/133] rename new migration --- ...es.js => 20250204-01-disable-nullable-blob-content-types.js} | 0 ... => 20250204-01-disable-nullable-blob-content-types.spec.js} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/model/migrations-post-knex/{20250113-01-disable-nullable-blob-content-types.js => 20250204-01-disable-nullable-blob-content-types.js} (100%) rename test/db-migrations/{20250113-01-disable-nullable-blob-content-types.spec.js => 20250204-01-disable-nullable-blob-content-types.spec.js} (96%) diff --git a/lib/model/migrations-post-knex/20250113-01-disable-nullable-blob-content-types.js b/lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js similarity index 100% rename from lib/model/migrations-post-knex/20250113-01-disable-nullable-blob-content-types.js rename to lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js diff --git a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js similarity index 96% rename from test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js rename to test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js index b96715448..9b33aba49 100644 --- a/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js +++ b/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js @@ -7,7 +7,7 @@ const { // eslint-disable-line object-curly-newline rowsExistFor, } = require('./utils'); // eslint-disable-line object-curly-newline -describeNewMigration('20250113-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { +describeNewMigration('20250204-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { const aBlobWith = props => { const randomContent = randomBytes(100); const md5 = hash('md5', randomContent); // eslint-disable-line no-multi-spaces From 26fe2ea0a691f9cb37050f1ad0c5d5c515c1ef79 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:06:57 +0000 Subject: [PATCH 038/133] Fix test migrator --- test/db-migrations/migrator.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 16527f9e5..c8dd510f0 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -39,23 +39,25 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { function runBefore(migrationName) { const idx = getIndex(migrationName); // eslint-disable-line no-use-before-define - if (idx === 0) return; - - const previousMigration = allMigrations[idx - 1]; - - return runIncluding(previousMigration); // eslint-disable-line no-use-before-define + runUntilIndex(idx - 1); } function runIncluding(lastMigrationToRun) { - if (previousMigrator) previousMigrator.restoreMigrations(); - - const finalIdx = getIndex(lastMigrationToRun); // eslint-disable-line no-use-before-define + runUntilIndex(getIndex(lastMigrationToRun)); // eslint-disable-line no-use-before-define + } + function runUntilIndex(finalIdx) { for (let restoreIdx=lastRunIdx+1; restoreIdx<=finalIdx; ++restoreIdx) { // eslint-disable-line no-plusplus const f = allMigrations[restoreIdx] + '.js'; fs.renameSync(`${holdingPen}/${f}`, `${migrationsDir}/${f}`); } + if (previousMigrator) { + log('Restoring migrations for previousMigrator...'); + previousMigrator.restoreMigrations(); + } + + const lastMigrationToRun = allMigrations[finalIdx]; log('Running migrations until:', lastMigrationToRun, '...'); const res = execSync(`node ./lib/bin/run-migrations.js`, { encoding: 'utf8' }); From 2d015c81dace45870661cc9213bf91325e952c7b Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:10:16 +0000 Subject: [PATCH 039/133] update --- .../20250204-01-disable-nullable-blob-content-types.spec.js | 3 +-- test/db-migrations/migrator.js | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js index 9b33aba49..9ab3b8357 100644 --- a/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js +++ b/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js @@ -21,8 +21,7 @@ describeNewMigration('20250204-01-disable-nullable-blob-content-types', ({ runMi before(async () => { await rowsExistFor('blobs', blob1, blob2); - - await assertTableContents('blobs', blob1, blob2); // TODO should fail if old migration still exists + await assertTableContents('blobs', blob1, blob2); // should fail if old migration still exists await runMigrationBeingTested(); }); diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index c8dd510f0..4594cdd4c 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -74,6 +74,7 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { } function restoreMigrations() { + log('restoring migrations from ', holdingPen, 'to', migrationsDir, '...'); moveAll(holdingPen, migrationsDir); // eslint-disable-line no-use-before-define } @@ -84,7 +85,7 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { function moveAll(src, tgt) { fs.readdirSync(src) .filter(f => f.endsWith('.js')) - .forEach(f => fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); + .forEach(f => log(`Moving ${f} from ${src} to ${tgt}...`) || fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); } function loadMigrationsList() { From b21b48669c3038ae5934f17bac0ff0292f207e6e Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:11:15 +0000 Subject: [PATCH 040/133] remove logging --- test/db-migrations/migrator.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 4594cdd4c..613f5a6e9 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -52,10 +52,7 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { fs.renameSync(`${holdingPen}/${f}`, `${migrationsDir}/${f}`); } - if (previousMigrator) { - log('Restoring migrations for previousMigrator...'); - previousMigrator.restoreMigrations(); - } + if (previousMigrator) previousMigrator.restoreMigrations(); const lastMigrationToRun = allMigrations[finalIdx]; log('Running migrations until:', lastMigrationToRun, '...'); @@ -74,7 +71,6 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { } function restoreMigrations() { - log('restoring migrations from ', holdingPen, 'to', migrationsDir, '...'); moveAll(holdingPen, migrationsDir); // eslint-disable-line no-use-before-define } @@ -85,7 +81,7 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { function moveAll(src, tgt) { fs.readdirSync(src) .filter(f => f.endsWith('.js')) - .forEach(f => log(`Moving ${f} from ${src} to ${tgt}...`) || fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); + .forEach(f => fs.renameSync(`${src}/${f}`, `${tgt}/${f}`)); } function loadMigrationsList() { From 4c5ce3a4bd957aaa1b7dcfc7926e1b0072795990 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:12:03 +0000 Subject: [PATCH 041/133] remove superseded migration --- ...-01-disable-nullable-blob-content-types.js | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js diff --git a/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js b/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js deleted file mode 100644 index b3844bc3a..000000000 --- a/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2025 ODK Central Developers -// See the NOTICE file at the top-level directory of this distribution and at -// https://github.com/getodk/central-backend/blob/master/NOTICE. -// This file is part of ODK Central. It is subject to the license terms in -// the LICENSE file found in the top-level directory of this distribution and at -// https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, -// including this file, may be copied, modified, propagated, or distributed -// except according to the terms contained in the LICENSE file. - -const up = (db) => db.raw(` - UPDATE blobs SET "contentType"='application/octet-stream' WHERE "contentType" IS NULL; - ALTER TABLE blobs - ALTER COLUMN "contentType" SET DEFAULT 'application/octet-stream', - ALTER COLUMN "contentType" SET NOT NULL -`); - -const down = (db) => db.raw(` - ALTER TABLE blobs - ALTER COLUMN "contentType" DROP NOT NULL, - ALTER COLUMN "contentType" DROP DEFAULT -`); - -module.exports = { up, down }; From a15fe022760cb0286f490a45e6c01c7941fb3ef4 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:13:41 +0000 Subject: [PATCH 042/133] lint --- test/db-migrations/migrator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 613f5a6e9..682046896 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -39,7 +39,7 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { function runBefore(migrationName) { const idx = getIndex(migrationName); // eslint-disable-line no-use-before-define - runUntilIndex(idx - 1); + runUntilIndex(idx - 1); // eslint-disable-line no-use-before-define } function runIncluding(lastMigrationToRun) { From b78683db5c164f2e363f47efbc5b33c68a3cbf4f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:14:38 +0000 Subject: [PATCH 043/133] reintroduce faster migration --- .../20250204-01-disable-nullable-blob-content-types.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js b/lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js index eb7bc2c39..9d57cae54 100644 --- a/lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js +++ b/lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js @@ -8,8 +8,8 @@ // except according to the terms contained in the LICENSE file. const up = (db) => db.query(` + UPDATE blobs SET "contentType"='application/octet-stream' WHERE "contentType" IS NULL; ALTER TABLE blobs - ALTER COLUMN "contentType" TYPE TEXT USING(COALESCE("contentType", 'application/octet-stream')), ALTER COLUMN "contentType" SET DEFAULT 'application/octet-stream', ALTER COLUMN "contentType" SET NOT NULL `); From 8b3b4db79c27be35380c2c74c05f8552343aee9f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 4 Feb 2025 06:31:21 +0000 Subject: [PATCH 044/133] Add review query --- lib/bin/run-migrations.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index 09141f4f4..755c6be01 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -14,6 +14,8 @@ const { pgMigrations } = require('../model/pg-migrator'); try { await withKnex(require('config').get('default.database'))(migrate); await pgMigrations(require('config').get('default.database')); + // REVIEW should the new migrator follow the same function signature? e.g. + // withPg(config)(migrate)? } catch (err) { console.error('Error:', err.message); process.exit(1); From b44e6745adba16bdd2a6b09d7da639af1098af01 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 11 Feb 2025 09:33:20 +0000 Subject: [PATCH 045/133] Resolve TODO --- lib/model/knex-migrator.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 2d5b04ee6..68d5f7e64 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -10,7 +10,6 @@ // This is a variety of functions helpful for connecting to and performing // top-level operations with a database, like migrations. -// TODO rename e.g. legacy-knex-migrator // TODO move migration files to e.g. /migrations/legacy const knex = require('knex'); From cf5a4fd473d078cfeba261e1c01fc3cc06541b4b Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 09:42:32 +0000 Subject: [PATCH 046/133] spelling --- lib/model/pg-migrator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index eb936b7be..57d7436cf 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -117,7 +117,7 @@ const pgMigrations = async (config) => { log('Validating', toRun.length, 'migrations...'); for (const { migration, name } of toRun) { - log('Validing migration:', name, '...'); + log('Validating migration:', name, '...'); if (name.length > maxLen) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); From 5dc4df6ada83e8dc49c4a21dab3cab4c3c954c4d Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 09:48:43 +0000 Subject: [PATCH 047/133] Use same migrations table --- lib/model/pg-migrator.js | 64 ++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 57d7436cf..35a1094a4 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -45,7 +45,7 @@ const getMigrationsToRun = async client => { .sort(); log('allMigrations:', allMigrations); - const alreadyRun = (await client.query('SELECT name FROM post_knex_migrations')).rows.map(r => r.name); + const alreadyRun = (await client.query('SELECT name FROM knex_migrations')).rows.map(r => r.name); log('alreadyRun:', alreadyRun); const toRunNames = allMigrations.filter(m => !alreadyRun.includes(m)); @@ -67,44 +67,50 @@ const pgMigrations = async (config) => { // In the main, this migrator is written to behave similarly to knex's: // + // * uses existing knex_migrations and knex_migrations_lock tables // * expects transaction property async .up({ raw }) // * provides implementation of db.raw() // * runs all new migrations in the same transaction // // Notable differences // - // * uses new post_knex_migrations table // * ONLY provides db.raw()-equivalent function to transactions - no knex query builder etc. - // * ONLY implements up(); will throw if a transaction has other properties, except for `down()` which is currently ignored TODO implement this if it's useful to devs - // * gets list of migrations to run _after_ acquiring db lock - // * sets migration_time to be the start of the migration batch's transaction rather than some other intermediate time - + // * ONLY implements up(); will throw if a transaction has other properties, except for `down()` + // which is currently ignored TODO implement this if it's useful to devs + // * gets list of migrations to run _after_ acquiring db lock (knex checks before acquiring + // lock, and then has to re-check afterwards) + // * sets migration_time to be the start of the migration batch's transaction rather than some + // other intermediate time + // * instead of attempting to acquire a lock on the single row in the knex_migrations_lock + // table, this code takes the simpler approach of locking the whole table. This table could + // be discarded completely by instead locking the knex_migrations table, but backwards- + // compatibility is essential to prevent concurrent running of knex-based and pg-based + // migrators. await withPg(config, async client => { try { log('Starting transaction...'); - await client.query('BEGIN'); // TODO do we need a specific transaction type? + await client.query('BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE'); log('Transaction started.'); - log('Acquiring knex lock...'); - // TODO do this... if it's useful. Need to think of _some_ way to prevent new migrations and old migrations running simultaneously. - log('Knex lock acquired'); - - log('Creating new table if not exists...'); - // N.B. this table is created to be similar to the legacy knex-created table. - // The key difference is that name, batch and migration_time columns are - // not nullable. - const maxLen = 255; + log('Creating tables if they do not exist...'); + // N.B. these tables are created to be similar to the legacy knex-created table. + const nameMaxLen = 255; await client.query(` - CREATE TABLE IF NOT EXISTS post_knex_migrations ( - id SERIAL PRIMARY KEY, - name VARCHAR(${maxLen}) NOT NULL, - batch INTEGER NOT NULL, - migration_time TIMESTAMP(3) WITH TIME ZONE NOT NULL - )`); - log('Table now definitely exists.'); - - log('Acquiring lock on post_knex_migrations table...'); - await client.query('LOCK TABLE post_knex_migrations IN EXCLUSIVE MODE NOWAIT'); + CREATE TABLE IF NOT EXISTS knex_migrations ( + id SERIAL PRIMARY KEY, + name VARCHAR(${nameMaxLen}) NOT NULL, + batch INTEGER, + migration_time TIMESTAMP(3) WITH TIME ZONE + ); + CREATE TABLE IF NOT EXISTS knex_migrations_lock ( + index SERIAL PRIMARY KEY, + is_locked INTEGER NOT NULL + ); + `); + log('Tables now definitely exists.'); + + log('Acquiring lock on knex_migrations_lock table...'); + await client.query('LOCK TABLE knex_migrations_lock IN EXCLUSIVE MODE NOWAIT'); log('Lock acquired.'); const toRun = await getMigrationsToRun(client); @@ -119,7 +125,7 @@ const pgMigrations = async (config) => { for (const { migration, name } of toRun) { log('Validating migration:', name, '...'); - if (name.length > maxLen) throw new Error(`Migration name '${name}' is too long - max length is ${maxLen}, but got ${name.length}`); + if (name.length > nameMaxLen) throw new Error(`Migration name '${name}' is too long - max length is ${nameMaxLen}, but got ${name.length}`); // TODO check for illegal chars in name? @@ -148,7 +154,7 @@ const pgMigrations = async (config) => { } log(toRun.length, 'migrations ran OK.'); - const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM post_knex_migrations`)).rows[0]; + const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM knex_migrations`)).rows[0]; log('lastBatch:', lastBatch); // Note that migration_time is CLOCK_TIMESTAMP() to match knex implementation. @@ -156,7 +162,7 @@ const pgMigrations = async (config) => { const namesJson = JSON.stringify(toRun.map(m => m.name)); // See: https://www.postgresql.org/docs/current/functions-json.html await client.query(` - INSERT INTO post_knex_migrations(name, batch, migration_time) + INSERT INTO knex_migrations(name, batch, migration_time) SELECT value#>>'{}' AS name , ${lastBatch + 1} AS batch , CLOCK_TIMESTAMP() AS migration_time From 9d0335f66615fc0b74640c07e54e793437d6386a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 09:50:02 +0000 Subject: [PATCH 048/133] revert name change for describeMigration() --- ...0250204-01-disable-nullable-blob-content-types.spec.js | 4 ++-- test/db-migrations/utils.js | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js index 9ab3b8357..e9b27d750 100644 --- a/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js +++ b/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js @@ -3,11 +3,11 @@ const { hash, randomBytes } = require('node:crypto'); const { // eslint-disable-line object-curly-newline assertTableContents, - describeNewMigration, + describeMigration, rowsExistFor, } = require('./utils'); // eslint-disable-line object-curly-newline -describeNewMigration('20250204-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { +describeMigration('20250204-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { const aBlobWith = props => { const randomContent = randomBytes(100); const md5 = hash('md5', randomContent); // eslint-disable-line no-multi-spaces diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index fe17b10e0..4075620a4 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -34,9 +34,9 @@ function describeLegacyMigration(...args) { return _describeMigration(migrator.l describeLegacyMigration.only = (...args) => _describeMigration(migrator.legacy, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces describeLegacyMigration.skip = (...args) => _describeMigration(migrator.legacy, describe.skip, ...args); // eslint-disable-line no-multi-spaces -function describeNewMigration(...args) { return _describeMigration(migrator.postKnex, describe, ...args); } // eslint-disable-line no-multi-spaces -describeNewMigration.only = (...args) => _describeMigration(migrator.postKnex, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces -describeNewMigration.skip = (...args) => _describeMigration(migrator.postKnex, describe.skip, ...args); // eslint-disable-line no-multi-spaces +function describeMigration(...args) { return _describeMigration(migrator.postKnex, describe, ...args); } // eslint-disable-line no-multi-spaces +describeMigration.only = (...args) => _describeMigration(migrator.postKnex, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces +describeMigration.skip = (...args) => _describeMigration(migrator.postKnex, describe.skip, ...args); // eslint-disable-line no-multi-spaces async function assertIndexExists(tableName, expected) { if (arguments.length !== 2) throw new Error('Incorrect arg count.'); @@ -186,7 +186,7 @@ module.exports = { assertTableSchema, describeLegacyMigration, - describeNewMigration, // TODO rename to simply describeMigration + describeMigration, rowsExistFor, }; From 5336ac9507900c52096baae340ebb8e24c1b6fe0 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 09:57:21 +0000 Subject: [PATCH 049/133] fix knex_migrations table updates --- lib/model/pg-migrator.js | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 35a1094a4..bea20006e 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -147,28 +147,23 @@ const pgMigrations = async (config) => { log(toRun.length, 'migrations look valid.'); log('Running', toRun.length, 'migrations...'); + const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM knex_migrations`)).rows[0]; + const batchNumber = lastBatch + 1; + log(' batch number:', batchNumber); + for (const { migration, name } of toRun) { log('Running migration:', name); await migration.up(client); // eslint-disable-line no-await-in-loop + // `CLOCK_TIMESTAMP()` used to match knex migrator's `new Date()`. + await client.query(` + INSERT INTO knex_migrations + (name, batch, migration_time) + VALUES($1, $2, CLOCK_TIMESTAMP()) + `, [ name, batchNumber ]); log('Migration complete:', name); } log(toRun.length, 'migrations ran OK.'); - const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM knex_migrations`)).rows[0]; - log('lastBatch:', lastBatch); - - // Note that migration_time is CLOCK_TIMESTAMP() to match knex implementation. - // TODO confirm in relevant version of knex source code that this is actually the case, and link here. - const namesJson = JSON.stringify(toRun.map(m => m.name)); - // See: https://www.postgresql.org/docs/current/functions-json.html - await client.query(` - INSERT INTO knex_migrations(name, batch, migration_time) - SELECT value#>>'{}' AS name - , ${lastBatch + 1} AS batch - , CLOCK_TIMESTAMP() AS migration_time - FROM JSON_ARRAY_ELEMENTS($1) - `, [ namesJson ]); - log('Committing migrations...'); await client.query('COMMIT'); log('Migrations committed.'); From 86082d4964a7f391c3bc26dca8069507269f87b3 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:00:43 +0000 Subject: [PATCH 050/133] lint --- Makefile | 6 +----- lib/bin/check-migrations.js | 21 --------------------- lib/model/knex-migrator.js | 10 +--------- lib/model/pg-migrator.js | 18 ++++-------------- 4 files changed, 6 insertions(+), 49 deletions(-) delete mode 100644 lib/bin/check-migrations.js diff --git a/Makefile b/Makefile index 8760c350e..a85ad22f1 100644 --- a/Makefile +++ b/Makefile @@ -72,16 +72,12 @@ fake-s3-server-persistent: migrations: node_version node lib/bin/run-migrations.js -.PHONY: check-migrations -check-migrations: node_version - node lib/bin/check-migrations.js - ################################################################################ # RUN SERVER .PHONY: base -base: node_modules node_version migrations check-migrations +base: node_modules node_version migrations .PHONY: dev dev: base diff --git a/lib/bin/check-migrations.js b/lib/bin/check-migrations.js deleted file mode 100644 index 2db7ca20e..000000000 --- a/lib/bin/check-migrations.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2022 ODK Central Developers -// See the NOTICE file at the top-level directory of this distribution and at -// https://github.com/getodk/central-backend/blob/master/NOTICE. -// This file is part of ODK Central. It is subject to the license terms in -// the LICENSE file found in the top-level directory of this distribution and at -// https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, -// including this file, may be copied, modified, propagated, or distributed -// except according to the terms contained in the LICENSE file. - -const { withKnex, checkMigrations } = require('../model/knex-migrator'); -const { checkPgMigrations } = require('../model/pg-migrator'); - -(async () => { - try { - await withKnex(require('config').get('default.database'))(checkMigrations); - await checkPgMigrations(require('config').get('default.database')); - } catch (err) { - console.error('Error:', err.message); - process.exit(1); - } -})(); diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 68d5f7e64..497659fea 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -27,13 +27,5 @@ const withKnex = (config) => (mutator) => { // Given a database, initiates migrations on it. const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations` }); -// Checks for pending migrations and returns an exit code of 1 if any are -// still pending/unapplied (e.g. automatically running migrations just failed). -const checkMigrations = (db) => db.migrate.list({ directory: `${__dirname}/migrations` }) - .then((res) => { - if (res[1].length > 0) - process.exitCode = 1; - }); - -module.exports = { checkMigrations, knexConnect, withKnex, migrate }; +module.exports = { knexConnect, withKnex, migrate }; diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index bea20006e..fa08fc839 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -151,9 +151,10 @@ const pgMigrations = async (config) => { const batchNumber = lastBatch + 1; log(' batch number:', batchNumber); + /* eslint-disable no-await-in-loop */ for (const { migration, name } of toRun) { log('Running migration:', name); - await migration.up(client); // eslint-disable-line no-await-in-loop + await migration.up(client); // `CLOCK_TIMESTAMP()` used to match knex migrator's `new Date()`. await client.query(` INSERT INTO knex_migrations @@ -162,6 +163,7 @@ const pgMigrations = async (config) => { `, [ name, batchNumber ]); log('Migration complete:', name); } + /* eslint-enable no-await-in-loop */ log(toRun.length, 'migrations ran OK.'); log('Committing migrations...'); @@ -175,16 +177,4 @@ const pgMigrations = async (config) => { }); }; -// Checks for pending migrations and returns an exit code of 1 if any are -// still pending/unapplied (e.g. automatically running migrations just failed). -const checkPgMigrations = async config => { - const log = (...args) => console.log('[checkPgMigrations]', ...args); // eslint-disable-line no-console - log('ENTRY'); - - await withPg(config, async client => { - const toRun = await getMigrationsToRun(client); - if (toRun.length) process.exitCode = 1; - }); -}; - -module.exports = { checkPgMigrations, withPg, pgMigrations }; +module.exports = { withPg, pgMigrations }; From d27608565355d5a423ba0b21063ff569dc6efd74 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:08:08 +0000 Subject: [PATCH 051/133] ignore missing migrations --- lib/model/knex-migrator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 497659fea..a8ec8ed62 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -25,7 +25,8 @@ const withKnex = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations` }); +// Ignore missing migrations, as they probably came from the new migrator. +const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations`, disableMigrationsListValidation: true }); module.exports = { knexConnect, withKnex, migrate }; From 5aba8f82dd15bc00440a88da0fe4be434601930f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:08:58 +0000 Subject: [PATCH 052/133] document previous --- lib/model/pg-migrator.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index fa08fc839..a2a286bb2 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -86,6 +86,8 @@ const pgMigrations = async (config) => { // be discarded completely by instead locking the knex_migrations table, but backwards- // compatibility is essential to prevent concurrent running of knex-based and pg-based // migrators. + // * does not check that all migrations listed in the database table actually exist in the + // filesystem await withPg(config, async client => { try { log('Starting transaction...'); From 9393aa4b767b770326a8ece56a4b96f09f0899a1 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:12:05 +0000 Subject: [PATCH 053/133] change migration directories --- .github/workflows/db-migrations.yml | 2 -- lib/model/knex-migrator.js | 2 +- lib/model/pg-migrator.js | 2 +- test/db-migrations/migrator.js | 4 ++-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/db-migrations.yml b/.github/workflows/db-migrations.yml index 4a33bf04a..8b6594c9c 100644 --- a/.github/workflows/db-migrations.yml +++ b/.github/workflows/db-migrations.yml @@ -6,7 +6,6 @@ on: - .github/workflows/db-migrations.yml - lib/bin/create-docker-databases.js - lib/model/migrations/** - - lib/model/migrations-post-knex/** - test/db-migrations/** - package.json - package-lock.json @@ -16,7 +15,6 @@ on: - .github/workflows/db-migrations.yml - lib/bin/create-docker-databases.js - lib/model/migrations/** - - lib/model/migrations-post-knex/** - test/db-migrations/** - package.json - package-lock.json diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index a8ec8ed62..118ec8c86 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -26,7 +26,7 @@ const withKnex = (config) => (mutator) => { // Given a database, initiates migrations on it. // Ignore missing migrations, as they probably came from the new migrator. -const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations`, disableMigrationsListValidation: true }); +const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy`, disableMigrationsListValidation: true }); module.exports = { knexConnect, withKnex, migrate }; diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index a2a286bb2..44340d974 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -12,7 +12,7 @@ const { lstatSync, readdirSync } = require('node:fs'); const _ = require('lodash'); // eslint-disable-line import/no-extraneous-dependencies const pg = require('pg'); -const migrationsDir = `${__dirname}/migrations-post-knex`; // TODO rename to /migrations/current or something +const migrationsDir = `${__dirname}/migrations`; const withPg = async (config, fn) => { const log = (...args) => console.log('[withPg]', ...args); // eslint-disable-line no-console diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index 682046896..d943c9e43 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -15,8 +15,8 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); -const legacy = createMigrator('Legacy', './lib/model/migrations', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces -const postKnex = createMigrator('Post-knex', './lib/model/migrations-post-knex', './test/db-migrations/.holding-pen/post-knex', legacy); // eslint-disable-line no-use-before-define +const legacy = createMigrator('Legacy', './lib/model/migrations/legacy', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces +const postKnex = createMigrator('Post-knex', './lib/model/migrations', './test/db-migrations/.holding-pen/pg', legacy); // eslint-disable-line no-use-before-define, no-multi-spaces module.exports = { legacy, postKnex }; From 0cee98331c75108ff1674d02890cdcf8d6e9fa68 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:14:26 +0000 Subject: [PATCH 054/133] move migrations --- lib/model/migrations/{ => legacy}/.eslintrc.json | 0 lib/model/migrations/{ => legacy}/20170920-01-initial.js | 0 lib/model/migrations/{ => legacy}/20171010-01-auth.js | 0 lib/model/migrations/{ => legacy}/20171023-01-authz-forms.js | 0 .../{ => legacy}/20171030-01-add-default-authz-records.js | 0 .../{ => legacy}/20171106-01-remove-user-update-timestamp.js | 0 .../{ => legacy}/20171121-01-add-submissions-constraint.js | 0 lib/model/migrations/{ => legacy}/20171121-02-add-submitter.js | 0 .../migrations/{ => legacy}/20171213-01-unrequire-display-name.js | 0 lib/model/migrations/{ => legacy}/20180108-01-expiring-actors.js | 0 lib/model/migrations/{ => legacy}/20180108-02-enum-to-varchar.js | 0 lib/model/migrations/{ => legacy}/20180112-01-audit-table.js | 0 lib/model/migrations/{ => legacy}/20180112-02-add-field-keys.js | 0 .../migrations/{ => legacy}/20180118-01-rerequire-display-name.js | 0 .../migrations/{ => legacy}/20180125-01-add-form-detail-fields.js | 0 .../migrations/{ => legacy}/20180125-02-more-field-key-grants.js | 0 lib/model/migrations/{ => legacy}/20180125-03-add-blob-tables.js | 0 lib/model/migrations/{ => legacy}/20180301-01-configuration.js | 0 .../{ => legacy}/20180322-01-additional-form-options.js | 0 .../{ => legacy}/20180327-01-update-form-constraints.js | 0 .../migrations/{ => legacy}/20180501-01-add-configs-timestamp.js | 0 lib/model/migrations/{ => legacy}/20180501-02-fix-date-columns.js | 0 .../{ => legacy}/20180515-01-enforce-nonnull-form-version.js | 0 .../{ => legacy}/20180727-01-rename-attachments-table.js | 0 lib/model/migrations/{ => legacy}/20180727-02-add-md5-to-blobs.js | 0 .../{ => legacy}/20180727-03-add-form-attachments-table.js | 0 .../{ => legacy}/20181011-make-email-case-insensitive.js | 0 .../{ => legacy}/20181012-01-add-submissions-createdat-index.js | 0 lib/model/migrations/{ => legacy}/20181206-01-add-projects.js | 0 .../migrations/{ => legacy}/20181207-01-grant-verbs-to-text.js | 0 .../migrations/{ => legacy}/20181207-02-rename-grant-verbs.js | 0 .../migrations/{ => legacy}/20181211-01-audit-verbs-to-text.js | 0 .../migrations/{ => legacy}/20181211-02-rename-audit-actions.js | 0 lib/model/migrations/{ => legacy}/20181212-00-fix-user-type.js | 0 lib/model/migrations/{ => legacy}/20181212-01-add-roles.js | 0 lib/model/migrations/{ => legacy}/20181212-02-remove-groups.js | 0 .../migrations/{ => legacy}/20181212-03-add-single-use-roles.js | 0 .../{ => legacy}/20181219-01-add-submission-update-verb.js | 0 .../{ => legacy}/20181221-01-nullable-submission-blobs.js | 0 .../{ => legacy}/20181230-01-add-device-id-to-submission.js | 0 .../{ => legacy}/20190225-01-add-actor-trigram-indices.js | 0 lib/model/migrations/{ => legacy}/20190225-02-add-role-grants.js | 0 .../migrations/{ => legacy}/20190226-01-convert-verbs-to-jsonb.js | 0 .../migrations/{ => legacy}/20190226-02-add-role-actee-species.js | 0 .../migrations/{ => legacy}/20190226-03-add-assignment-verbs.js | 0 .../{ => legacy}/20190226-04-add-assignment-actee-species.js | 0 .../{ => legacy}/20190227-01-add-project-manager-role.js | 0 .../{ => legacy}/20190405-01-add-project-archival-flag.js | 0 lib/model/migrations/{ => legacy}/20190416-01-email-uniqueness.js | 0 .../migrations/{ => legacy}/20190416-02-add-user-delete-verb.js | 0 .../migrations/{ => legacy}/20190520-01-add-form-versioning.js | 0 .../{ => legacy}/20190523-01-add-form-state-constraint.js | 0 lib/model/migrations/{ => legacy}/20190605-01-reformat-audits.js | 0 .../{ => legacy}/20190607-01-convert-audit-details-to-jsonb.js | 0 .../{ => legacy}/20190607-02-standardize-attachment-actees.js | 0 .../{ => legacy}/20190607-03-rename-sub-attachment-audits.js | 0 lib/model/migrations/{ => legacy}/20190610-01-add-audits-verbs.js | 0 .../20190610-02-backfill-submission-audit-instanceids.js | 0 .../{ => legacy}/20190611-01-add-updatedat-to-form-attachments.js | 0 lib/model/migrations/{ => legacy}/20190618-01-add-csrf-token.js | 0 .../{ => legacy}/20190618-01-add-encryption-tracking.js | 0 .../{ => legacy}/20190701-01-add-managed-encryption-key-check.js | 0 .../{ => legacy}/20190916-01-granularize-app-user-permissions.js | 0 .../migrations/{ => legacy}/20190917-01-cleanup-app-user-role.js | 0 .../{ => legacy}/20190923-01-add-project-viewer-role.js | 0 .../migrations/{ => legacy}/20190925-01-add-client-audits.js | 0 .../migrations/{ => legacy}/20191007-01-backfill-client-audits.js | 0 .../{ => legacy}/20191010-01-add-excel-blob-reference.js | 0 .../{ => legacy}/20191023-01-add-worker-columns-to-audits.js | 0 lib/model/migrations/{ => legacy}/20191025-01-add-id-to-audits.js | 0 .../{ => legacy}/20191106-01-remove-deleted-actor-assignments.js | 0 .../migrations/{ => legacy}/20191231-01-remove-transformations.js | 0 .../migrations/{ => legacy}/20191231-02-add-schema-storage.js | 0 lib/model/migrations/{ => legacy}/20200110-01-add-drafts.js | 0 .../migrations/{ => legacy}/20200112-01-check-field-collisions.js | 0 .../{ => legacy}/20200114-01-remove-formid-sha256-constraint.js | 0 .../migrations/{ => legacy}/20200117-01-draft-test-submissions.js | 0 lib/model/migrations/{ => legacy}/20200121-01-add-draft-keys.js | 0 .../{ => legacy}/20200122-01-remove-draft-form-state.js | 0 .../{ => legacy}/20200129-01-cascade-submission-deletes.js | 0 .../{ => legacy}/20200220-01-repair-submission-parsing.js | 0 .../{ => legacy}/20200403-01-add-performance-indices.js | 0 .../{ => legacy}/20200407-01-allow-actorless-submission-defs.js | 0 .../{ => legacy}/20200423-01-fix-field-insert-performance.js | 0 .../migrations/{ => legacy}/20200428-01-allow-string-downcast.js | 0 lib/model/migrations/{ => legacy}/20200519-01-add-enketo-id.js | 0 .../migrations/{ => legacy}/20200519-02-add-form-viewer-role.js | 0 lib/model/migrations/{ => legacy}/20200520-01-backfill-enketo.js | 0 .../{ => legacy}/20200715-01-add-data-collector-role.js | 0 lib/model/migrations/{ => legacy}/20200721-01-add-public-links.js | 0 .../{ => legacy}/20200728-01-add-enketo-single-token-to-forms.js | 0 .../20200731-01-allow-project-managers-to-end-sessions.js | 0 .../{ => legacy}/20200810-01-reschedule-enketo-processing.js | 0 .../{ => legacy}/20200918-01-repair-publishedat-dates.js | 0 .../migrations/{ => legacy}/20200930-01-add-backup-run-verb.js | 0 .../20201117-01-remove-deleted-actor-assignments-again.js | 0 .../{ => legacy}/20201207-01-harmonize-submitter-id-columns.js | 0 .../20210118-01-add-current-flag-to-submission-defs.js | 0 lib/model/migrations/{ => legacy}/20210120-01-instance-names.js | 0 .../{ => legacy}/20210203-01-add-hierarchy-to-actees.js | 0 .../{ => legacy}/20210210-01-add-instanceid-to-submission-defs.js | 0 .../{ => legacy}/20210218-01-add-submission-edit-verbs.js | 0 .../{ => legacy}/20210218-02-add-draft-to-submissions-unique.js | 0 lib/model/migrations/{ => legacy}/20210219-01-add-review-state.js | 0 .../{ => legacy}/20210219-02-add-notes-and-index-to-audits.js | 0 .../20210324-01-add-submission-edit-verbs-to-managers.js | 0 .../{ => legacy}/20210325-01-remove-project.list-verb.js | 0 .../{ => legacy}/20210408-01-drop-public-link-createdat.js | 0 .../{ => legacy}/20210408-02-backfill-specialized-actor-audits.js | 0 lib/model/migrations/{ => legacy}/20210409-01-add-comments.js | 0 .../migrations/{ => legacy}/20210409-02-update-review-states.js | 0 .../migrations/{ => legacy}/20210423-01-add-name-to-form-def.js | 0 lib/model/migrations/{ => legacy}/20210423-02-drop-form-name.js | 0 .../migrations/{ => legacy}/20210716-01-config-value-jsonb.js | 0 .../migrations/{ => legacy}/20210721-01-add-config-set-verb.js | 0 .../20210817-01-disallow-structure-downcast-to-string.js | 0 .../{ => legacy}/20210825-01-add-analytics-read-verb.js | 0 .../{ => legacy}/20210903-01-backfill-encrypted-client-audits.js | 0 .../20210927-01-revert-disallow-structure-downcast.js | 0 .../{ => legacy}/20211008-01-track-select-many-options.js | 0 .../migrations/{ => legacy}/20211021-remove-hashes-from-audits.js | 0 .../{ => legacy}/20211109-01-add-user-agent-to-submissions.js | 0 .../{ => legacy}/20211114-01-flag-initial-submission-def.js | 0 .../migrations/{ => legacy}/20211117-01-add-form-restore-verb.js | 0 .../{ => legacy}/20211129-01-add-purged-details-to-actees.js | 0 .../migrations/{ => legacy}/20220121-01-form-cascade-delete.js | 0 .../migrations/{ => legacy}/20220121-02-purge-deleted-forms.js | 0 .../migrations/{ => legacy}/20220209-01-purge-unneeded-drafts.js | 0 .../{ => legacy}/20220309-01-add-project-description.js | 0 .../migrations/{ => legacy}/20220803-01-create-entities-schema.js | 0 .../migrations/{ => legacy}/20221003-01-add-dataset-verbs.js | 0 .../{ => legacy}/20221114-01-explict-dataset-publish.js | 0 .../20221117-01-check-datasetId-is-null-for-non-file-type.js | 0 .../{ => legacy}/20221118-01-make-entities-columns-not-null.js | 0 .../migrations/{ => legacy}/20221208-01-reduce-tz-precision.js | 0 .../migrations/{ => legacy}/20230106-01-remove-revision-number.js | 0 lib/model/migrations/{ => legacy}/20230109-01-add-form-schema.js | 0 .../migrations/{ => legacy}/20230123-01-remove-google-backups.js | 0 .../migrations/{ => legacy}/20230126-01-add-entity-indices.js | 0 .../{ => legacy}/20230127-01-rename-entity-created-by.js | 0 .../migrations/{ => legacy}/20230324-01-edit-dataset-verbs.js | 0 .../migrations/{ => legacy}/20230406-01-add-entity-def-fields.js | 0 .../{ => legacy}/20230406-02-move-entity-label-add-deletedAt.js | 0 .../migrations/{ => legacy}/20230414-01-remove-user-mfa-secret.js | 0 .../{ => legacy}/20230419-01-optimize-indices-sub-defs.js | 0 .../migrations/{ => legacy}/20230509-01-dataset-approval-flag.js | 0 lib/model/migrations/{ => legacy}/20230512-01-add-entity-root.js | 0 .../migrations/{ => legacy}/20230512-02-backfill-entity-id.js | 0 .../migrations/{ => legacy}/20230512-03-add-entity-source.js | 0 .../{ => legacy}/20230518-01-add-entity-index-to-audits.js | 0 150 files changed, 0 insertions(+), 0 deletions(-) rename lib/model/migrations/{ => legacy}/.eslintrc.json (100%) rename lib/model/migrations/{ => legacy}/20170920-01-initial.js (100%) rename lib/model/migrations/{ => legacy}/20171010-01-auth.js (100%) rename lib/model/migrations/{ => legacy}/20171023-01-authz-forms.js (100%) rename lib/model/migrations/{ => legacy}/20171030-01-add-default-authz-records.js (100%) rename lib/model/migrations/{ => legacy}/20171106-01-remove-user-update-timestamp.js (100%) rename lib/model/migrations/{ => legacy}/20171121-01-add-submissions-constraint.js (100%) rename lib/model/migrations/{ => legacy}/20171121-02-add-submitter.js (100%) rename lib/model/migrations/{ => legacy}/20171213-01-unrequire-display-name.js (100%) rename lib/model/migrations/{ => legacy}/20180108-01-expiring-actors.js (100%) rename lib/model/migrations/{ => legacy}/20180108-02-enum-to-varchar.js (100%) rename lib/model/migrations/{ => legacy}/20180112-01-audit-table.js (100%) rename lib/model/migrations/{ => legacy}/20180112-02-add-field-keys.js (100%) rename lib/model/migrations/{ => legacy}/20180118-01-rerequire-display-name.js (100%) rename lib/model/migrations/{ => legacy}/20180125-01-add-form-detail-fields.js (100%) rename lib/model/migrations/{ => legacy}/20180125-02-more-field-key-grants.js (100%) rename lib/model/migrations/{ => legacy}/20180125-03-add-blob-tables.js (100%) rename lib/model/migrations/{ => legacy}/20180301-01-configuration.js (100%) rename lib/model/migrations/{ => legacy}/20180322-01-additional-form-options.js (100%) rename lib/model/migrations/{ => legacy}/20180327-01-update-form-constraints.js (100%) rename lib/model/migrations/{ => legacy}/20180501-01-add-configs-timestamp.js (100%) rename lib/model/migrations/{ => legacy}/20180501-02-fix-date-columns.js (100%) rename lib/model/migrations/{ => legacy}/20180515-01-enforce-nonnull-form-version.js (100%) rename lib/model/migrations/{ => legacy}/20180727-01-rename-attachments-table.js (100%) rename lib/model/migrations/{ => legacy}/20180727-02-add-md5-to-blobs.js (100%) rename lib/model/migrations/{ => legacy}/20180727-03-add-form-attachments-table.js (100%) rename lib/model/migrations/{ => legacy}/20181011-make-email-case-insensitive.js (100%) rename lib/model/migrations/{ => legacy}/20181012-01-add-submissions-createdat-index.js (100%) rename lib/model/migrations/{ => legacy}/20181206-01-add-projects.js (100%) rename lib/model/migrations/{ => legacy}/20181207-01-grant-verbs-to-text.js (100%) rename lib/model/migrations/{ => legacy}/20181207-02-rename-grant-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20181211-01-audit-verbs-to-text.js (100%) rename lib/model/migrations/{ => legacy}/20181211-02-rename-audit-actions.js (100%) rename lib/model/migrations/{ => legacy}/20181212-00-fix-user-type.js (100%) rename lib/model/migrations/{ => legacy}/20181212-01-add-roles.js (100%) rename lib/model/migrations/{ => legacy}/20181212-02-remove-groups.js (100%) rename lib/model/migrations/{ => legacy}/20181212-03-add-single-use-roles.js (100%) rename lib/model/migrations/{ => legacy}/20181219-01-add-submission-update-verb.js (100%) rename lib/model/migrations/{ => legacy}/20181221-01-nullable-submission-blobs.js (100%) rename lib/model/migrations/{ => legacy}/20181230-01-add-device-id-to-submission.js (100%) rename lib/model/migrations/{ => legacy}/20190225-01-add-actor-trigram-indices.js (100%) rename lib/model/migrations/{ => legacy}/20190225-02-add-role-grants.js (100%) rename lib/model/migrations/{ => legacy}/20190226-01-convert-verbs-to-jsonb.js (100%) rename lib/model/migrations/{ => legacy}/20190226-02-add-role-actee-species.js (100%) rename lib/model/migrations/{ => legacy}/20190226-03-add-assignment-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20190226-04-add-assignment-actee-species.js (100%) rename lib/model/migrations/{ => legacy}/20190227-01-add-project-manager-role.js (100%) rename lib/model/migrations/{ => legacy}/20190405-01-add-project-archival-flag.js (100%) rename lib/model/migrations/{ => legacy}/20190416-01-email-uniqueness.js (100%) rename lib/model/migrations/{ => legacy}/20190416-02-add-user-delete-verb.js (100%) rename lib/model/migrations/{ => legacy}/20190520-01-add-form-versioning.js (100%) rename lib/model/migrations/{ => legacy}/20190523-01-add-form-state-constraint.js (100%) rename lib/model/migrations/{ => legacy}/20190605-01-reformat-audits.js (100%) rename lib/model/migrations/{ => legacy}/20190607-01-convert-audit-details-to-jsonb.js (100%) rename lib/model/migrations/{ => legacy}/20190607-02-standardize-attachment-actees.js (100%) rename lib/model/migrations/{ => legacy}/20190607-03-rename-sub-attachment-audits.js (100%) rename lib/model/migrations/{ => legacy}/20190610-01-add-audits-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20190610-02-backfill-submission-audit-instanceids.js (100%) rename lib/model/migrations/{ => legacy}/20190611-01-add-updatedat-to-form-attachments.js (100%) rename lib/model/migrations/{ => legacy}/20190618-01-add-csrf-token.js (100%) rename lib/model/migrations/{ => legacy}/20190618-01-add-encryption-tracking.js (100%) rename lib/model/migrations/{ => legacy}/20190701-01-add-managed-encryption-key-check.js (100%) rename lib/model/migrations/{ => legacy}/20190916-01-granularize-app-user-permissions.js (100%) rename lib/model/migrations/{ => legacy}/20190917-01-cleanup-app-user-role.js (100%) rename lib/model/migrations/{ => legacy}/20190923-01-add-project-viewer-role.js (100%) rename lib/model/migrations/{ => legacy}/20190925-01-add-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191007-01-backfill-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191010-01-add-excel-blob-reference.js (100%) rename lib/model/migrations/{ => legacy}/20191023-01-add-worker-columns-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191025-01-add-id-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20191106-01-remove-deleted-actor-assignments.js (100%) rename lib/model/migrations/{ => legacy}/20191231-01-remove-transformations.js (100%) rename lib/model/migrations/{ => legacy}/20191231-02-add-schema-storage.js (100%) rename lib/model/migrations/{ => legacy}/20200110-01-add-drafts.js (100%) rename lib/model/migrations/{ => legacy}/20200112-01-check-field-collisions.js (100%) rename lib/model/migrations/{ => legacy}/20200114-01-remove-formid-sha256-constraint.js (100%) rename lib/model/migrations/{ => legacy}/20200117-01-draft-test-submissions.js (100%) rename lib/model/migrations/{ => legacy}/20200121-01-add-draft-keys.js (100%) rename lib/model/migrations/{ => legacy}/20200122-01-remove-draft-form-state.js (100%) rename lib/model/migrations/{ => legacy}/20200129-01-cascade-submission-deletes.js (100%) rename lib/model/migrations/{ => legacy}/20200220-01-repair-submission-parsing.js (100%) rename lib/model/migrations/{ => legacy}/20200403-01-add-performance-indices.js (100%) rename lib/model/migrations/{ => legacy}/20200407-01-allow-actorless-submission-defs.js (100%) rename lib/model/migrations/{ => legacy}/20200423-01-fix-field-insert-performance.js (100%) rename lib/model/migrations/{ => legacy}/20200428-01-allow-string-downcast.js (100%) rename lib/model/migrations/{ => legacy}/20200519-01-add-enketo-id.js (100%) rename lib/model/migrations/{ => legacy}/20200519-02-add-form-viewer-role.js (100%) rename lib/model/migrations/{ => legacy}/20200520-01-backfill-enketo.js (100%) rename lib/model/migrations/{ => legacy}/20200715-01-add-data-collector-role.js (100%) rename lib/model/migrations/{ => legacy}/20200721-01-add-public-links.js (100%) rename lib/model/migrations/{ => legacy}/20200728-01-add-enketo-single-token-to-forms.js (100%) rename lib/model/migrations/{ => legacy}/20200731-01-allow-project-managers-to-end-sessions.js (100%) rename lib/model/migrations/{ => legacy}/20200810-01-reschedule-enketo-processing.js (100%) rename lib/model/migrations/{ => legacy}/20200918-01-repair-publishedat-dates.js (100%) rename lib/model/migrations/{ => legacy}/20200930-01-add-backup-run-verb.js (100%) rename lib/model/migrations/{ => legacy}/20201117-01-remove-deleted-actor-assignments-again.js (100%) rename lib/model/migrations/{ => legacy}/20201207-01-harmonize-submitter-id-columns.js (100%) rename lib/model/migrations/{ => legacy}/20210118-01-add-current-flag-to-submission-defs.js (100%) rename lib/model/migrations/{ => legacy}/20210120-01-instance-names.js (100%) rename lib/model/migrations/{ => legacy}/20210203-01-add-hierarchy-to-actees.js (100%) rename lib/model/migrations/{ => legacy}/20210210-01-add-instanceid-to-submission-defs.js (100%) rename lib/model/migrations/{ => legacy}/20210218-01-add-submission-edit-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20210218-02-add-draft-to-submissions-unique.js (100%) rename lib/model/migrations/{ => legacy}/20210219-01-add-review-state.js (100%) rename lib/model/migrations/{ => legacy}/20210219-02-add-notes-and-index-to-audits.js (100%) rename lib/model/migrations/{ => legacy}/20210324-01-add-submission-edit-verbs-to-managers.js (100%) rename lib/model/migrations/{ => legacy}/20210325-01-remove-project.list-verb.js (100%) rename lib/model/migrations/{ => legacy}/20210408-01-drop-public-link-createdat.js (100%) rename lib/model/migrations/{ => legacy}/20210408-02-backfill-specialized-actor-audits.js (100%) rename lib/model/migrations/{ => legacy}/20210409-01-add-comments.js (100%) rename lib/model/migrations/{ => legacy}/20210409-02-update-review-states.js (100%) rename lib/model/migrations/{ => legacy}/20210423-01-add-name-to-form-def.js (100%) rename lib/model/migrations/{ => legacy}/20210423-02-drop-form-name.js (100%) rename lib/model/migrations/{ => legacy}/20210716-01-config-value-jsonb.js (100%) rename lib/model/migrations/{ => legacy}/20210721-01-add-config-set-verb.js (100%) rename lib/model/migrations/{ => legacy}/20210817-01-disallow-structure-downcast-to-string.js (100%) rename lib/model/migrations/{ => legacy}/20210825-01-add-analytics-read-verb.js (100%) rename lib/model/migrations/{ => legacy}/20210903-01-backfill-encrypted-client-audits.js (100%) rename lib/model/migrations/{ => legacy}/20210927-01-revert-disallow-structure-downcast.js (100%) rename lib/model/migrations/{ => legacy}/20211008-01-track-select-many-options.js (100%) rename lib/model/migrations/{ => legacy}/20211021-remove-hashes-from-audits.js (100%) rename lib/model/migrations/{ => legacy}/20211109-01-add-user-agent-to-submissions.js (100%) rename lib/model/migrations/{ => legacy}/20211114-01-flag-initial-submission-def.js (100%) rename lib/model/migrations/{ => legacy}/20211117-01-add-form-restore-verb.js (100%) rename lib/model/migrations/{ => legacy}/20211129-01-add-purged-details-to-actees.js (100%) rename lib/model/migrations/{ => legacy}/20220121-01-form-cascade-delete.js (100%) rename lib/model/migrations/{ => legacy}/20220121-02-purge-deleted-forms.js (100%) rename lib/model/migrations/{ => legacy}/20220209-01-purge-unneeded-drafts.js (100%) rename lib/model/migrations/{ => legacy}/20220309-01-add-project-description.js (100%) rename lib/model/migrations/{ => legacy}/20220803-01-create-entities-schema.js (100%) rename lib/model/migrations/{ => legacy}/20221003-01-add-dataset-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20221114-01-explict-dataset-publish.js (100%) rename lib/model/migrations/{ => legacy}/20221117-01-check-datasetId-is-null-for-non-file-type.js (100%) rename lib/model/migrations/{ => legacy}/20221118-01-make-entities-columns-not-null.js (100%) rename lib/model/migrations/{ => legacy}/20221208-01-reduce-tz-precision.js (100%) rename lib/model/migrations/{ => legacy}/20230106-01-remove-revision-number.js (100%) rename lib/model/migrations/{ => legacy}/20230109-01-add-form-schema.js (100%) rename lib/model/migrations/{ => legacy}/20230123-01-remove-google-backups.js (100%) rename lib/model/migrations/{ => legacy}/20230126-01-add-entity-indices.js (100%) rename lib/model/migrations/{ => legacy}/20230127-01-rename-entity-created-by.js (100%) rename lib/model/migrations/{ => legacy}/20230324-01-edit-dataset-verbs.js (100%) rename lib/model/migrations/{ => legacy}/20230406-01-add-entity-def-fields.js (100%) rename lib/model/migrations/{ => legacy}/20230406-02-move-entity-label-add-deletedAt.js (100%) rename lib/model/migrations/{ => legacy}/20230414-01-remove-user-mfa-secret.js (100%) rename lib/model/migrations/{ => legacy}/20230419-01-optimize-indices-sub-defs.js (100%) rename lib/model/migrations/{ => legacy}/20230509-01-dataset-approval-flag.js (100%) rename lib/model/migrations/{ => legacy}/20230512-01-add-entity-root.js (100%) rename lib/model/migrations/{ => legacy}/20230512-02-backfill-entity-id.js (100%) rename lib/model/migrations/{ => legacy}/20230512-03-add-entity-source.js (100%) rename lib/model/migrations/{ => legacy}/20230518-01-add-entity-index-to-audits.js (100%) diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/legacy/.eslintrc.json similarity index 100% rename from lib/model/migrations/.eslintrc.json rename to lib/model/migrations/legacy/.eslintrc.json diff --git a/lib/model/migrations/20170920-01-initial.js b/lib/model/migrations/legacy/20170920-01-initial.js similarity index 100% rename from lib/model/migrations/20170920-01-initial.js rename to lib/model/migrations/legacy/20170920-01-initial.js diff --git a/lib/model/migrations/20171010-01-auth.js b/lib/model/migrations/legacy/20171010-01-auth.js similarity index 100% rename from lib/model/migrations/20171010-01-auth.js rename to lib/model/migrations/legacy/20171010-01-auth.js diff --git a/lib/model/migrations/20171023-01-authz-forms.js b/lib/model/migrations/legacy/20171023-01-authz-forms.js similarity index 100% rename from lib/model/migrations/20171023-01-authz-forms.js rename to lib/model/migrations/legacy/20171023-01-authz-forms.js diff --git a/lib/model/migrations/20171030-01-add-default-authz-records.js b/lib/model/migrations/legacy/20171030-01-add-default-authz-records.js similarity index 100% rename from lib/model/migrations/20171030-01-add-default-authz-records.js rename to lib/model/migrations/legacy/20171030-01-add-default-authz-records.js diff --git a/lib/model/migrations/20171106-01-remove-user-update-timestamp.js b/lib/model/migrations/legacy/20171106-01-remove-user-update-timestamp.js similarity index 100% rename from lib/model/migrations/20171106-01-remove-user-update-timestamp.js rename to lib/model/migrations/legacy/20171106-01-remove-user-update-timestamp.js diff --git a/lib/model/migrations/20171121-01-add-submissions-constraint.js b/lib/model/migrations/legacy/20171121-01-add-submissions-constraint.js similarity index 100% rename from lib/model/migrations/20171121-01-add-submissions-constraint.js rename to lib/model/migrations/legacy/20171121-01-add-submissions-constraint.js diff --git a/lib/model/migrations/20171121-02-add-submitter.js b/lib/model/migrations/legacy/20171121-02-add-submitter.js similarity index 100% rename from lib/model/migrations/20171121-02-add-submitter.js rename to lib/model/migrations/legacy/20171121-02-add-submitter.js diff --git a/lib/model/migrations/20171213-01-unrequire-display-name.js b/lib/model/migrations/legacy/20171213-01-unrequire-display-name.js similarity index 100% rename from lib/model/migrations/20171213-01-unrequire-display-name.js rename to lib/model/migrations/legacy/20171213-01-unrequire-display-name.js diff --git a/lib/model/migrations/20180108-01-expiring-actors.js b/lib/model/migrations/legacy/20180108-01-expiring-actors.js similarity index 100% rename from lib/model/migrations/20180108-01-expiring-actors.js rename to lib/model/migrations/legacy/20180108-01-expiring-actors.js diff --git a/lib/model/migrations/20180108-02-enum-to-varchar.js b/lib/model/migrations/legacy/20180108-02-enum-to-varchar.js similarity index 100% rename from lib/model/migrations/20180108-02-enum-to-varchar.js rename to lib/model/migrations/legacy/20180108-02-enum-to-varchar.js diff --git a/lib/model/migrations/20180112-01-audit-table.js b/lib/model/migrations/legacy/20180112-01-audit-table.js similarity index 100% rename from lib/model/migrations/20180112-01-audit-table.js rename to lib/model/migrations/legacy/20180112-01-audit-table.js diff --git a/lib/model/migrations/20180112-02-add-field-keys.js b/lib/model/migrations/legacy/20180112-02-add-field-keys.js similarity index 100% rename from lib/model/migrations/20180112-02-add-field-keys.js rename to lib/model/migrations/legacy/20180112-02-add-field-keys.js diff --git a/lib/model/migrations/20180118-01-rerequire-display-name.js b/lib/model/migrations/legacy/20180118-01-rerequire-display-name.js similarity index 100% rename from lib/model/migrations/20180118-01-rerequire-display-name.js rename to lib/model/migrations/legacy/20180118-01-rerequire-display-name.js diff --git a/lib/model/migrations/20180125-01-add-form-detail-fields.js b/lib/model/migrations/legacy/20180125-01-add-form-detail-fields.js similarity index 100% rename from lib/model/migrations/20180125-01-add-form-detail-fields.js rename to lib/model/migrations/legacy/20180125-01-add-form-detail-fields.js diff --git a/lib/model/migrations/20180125-02-more-field-key-grants.js b/lib/model/migrations/legacy/20180125-02-more-field-key-grants.js similarity index 100% rename from lib/model/migrations/20180125-02-more-field-key-grants.js rename to lib/model/migrations/legacy/20180125-02-more-field-key-grants.js diff --git a/lib/model/migrations/20180125-03-add-blob-tables.js b/lib/model/migrations/legacy/20180125-03-add-blob-tables.js similarity index 100% rename from lib/model/migrations/20180125-03-add-blob-tables.js rename to lib/model/migrations/legacy/20180125-03-add-blob-tables.js diff --git a/lib/model/migrations/20180301-01-configuration.js b/lib/model/migrations/legacy/20180301-01-configuration.js similarity index 100% rename from lib/model/migrations/20180301-01-configuration.js rename to lib/model/migrations/legacy/20180301-01-configuration.js diff --git a/lib/model/migrations/20180322-01-additional-form-options.js b/lib/model/migrations/legacy/20180322-01-additional-form-options.js similarity index 100% rename from lib/model/migrations/20180322-01-additional-form-options.js rename to lib/model/migrations/legacy/20180322-01-additional-form-options.js diff --git a/lib/model/migrations/20180327-01-update-form-constraints.js b/lib/model/migrations/legacy/20180327-01-update-form-constraints.js similarity index 100% rename from lib/model/migrations/20180327-01-update-form-constraints.js rename to lib/model/migrations/legacy/20180327-01-update-form-constraints.js diff --git a/lib/model/migrations/20180501-01-add-configs-timestamp.js b/lib/model/migrations/legacy/20180501-01-add-configs-timestamp.js similarity index 100% rename from lib/model/migrations/20180501-01-add-configs-timestamp.js rename to lib/model/migrations/legacy/20180501-01-add-configs-timestamp.js diff --git a/lib/model/migrations/20180501-02-fix-date-columns.js b/lib/model/migrations/legacy/20180501-02-fix-date-columns.js similarity index 100% rename from lib/model/migrations/20180501-02-fix-date-columns.js rename to lib/model/migrations/legacy/20180501-02-fix-date-columns.js diff --git a/lib/model/migrations/20180515-01-enforce-nonnull-form-version.js b/lib/model/migrations/legacy/20180515-01-enforce-nonnull-form-version.js similarity index 100% rename from lib/model/migrations/20180515-01-enforce-nonnull-form-version.js rename to lib/model/migrations/legacy/20180515-01-enforce-nonnull-form-version.js diff --git a/lib/model/migrations/20180727-01-rename-attachments-table.js b/lib/model/migrations/legacy/20180727-01-rename-attachments-table.js similarity index 100% rename from lib/model/migrations/20180727-01-rename-attachments-table.js rename to lib/model/migrations/legacy/20180727-01-rename-attachments-table.js diff --git a/lib/model/migrations/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js similarity index 100% rename from lib/model/migrations/20180727-02-add-md5-to-blobs.js rename to lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js diff --git a/lib/model/migrations/20180727-03-add-form-attachments-table.js b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js similarity index 100% rename from lib/model/migrations/20180727-03-add-form-attachments-table.js rename to lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js diff --git a/lib/model/migrations/20181011-make-email-case-insensitive.js b/lib/model/migrations/legacy/20181011-make-email-case-insensitive.js similarity index 100% rename from lib/model/migrations/20181011-make-email-case-insensitive.js rename to lib/model/migrations/legacy/20181011-make-email-case-insensitive.js diff --git a/lib/model/migrations/20181012-01-add-submissions-createdat-index.js b/lib/model/migrations/legacy/20181012-01-add-submissions-createdat-index.js similarity index 100% rename from lib/model/migrations/20181012-01-add-submissions-createdat-index.js rename to lib/model/migrations/legacy/20181012-01-add-submissions-createdat-index.js diff --git a/lib/model/migrations/20181206-01-add-projects.js b/lib/model/migrations/legacy/20181206-01-add-projects.js similarity index 100% rename from lib/model/migrations/20181206-01-add-projects.js rename to lib/model/migrations/legacy/20181206-01-add-projects.js diff --git a/lib/model/migrations/20181207-01-grant-verbs-to-text.js b/lib/model/migrations/legacy/20181207-01-grant-verbs-to-text.js similarity index 100% rename from lib/model/migrations/20181207-01-grant-verbs-to-text.js rename to lib/model/migrations/legacy/20181207-01-grant-verbs-to-text.js diff --git a/lib/model/migrations/20181207-02-rename-grant-verbs.js b/lib/model/migrations/legacy/20181207-02-rename-grant-verbs.js similarity index 100% rename from lib/model/migrations/20181207-02-rename-grant-verbs.js rename to lib/model/migrations/legacy/20181207-02-rename-grant-verbs.js diff --git a/lib/model/migrations/20181211-01-audit-verbs-to-text.js b/lib/model/migrations/legacy/20181211-01-audit-verbs-to-text.js similarity index 100% rename from lib/model/migrations/20181211-01-audit-verbs-to-text.js rename to lib/model/migrations/legacy/20181211-01-audit-verbs-to-text.js diff --git a/lib/model/migrations/20181211-02-rename-audit-actions.js b/lib/model/migrations/legacy/20181211-02-rename-audit-actions.js similarity index 100% rename from lib/model/migrations/20181211-02-rename-audit-actions.js rename to lib/model/migrations/legacy/20181211-02-rename-audit-actions.js diff --git a/lib/model/migrations/20181212-00-fix-user-type.js b/lib/model/migrations/legacy/20181212-00-fix-user-type.js similarity index 100% rename from lib/model/migrations/20181212-00-fix-user-type.js rename to lib/model/migrations/legacy/20181212-00-fix-user-type.js diff --git a/lib/model/migrations/20181212-01-add-roles.js b/lib/model/migrations/legacy/20181212-01-add-roles.js similarity index 100% rename from lib/model/migrations/20181212-01-add-roles.js rename to lib/model/migrations/legacy/20181212-01-add-roles.js diff --git a/lib/model/migrations/20181212-02-remove-groups.js b/lib/model/migrations/legacy/20181212-02-remove-groups.js similarity index 100% rename from lib/model/migrations/20181212-02-remove-groups.js rename to lib/model/migrations/legacy/20181212-02-remove-groups.js diff --git a/lib/model/migrations/20181212-03-add-single-use-roles.js b/lib/model/migrations/legacy/20181212-03-add-single-use-roles.js similarity index 100% rename from lib/model/migrations/20181212-03-add-single-use-roles.js rename to lib/model/migrations/legacy/20181212-03-add-single-use-roles.js diff --git a/lib/model/migrations/20181219-01-add-submission-update-verb.js b/lib/model/migrations/legacy/20181219-01-add-submission-update-verb.js similarity index 100% rename from lib/model/migrations/20181219-01-add-submission-update-verb.js rename to lib/model/migrations/legacy/20181219-01-add-submission-update-verb.js diff --git a/lib/model/migrations/20181221-01-nullable-submission-blobs.js b/lib/model/migrations/legacy/20181221-01-nullable-submission-blobs.js similarity index 100% rename from lib/model/migrations/20181221-01-nullable-submission-blobs.js rename to lib/model/migrations/legacy/20181221-01-nullable-submission-blobs.js diff --git a/lib/model/migrations/20181230-01-add-device-id-to-submission.js b/lib/model/migrations/legacy/20181230-01-add-device-id-to-submission.js similarity index 100% rename from lib/model/migrations/20181230-01-add-device-id-to-submission.js rename to lib/model/migrations/legacy/20181230-01-add-device-id-to-submission.js diff --git a/lib/model/migrations/20190225-01-add-actor-trigram-indices.js b/lib/model/migrations/legacy/20190225-01-add-actor-trigram-indices.js similarity index 100% rename from lib/model/migrations/20190225-01-add-actor-trigram-indices.js rename to lib/model/migrations/legacy/20190225-01-add-actor-trigram-indices.js diff --git a/lib/model/migrations/20190225-02-add-role-grants.js b/lib/model/migrations/legacy/20190225-02-add-role-grants.js similarity index 100% rename from lib/model/migrations/20190225-02-add-role-grants.js rename to lib/model/migrations/legacy/20190225-02-add-role-grants.js diff --git a/lib/model/migrations/20190226-01-convert-verbs-to-jsonb.js b/lib/model/migrations/legacy/20190226-01-convert-verbs-to-jsonb.js similarity index 100% rename from lib/model/migrations/20190226-01-convert-verbs-to-jsonb.js rename to lib/model/migrations/legacy/20190226-01-convert-verbs-to-jsonb.js diff --git a/lib/model/migrations/20190226-02-add-role-actee-species.js b/lib/model/migrations/legacy/20190226-02-add-role-actee-species.js similarity index 100% rename from lib/model/migrations/20190226-02-add-role-actee-species.js rename to lib/model/migrations/legacy/20190226-02-add-role-actee-species.js diff --git a/lib/model/migrations/20190226-03-add-assignment-verbs.js b/lib/model/migrations/legacy/20190226-03-add-assignment-verbs.js similarity index 100% rename from lib/model/migrations/20190226-03-add-assignment-verbs.js rename to lib/model/migrations/legacy/20190226-03-add-assignment-verbs.js diff --git a/lib/model/migrations/20190226-04-add-assignment-actee-species.js b/lib/model/migrations/legacy/20190226-04-add-assignment-actee-species.js similarity index 100% rename from lib/model/migrations/20190226-04-add-assignment-actee-species.js rename to lib/model/migrations/legacy/20190226-04-add-assignment-actee-species.js diff --git a/lib/model/migrations/20190227-01-add-project-manager-role.js b/lib/model/migrations/legacy/20190227-01-add-project-manager-role.js similarity index 100% rename from lib/model/migrations/20190227-01-add-project-manager-role.js rename to lib/model/migrations/legacy/20190227-01-add-project-manager-role.js diff --git a/lib/model/migrations/20190405-01-add-project-archival-flag.js b/lib/model/migrations/legacy/20190405-01-add-project-archival-flag.js similarity index 100% rename from lib/model/migrations/20190405-01-add-project-archival-flag.js rename to lib/model/migrations/legacy/20190405-01-add-project-archival-flag.js diff --git a/lib/model/migrations/20190416-01-email-uniqueness.js b/lib/model/migrations/legacy/20190416-01-email-uniqueness.js similarity index 100% rename from lib/model/migrations/20190416-01-email-uniqueness.js rename to lib/model/migrations/legacy/20190416-01-email-uniqueness.js diff --git a/lib/model/migrations/20190416-02-add-user-delete-verb.js b/lib/model/migrations/legacy/20190416-02-add-user-delete-verb.js similarity index 100% rename from lib/model/migrations/20190416-02-add-user-delete-verb.js rename to lib/model/migrations/legacy/20190416-02-add-user-delete-verb.js diff --git a/lib/model/migrations/20190520-01-add-form-versioning.js b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js similarity index 100% rename from lib/model/migrations/20190520-01-add-form-versioning.js rename to lib/model/migrations/legacy/20190520-01-add-form-versioning.js diff --git a/lib/model/migrations/20190523-01-add-form-state-constraint.js b/lib/model/migrations/legacy/20190523-01-add-form-state-constraint.js similarity index 100% rename from lib/model/migrations/20190523-01-add-form-state-constraint.js rename to lib/model/migrations/legacy/20190523-01-add-form-state-constraint.js diff --git a/lib/model/migrations/20190605-01-reformat-audits.js b/lib/model/migrations/legacy/20190605-01-reformat-audits.js similarity index 100% rename from lib/model/migrations/20190605-01-reformat-audits.js rename to lib/model/migrations/legacy/20190605-01-reformat-audits.js diff --git a/lib/model/migrations/20190607-01-convert-audit-details-to-jsonb.js b/lib/model/migrations/legacy/20190607-01-convert-audit-details-to-jsonb.js similarity index 100% rename from lib/model/migrations/20190607-01-convert-audit-details-to-jsonb.js rename to lib/model/migrations/legacy/20190607-01-convert-audit-details-to-jsonb.js diff --git a/lib/model/migrations/20190607-02-standardize-attachment-actees.js b/lib/model/migrations/legacy/20190607-02-standardize-attachment-actees.js similarity index 100% rename from lib/model/migrations/20190607-02-standardize-attachment-actees.js rename to lib/model/migrations/legacy/20190607-02-standardize-attachment-actees.js diff --git a/lib/model/migrations/20190607-03-rename-sub-attachment-audits.js b/lib/model/migrations/legacy/20190607-03-rename-sub-attachment-audits.js similarity index 100% rename from lib/model/migrations/20190607-03-rename-sub-attachment-audits.js rename to lib/model/migrations/legacy/20190607-03-rename-sub-attachment-audits.js diff --git a/lib/model/migrations/20190610-01-add-audits-verbs.js b/lib/model/migrations/legacy/20190610-01-add-audits-verbs.js similarity index 100% rename from lib/model/migrations/20190610-01-add-audits-verbs.js rename to lib/model/migrations/legacy/20190610-01-add-audits-verbs.js diff --git a/lib/model/migrations/20190610-02-backfill-submission-audit-instanceids.js b/lib/model/migrations/legacy/20190610-02-backfill-submission-audit-instanceids.js similarity index 100% rename from lib/model/migrations/20190610-02-backfill-submission-audit-instanceids.js rename to lib/model/migrations/legacy/20190610-02-backfill-submission-audit-instanceids.js diff --git a/lib/model/migrations/20190611-01-add-updatedat-to-form-attachments.js b/lib/model/migrations/legacy/20190611-01-add-updatedat-to-form-attachments.js similarity index 100% rename from lib/model/migrations/20190611-01-add-updatedat-to-form-attachments.js rename to lib/model/migrations/legacy/20190611-01-add-updatedat-to-form-attachments.js diff --git a/lib/model/migrations/20190618-01-add-csrf-token.js b/lib/model/migrations/legacy/20190618-01-add-csrf-token.js similarity index 100% rename from lib/model/migrations/20190618-01-add-csrf-token.js rename to lib/model/migrations/legacy/20190618-01-add-csrf-token.js diff --git a/lib/model/migrations/20190618-01-add-encryption-tracking.js b/lib/model/migrations/legacy/20190618-01-add-encryption-tracking.js similarity index 100% rename from lib/model/migrations/20190618-01-add-encryption-tracking.js rename to lib/model/migrations/legacy/20190618-01-add-encryption-tracking.js diff --git a/lib/model/migrations/20190701-01-add-managed-encryption-key-check.js b/lib/model/migrations/legacy/20190701-01-add-managed-encryption-key-check.js similarity index 100% rename from lib/model/migrations/20190701-01-add-managed-encryption-key-check.js rename to lib/model/migrations/legacy/20190701-01-add-managed-encryption-key-check.js diff --git a/lib/model/migrations/20190916-01-granularize-app-user-permissions.js b/lib/model/migrations/legacy/20190916-01-granularize-app-user-permissions.js similarity index 100% rename from lib/model/migrations/20190916-01-granularize-app-user-permissions.js rename to lib/model/migrations/legacy/20190916-01-granularize-app-user-permissions.js diff --git a/lib/model/migrations/20190917-01-cleanup-app-user-role.js b/lib/model/migrations/legacy/20190917-01-cleanup-app-user-role.js similarity index 100% rename from lib/model/migrations/20190917-01-cleanup-app-user-role.js rename to lib/model/migrations/legacy/20190917-01-cleanup-app-user-role.js diff --git a/lib/model/migrations/20190923-01-add-project-viewer-role.js b/lib/model/migrations/legacy/20190923-01-add-project-viewer-role.js similarity index 100% rename from lib/model/migrations/20190923-01-add-project-viewer-role.js rename to lib/model/migrations/legacy/20190923-01-add-project-viewer-role.js diff --git a/lib/model/migrations/20190925-01-add-client-audits.js b/lib/model/migrations/legacy/20190925-01-add-client-audits.js similarity index 100% rename from lib/model/migrations/20190925-01-add-client-audits.js rename to lib/model/migrations/legacy/20190925-01-add-client-audits.js diff --git a/lib/model/migrations/20191007-01-backfill-client-audits.js b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js similarity index 100% rename from lib/model/migrations/20191007-01-backfill-client-audits.js rename to lib/model/migrations/legacy/20191007-01-backfill-client-audits.js diff --git a/lib/model/migrations/20191010-01-add-excel-blob-reference.js b/lib/model/migrations/legacy/20191010-01-add-excel-blob-reference.js similarity index 100% rename from lib/model/migrations/20191010-01-add-excel-blob-reference.js rename to lib/model/migrations/legacy/20191010-01-add-excel-blob-reference.js diff --git a/lib/model/migrations/20191023-01-add-worker-columns-to-audits.js b/lib/model/migrations/legacy/20191023-01-add-worker-columns-to-audits.js similarity index 100% rename from lib/model/migrations/20191023-01-add-worker-columns-to-audits.js rename to lib/model/migrations/legacy/20191023-01-add-worker-columns-to-audits.js diff --git a/lib/model/migrations/20191025-01-add-id-to-audits.js b/lib/model/migrations/legacy/20191025-01-add-id-to-audits.js similarity index 100% rename from lib/model/migrations/20191025-01-add-id-to-audits.js rename to lib/model/migrations/legacy/20191025-01-add-id-to-audits.js diff --git a/lib/model/migrations/20191106-01-remove-deleted-actor-assignments.js b/lib/model/migrations/legacy/20191106-01-remove-deleted-actor-assignments.js similarity index 100% rename from lib/model/migrations/20191106-01-remove-deleted-actor-assignments.js rename to lib/model/migrations/legacy/20191106-01-remove-deleted-actor-assignments.js diff --git a/lib/model/migrations/20191231-01-remove-transformations.js b/lib/model/migrations/legacy/20191231-01-remove-transformations.js similarity index 100% rename from lib/model/migrations/20191231-01-remove-transformations.js rename to lib/model/migrations/legacy/20191231-01-remove-transformations.js diff --git a/lib/model/migrations/20191231-02-add-schema-storage.js b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js similarity index 100% rename from lib/model/migrations/20191231-02-add-schema-storage.js rename to lib/model/migrations/legacy/20191231-02-add-schema-storage.js diff --git a/lib/model/migrations/20200110-01-add-drafts.js b/lib/model/migrations/legacy/20200110-01-add-drafts.js similarity index 100% rename from lib/model/migrations/20200110-01-add-drafts.js rename to lib/model/migrations/legacy/20200110-01-add-drafts.js diff --git a/lib/model/migrations/20200112-01-check-field-collisions.js b/lib/model/migrations/legacy/20200112-01-check-field-collisions.js similarity index 100% rename from lib/model/migrations/20200112-01-check-field-collisions.js rename to lib/model/migrations/legacy/20200112-01-check-field-collisions.js diff --git a/lib/model/migrations/20200114-01-remove-formid-sha256-constraint.js b/lib/model/migrations/legacy/20200114-01-remove-formid-sha256-constraint.js similarity index 100% rename from lib/model/migrations/20200114-01-remove-formid-sha256-constraint.js rename to lib/model/migrations/legacy/20200114-01-remove-formid-sha256-constraint.js diff --git a/lib/model/migrations/20200117-01-draft-test-submissions.js b/lib/model/migrations/legacy/20200117-01-draft-test-submissions.js similarity index 100% rename from lib/model/migrations/20200117-01-draft-test-submissions.js rename to lib/model/migrations/legacy/20200117-01-draft-test-submissions.js diff --git a/lib/model/migrations/20200121-01-add-draft-keys.js b/lib/model/migrations/legacy/20200121-01-add-draft-keys.js similarity index 100% rename from lib/model/migrations/20200121-01-add-draft-keys.js rename to lib/model/migrations/legacy/20200121-01-add-draft-keys.js diff --git a/lib/model/migrations/20200122-01-remove-draft-form-state.js b/lib/model/migrations/legacy/20200122-01-remove-draft-form-state.js similarity index 100% rename from lib/model/migrations/20200122-01-remove-draft-form-state.js rename to lib/model/migrations/legacy/20200122-01-remove-draft-form-state.js diff --git a/lib/model/migrations/20200129-01-cascade-submission-deletes.js b/lib/model/migrations/legacy/20200129-01-cascade-submission-deletes.js similarity index 100% rename from lib/model/migrations/20200129-01-cascade-submission-deletes.js rename to lib/model/migrations/legacy/20200129-01-cascade-submission-deletes.js diff --git a/lib/model/migrations/20200220-01-repair-submission-parsing.js b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js similarity index 100% rename from lib/model/migrations/20200220-01-repair-submission-parsing.js rename to lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js diff --git a/lib/model/migrations/20200403-01-add-performance-indices.js b/lib/model/migrations/legacy/20200403-01-add-performance-indices.js similarity index 100% rename from lib/model/migrations/20200403-01-add-performance-indices.js rename to lib/model/migrations/legacy/20200403-01-add-performance-indices.js diff --git a/lib/model/migrations/20200407-01-allow-actorless-submission-defs.js b/lib/model/migrations/legacy/20200407-01-allow-actorless-submission-defs.js similarity index 100% rename from lib/model/migrations/20200407-01-allow-actorless-submission-defs.js rename to lib/model/migrations/legacy/20200407-01-allow-actorless-submission-defs.js diff --git a/lib/model/migrations/20200423-01-fix-field-insert-performance.js b/lib/model/migrations/legacy/20200423-01-fix-field-insert-performance.js similarity index 100% rename from lib/model/migrations/20200423-01-fix-field-insert-performance.js rename to lib/model/migrations/legacy/20200423-01-fix-field-insert-performance.js diff --git a/lib/model/migrations/20200428-01-allow-string-downcast.js b/lib/model/migrations/legacy/20200428-01-allow-string-downcast.js similarity index 100% rename from lib/model/migrations/20200428-01-allow-string-downcast.js rename to lib/model/migrations/legacy/20200428-01-allow-string-downcast.js diff --git a/lib/model/migrations/20200519-01-add-enketo-id.js b/lib/model/migrations/legacy/20200519-01-add-enketo-id.js similarity index 100% rename from lib/model/migrations/20200519-01-add-enketo-id.js rename to lib/model/migrations/legacy/20200519-01-add-enketo-id.js diff --git a/lib/model/migrations/20200519-02-add-form-viewer-role.js b/lib/model/migrations/legacy/20200519-02-add-form-viewer-role.js similarity index 100% rename from lib/model/migrations/20200519-02-add-form-viewer-role.js rename to lib/model/migrations/legacy/20200519-02-add-form-viewer-role.js diff --git a/lib/model/migrations/20200520-01-backfill-enketo.js b/lib/model/migrations/legacy/20200520-01-backfill-enketo.js similarity index 100% rename from lib/model/migrations/20200520-01-backfill-enketo.js rename to lib/model/migrations/legacy/20200520-01-backfill-enketo.js diff --git a/lib/model/migrations/20200715-01-add-data-collector-role.js b/lib/model/migrations/legacy/20200715-01-add-data-collector-role.js similarity index 100% rename from lib/model/migrations/20200715-01-add-data-collector-role.js rename to lib/model/migrations/legacy/20200715-01-add-data-collector-role.js diff --git a/lib/model/migrations/20200721-01-add-public-links.js b/lib/model/migrations/legacy/20200721-01-add-public-links.js similarity index 100% rename from lib/model/migrations/20200721-01-add-public-links.js rename to lib/model/migrations/legacy/20200721-01-add-public-links.js diff --git a/lib/model/migrations/20200728-01-add-enketo-single-token-to-forms.js b/lib/model/migrations/legacy/20200728-01-add-enketo-single-token-to-forms.js similarity index 100% rename from lib/model/migrations/20200728-01-add-enketo-single-token-to-forms.js rename to lib/model/migrations/legacy/20200728-01-add-enketo-single-token-to-forms.js diff --git a/lib/model/migrations/20200731-01-allow-project-managers-to-end-sessions.js b/lib/model/migrations/legacy/20200731-01-allow-project-managers-to-end-sessions.js similarity index 100% rename from lib/model/migrations/20200731-01-allow-project-managers-to-end-sessions.js rename to lib/model/migrations/legacy/20200731-01-allow-project-managers-to-end-sessions.js diff --git a/lib/model/migrations/20200810-01-reschedule-enketo-processing.js b/lib/model/migrations/legacy/20200810-01-reschedule-enketo-processing.js similarity index 100% rename from lib/model/migrations/20200810-01-reschedule-enketo-processing.js rename to lib/model/migrations/legacy/20200810-01-reschedule-enketo-processing.js diff --git a/lib/model/migrations/20200918-01-repair-publishedat-dates.js b/lib/model/migrations/legacy/20200918-01-repair-publishedat-dates.js similarity index 100% rename from lib/model/migrations/20200918-01-repair-publishedat-dates.js rename to lib/model/migrations/legacy/20200918-01-repair-publishedat-dates.js diff --git a/lib/model/migrations/20200930-01-add-backup-run-verb.js b/lib/model/migrations/legacy/20200930-01-add-backup-run-verb.js similarity index 100% rename from lib/model/migrations/20200930-01-add-backup-run-verb.js rename to lib/model/migrations/legacy/20200930-01-add-backup-run-verb.js diff --git a/lib/model/migrations/20201117-01-remove-deleted-actor-assignments-again.js b/lib/model/migrations/legacy/20201117-01-remove-deleted-actor-assignments-again.js similarity index 100% rename from lib/model/migrations/20201117-01-remove-deleted-actor-assignments-again.js rename to lib/model/migrations/legacy/20201117-01-remove-deleted-actor-assignments-again.js diff --git a/lib/model/migrations/20201207-01-harmonize-submitter-id-columns.js b/lib/model/migrations/legacy/20201207-01-harmonize-submitter-id-columns.js similarity index 100% rename from lib/model/migrations/20201207-01-harmonize-submitter-id-columns.js rename to lib/model/migrations/legacy/20201207-01-harmonize-submitter-id-columns.js diff --git a/lib/model/migrations/20210118-01-add-current-flag-to-submission-defs.js b/lib/model/migrations/legacy/20210118-01-add-current-flag-to-submission-defs.js similarity index 100% rename from lib/model/migrations/20210118-01-add-current-flag-to-submission-defs.js rename to lib/model/migrations/legacy/20210118-01-add-current-flag-to-submission-defs.js diff --git a/lib/model/migrations/20210120-01-instance-names.js b/lib/model/migrations/legacy/20210120-01-instance-names.js similarity index 100% rename from lib/model/migrations/20210120-01-instance-names.js rename to lib/model/migrations/legacy/20210120-01-instance-names.js diff --git a/lib/model/migrations/20210203-01-add-hierarchy-to-actees.js b/lib/model/migrations/legacy/20210203-01-add-hierarchy-to-actees.js similarity index 100% rename from lib/model/migrations/20210203-01-add-hierarchy-to-actees.js rename to lib/model/migrations/legacy/20210203-01-add-hierarchy-to-actees.js diff --git a/lib/model/migrations/20210210-01-add-instanceid-to-submission-defs.js b/lib/model/migrations/legacy/20210210-01-add-instanceid-to-submission-defs.js similarity index 100% rename from lib/model/migrations/20210210-01-add-instanceid-to-submission-defs.js rename to lib/model/migrations/legacy/20210210-01-add-instanceid-to-submission-defs.js diff --git a/lib/model/migrations/20210218-01-add-submission-edit-verbs.js b/lib/model/migrations/legacy/20210218-01-add-submission-edit-verbs.js similarity index 100% rename from lib/model/migrations/20210218-01-add-submission-edit-verbs.js rename to lib/model/migrations/legacy/20210218-01-add-submission-edit-verbs.js diff --git a/lib/model/migrations/20210218-02-add-draft-to-submissions-unique.js b/lib/model/migrations/legacy/20210218-02-add-draft-to-submissions-unique.js similarity index 100% rename from lib/model/migrations/20210218-02-add-draft-to-submissions-unique.js rename to lib/model/migrations/legacy/20210218-02-add-draft-to-submissions-unique.js diff --git a/lib/model/migrations/20210219-01-add-review-state.js b/lib/model/migrations/legacy/20210219-01-add-review-state.js similarity index 100% rename from lib/model/migrations/20210219-01-add-review-state.js rename to lib/model/migrations/legacy/20210219-01-add-review-state.js diff --git a/lib/model/migrations/20210219-02-add-notes-and-index-to-audits.js b/lib/model/migrations/legacy/20210219-02-add-notes-and-index-to-audits.js similarity index 100% rename from lib/model/migrations/20210219-02-add-notes-and-index-to-audits.js rename to lib/model/migrations/legacy/20210219-02-add-notes-and-index-to-audits.js diff --git a/lib/model/migrations/20210324-01-add-submission-edit-verbs-to-managers.js b/lib/model/migrations/legacy/20210324-01-add-submission-edit-verbs-to-managers.js similarity index 100% rename from lib/model/migrations/20210324-01-add-submission-edit-verbs-to-managers.js rename to lib/model/migrations/legacy/20210324-01-add-submission-edit-verbs-to-managers.js diff --git a/lib/model/migrations/20210325-01-remove-project.list-verb.js b/lib/model/migrations/legacy/20210325-01-remove-project.list-verb.js similarity index 100% rename from lib/model/migrations/20210325-01-remove-project.list-verb.js rename to lib/model/migrations/legacy/20210325-01-remove-project.list-verb.js diff --git a/lib/model/migrations/20210408-01-drop-public-link-createdat.js b/lib/model/migrations/legacy/20210408-01-drop-public-link-createdat.js similarity index 100% rename from lib/model/migrations/20210408-01-drop-public-link-createdat.js rename to lib/model/migrations/legacy/20210408-01-drop-public-link-createdat.js diff --git a/lib/model/migrations/20210408-02-backfill-specialized-actor-audits.js b/lib/model/migrations/legacy/20210408-02-backfill-specialized-actor-audits.js similarity index 100% rename from lib/model/migrations/20210408-02-backfill-specialized-actor-audits.js rename to lib/model/migrations/legacy/20210408-02-backfill-specialized-actor-audits.js diff --git a/lib/model/migrations/20210409-01-add-comments.js b/lib/model/migrations/legacy/20210409-01-add-comments.js similarity index 100% rename from lib/model/migrations/20210409-01-add-comments.js rename to lib/model/migrations/legacy/20210409-01-add-comments.js diff --git a/lib/model/migrations/20210409-02-update-review-states.js b/lib/model/migrations/legacy/20210409-02-update-review-states.js similarity index 100% rename from lib/model/migrations/20210409-02-update-review-states.js rename to lib/model/migrations/legacy/20210409-02-update-review-states.js diff --git a/lib/model/migrations/20210423-01-add-name-to-form-def.js b/lib/model/migrations/legacy/20210423-01-add-name-to-form-def.js similarity index 100% rename from lib/model/migrations/20210423-01-add-name-to-form-def.js rename to lib/model/migrations/legacy/20210423-01-add-name-to-form-def.js diff --git a/lib/model/migrations/20210423-02-drop-form-name.js b/lib/model/migrations/legacy/20210423-02-drop-form-name.js similarity index 100% rename from lib/model/migrations/20210423-02-drop-form-name.js rename to lib/model/migrations/legacy/20210423-02-drop-form-name.js diff --git a/lib/model/migrations/20210716-01-config-value-jsonb.js b/lib/model/migrations/legacy/20210716-01-config-value-jsonb.js similarity index 100% rename from lib/model/migrations/20210716-01-config-value-jsonb.js rename to lib/model/migrations/legacy/20210716-01-config-value-jsonb.js diff --git a/lib/model/migrations/20210721-01-add-config-set-verb.js b/lib/model/migrations/legacy/20210721-01-add-config-set-verb.js similarity index 100% rename from lib/model/migrations/20210721-01-add-config-set-verb.js rename to lib/model/migrations/legacy/20210721-01-add-config-set-verb.js diff --git a/lib/model/migrations/20210817-01-disallow-structure-downcast-to-string.js b/lib/model/migrations/legacy/20210817-01-disallow-structure-downcast-to-string.js similarity index 100% rename from lib/model/migrations/20210817-01-disallow-structure-downcast-to-string.js rename to lib/model/migrations/legacy/20210817-01-disallow-structure-downcast-to-string.js diff --git a/lib/model/migrations/20210825-01-add-analytics-read-verb.js b/lib/model/migrations/legacy/20210825-01-add-analytics-read-verb.js similarity index 100% rename from lib/model/migrations/20210825-01-add-analytics-read-verb.js rename to lib/model/migrations/legacy/20210825-01-add-analytics-read-verb.js diff --git a/lib/model/migrations/20210903-01-backfill-encrypted-client-audits.js b/lib/model/migrations/legacy/20210903-01-backfill-encrypted-client-audits.js similarity index 100% rename from lib/model/migrations/20210903-01-backfill-encrypted-client-audits.js rename to lib/model/migrations/legacy/20210903-01-backfill-encrypted-client-audits.js diff --git a/lib/model/migrations/20210927-01-revert-disallow-structure-downcast.js b/lib/model/migrations/legacy/20210927-01-revert-disallow-structure-downcast.js similarity index 100% rename from lib/model/migrations/20210927-01-revert-disallow-structure-downcast.js rename to lib/model/migrations/legacy/20210927-01-revert-disallow-structure-downcast.js diff --git a/lib/model/migrations/20211008-01-track-select-many-options.js b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js similarity index 100% rename from lib/model/migrations/20211008-01-track-select-many-options.js rename to lib/model/migrations/legacy/20211008-01-track-select-many-options.js diff --git a/lib/model/migrations/20211021-remove-hashes-from-audits.js b/lib/model/migrations/legacy/20211021-remove-hashes-from-audits.js similarity index 100% rename from lib/model/migrations/20211021-remove-hashes-from-audits.js rename to lib/model/migrations/legacy/20211021-remove-hashes-from-audits.js diff --git a/lib/model/migrations/20211109-01-add-user-agent-to-submissions.js b/lib/model/migrations/legacy/20211109-01-add-user-agent-to-submissions.js similarity index 100% rename from lib/model/migrations/20211109-01-add-user-agent-to-submissions.js rename to lib/model/migrations/legacy/20211109-01-add-user-agent-to-submissions.js diff --git a/lib/model/migrations/20211114-01-flag-initial-submission-def.js b/lib/model/migrations/legacy/20211114-01-flag-initial-submission-def.js similarity index 100% rename from lib/model/migrations/20211114-01-flag-initial-submission-def.js rename to lib/model/migrations/legacy/20211114-01-flag-initial-submission-def.js diff --git a/lib/model/migrations/20211117-01-add-form-restore-verb.js b/lib/model/migrations/legacy/20211117-01-add-form-restore-verb.js similarity index 100% rename from lib/model/migrations/20211117-01-add-form-restore-verb.js rename to lib/model/migrations/legacy/20211117-01-add-form-restore-verb.js diff --git a/lib/model/migrations/20211129-01-add-purged-details-to-actees.js b/lib/model/migrations/legacy/20211129-01-add-purged-details-to-actees.js similarity index 100% rename from lib/model/migrations/20211129-01-add-purged-details-to-actees.js rename to lib/model/migrations/legacy/20211129-01-add-purged-details-to-actees.js diff --git a/lib/model/migrations/20220121-01-form-cascade-delete.js b/lib/model/migrations/legacy/20220121-01-form-cascade-delete.js similarity index 100% rename from lib/model/migrations/20220121-01-form-cascade-delete.js rename to lib/model/migrations/legacy/20220121-01-form-cascade-delete.js diff --git a/lib/model/migrations/20220121-02-purge-deleted-forms.js b/lib/model/migrations/legacy/20220121-02-purge-deleted-forms.js similarity index 100% rename from lib/model/migrations/20220121-02-purge-deleted-forms.js rename to lib/model/migrations/legacy/20220121-02-purge-deleted-forms.js diff --git a/lib/model/migrations/20220209-01-purge-unneeded-drafts.js b/lib/model/migrations/legacy/20220209-01-purge-unneeded-drafts.js similarity index 100% rename from lib/model/migrations/20220209-01-purge-unneeded-drafts.js rename to lib/model/migrations/legacy/20220209-01-purge-unneeded-drafts.js diff --git a/lib/model/migrations/20220309-01-add-project-description.js b/lib/model/migrations/legacy/20220309-01-add-project-description.js similarity index 100% rename from lib/model/migrations/20220309-01-add-project-description.js rename to lib/model/migrations/legacy/20220309-01-add-project-description.js diff --git a/lib/model/migrations/20220803-01-create-entities-schema.js b/lib/model/migrations/legacy/20220803-01-create-entities-schema.js similarity index 100% rename from lib/model/migrations/20220803-01-create-entities-schema.js rename to lib/model/migrations/legacy/20220803-01-create-entities-schema.js diff --git a/lib/model/migrations/20221003-01-add-dataset-verbs.js b/lib/model/migrations/legacy/20221003-01-add-dataset-verbs.js similarity index 100% rename from lib/model/migrations/20221003-01-add-dataset-verbs.js rename to lib/model/migrations/legacy/20221003-01-add-dataset-verbs.js diff --git a/lib/model/migrations/20221114-01-explict-dataset-publish.js b/lib/model/migrations/legacy/20221114-01-explict-dataset-publish.js similarity index 100% rename from lib/model/migrations/20221114-01-explict-dataset-publish.js rename to lib/model/migrations/legacy/20221114-01-explict-dataset-publish.js diff --git a/lib/model/migrations/20221117-01-check-datasetId-is-null-for-non-file-type.js b/lib/model/migrations/legacy/20221117-01-check-datasetId-is-null-for-non-file-type.js similarity index 100% rename from lib/model/migrations/20221117-01-check-datasetId-is-null-for-non-file-type.js rename to lib/model/migrations/legacy/20221117-01-check-datasetId-is-null-for-non-file-type.js diff --git a/lib/model/migrations/20221118-01-make-entities-columns-not-null.js b/lib/model/migrations/legacy/20221118-01-make-entities-columns-not-null.js similarity index 100% rename from lib/model/migrations/20221118-01-make-entities-columns-not-null.js rename to lib/model/migrations/legacy/20221118-01-make-entities-columns-not-null.js diff --git a/lib/model/migrations/20221208-01-reduce-tz-precision.js b/lib/model/migrations/legacy/20221208-01-reduce-tz-precision.js similarity index 100% rename from lib/model/migrations/20221208-01-reduce-tz-precision.js rename to lib/model/migrations/legacy/20221208-01-reduce-tz-precision.js diff --git a/lib/model/migrations/20230106-01-remove-revision-number.js b/lib/model/migrations/legacy/20230106-01-remove-revision-number.js similarity index 100% rename from lib/model/migrations/20230106-01-remove-revision-number.js rename to lib/model/migrations/legacy/20230106-01-remove-revision-number.js diff --git a/lib/model/migrations/20230109-01-add-form-schema.js b/lib/model/migrations/legacy/20230109-01-add-form-schema.js similarity index 100% rename from lib/model/migrations/20230109-01-add-form-schema.js rename to lib/model/migrations/legacy/20230109-01-add-form-schema.js diff --git a/lib/model/migrations/20230123-01-remove-google-backups.js b/lib/model/migrations/legacy/20230123-01-remove-google-backups.js similarity index 100% rename from lib/model/migrations/20230123-01-remove-google-backups.js rename to lib/model/migrations/legacy/20230123-01-remove-google-backups.js diff --git a/lib/model/migrations/20230126-01-add-entity-indices.js b/lib/model/migrations/legacy/20230126-01-add-entity-indices.js similarity index 100% rename from lib/model/migrations/20230126-01-add-entity-indices.js rename to lib/model/migrations/legacy/20230126-01-add-entity-indices.js diff --git a/lib/model/migrations/20230127-01-rename-entity-created-by.js b/lib/model/migrations/legacy/20230127-01-rename-entity-created-by.js similarity index 100% rename from lib/model/migrations/20230127-01-rename-entity-created-by.js rename to lib/model/migrations/legacy/20230127-01-rename-entity-created-by.js diff --git a/lib/model/migrations/20230324-01-edit-dataset-verbs.js b/lib/model/migrations/legacy/20230324-01-edit-dataset-verbs.js similarity index 100% rename from lib/model/migrations/20230324-01-edit-dataset-verbs.js rename to lib/model/migrations/legacy/20230324-01-edit-dataset-verbs.js diff --git a/lib/model/migrations/20230406-01-add-entity-def-fields.js b/lib/model/migrations/legacy/20230406-01-add-entity-def-fields.js similarity index 100% rename from lib/model/migrations/20230406-01-add-entity-def-fields.js rename to lib/model/migrations/legacy/20230406-01-add-entity-def-fields.js diff --git a/lib/model/migrations/20230406-02-move-entity-label-add-deletedAt.js b/lib/model/migrations/legacy/20230406-02-move-entity-label-add-deletedAt.js similarity index 100% rename from lib/model/migrations/20230406-02-move-entity-label-add-deletedAt.js rename to lib/model/migrations/legacy/20230406-02-move-entity-label-add-deletedAt.js diff --git a/lib/model/migrations/20230414-01-remove-user-mfa-secret.js b/lib/model/migrations/legacy/20230414-01-remove-user-mfa-secret.js similarity index 100% rename from lib/model/migrations/20230414-01-remove-user-mfa-secret.js rename to lib/model/migrations/legacy/20230414-01-remove-user-mfa-secret.js diff --git a/lib/model/migrations/20230419-01-optimize-indices-sub-defs.js b/lib/model/migrations/legacy/20230419-01-optimize-indices-sub-defs.js similarity index 100% rename from lib/model/migrations/20230419-01-optimize-indices-sub-defs.js rename to lib/model/migrations/legacy/20230419-01-optimize-indices-sub-defs.js diff --git a/lib/model/migrations/20230509-01-dataset-approval-flag.js b/lib/model/migrations/legacy/20230509-01-dataset-approval-flag.js similarity index 100% rename from lib/model/migrations/20230509-01-dataset-approval-flag.js rename to lib/model/migrations/legacy/20230509-01-dataset-approval-flag.js diff --git a/lib/model/migrations/20230512-01-add-entity-root.js b/lib/model/migrations/legacy/20230512-01-add-entity-root.js similarity index 100% rename from lib/model/migrations/20230512-01-add-entity-root.js rename to lib/model/migrations/legacy/20230512-01-add-entity-root.js diff --git a/lib/model/migrations/20230512-02-backfill-entity-id.js b/lib/model/migrations/legacy/20230512-02-backfill-entity-id.js similarity index 100% rename from lib/model/migrations/20230512-02-backfill-entity-id.js rename to lib/model/migrations/legacy/20230512-02-backfill-entity-id.js diff --git a/lib/model/migrations/20230512-03-add-entity-source.js b/lib/model/migrations/legacy/20230512-03-add-entity-source.js similarity index 100% rename from lib/model/migrations/20230512-03-add-entity-source.js rename to lib/model/migrations/legacy/20230512-03-add-entity-source.js diff --git a/lib/model/migrations/20230518-01-add-entity-index-to-audits.js b/lib/model/migrations/legacy/20230518-01-add-entity-index-to-audits.js similarity index 100% rename from lib/model/migrations/20230518-01-add-entity-index-to-audits.js rename to lib/model/migrations/legacy/20230518-01-add-entity-index-to-audits.js From 244d36cf9744fe66ca3cbdb496e0ee5f74e3c42a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:16:28 +0000 Subject: [PATCH 055/133] last migration --- .../20250204-01-disable-nullable-blob-content-types.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/model/{migrations-post-knex => migrations}/20250204-01-disable-nullable-blob-content-types.js (100%) diff --git a/lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js b/lib/model/migrations/20250204-01-disable-nullable-blob-content-types.js similarity index 100% rename from lib/model/migrations-post-knex/20250204-01-disable-nullable-blob-content-types.js rename to lib/model/migrations/20250204-01-disable-nullable-blob-content-types.js From dfa2048df08d404bda71ca28292e2d82c45a2b1f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:18:02 +0000 Subject: [PATCH 056/133] rename post-knex --- test/db-migrations/migrator.js | 6 +++--- test/db-migrations/utils.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index d943c9e43..fba935d81 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -15,10 +15,10 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); -const legacy = createMigrator('Legacy', './lib/model/migrations/legacy', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces -const postKnex = createMigrator('Post-knex', './lib/model/migrations', './test/db-migrations/.holding-pen/pg', legacy); // eslint-disable-line no-use-before-define, no-multi-spaces +const legacy = createMigrator('Legacy', './lib/model/migrations/legacy', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces +const modern = createMigrator('Post-knex', './lib/model/migrations', './test/db-migrations/.holding-pen/pg', legacy); // eslint-disable-line no-use-before-define, no-multi-spaces -module.exports = { legacy, postKnex }; +module.exports = { legacy, modern }; function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { fs.mkdirSync(holdingPen, { recursive: true }); diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index 4075620a4..91b1b0e74 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -34,9 +34,9 @@ function describeLegacyMigration(...args) { return _describeMigration(migrator.l describeLegacyMigration.only = (...args) => _describeMigration(migrator.legacy, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces describeLegacyMigration.skip = (...args) => _describeMigration(migrator.legacy, describe.skip, ...args); // eslint-disable-line no-multi-spaces -function describeMigration(...args) { return _describeMigration(migrator.postKnex, describe, ...args); } // eslint-disable-line no-multi-spaces -describeMigration.only = (...args) => _describeMigration(migrator.postKnex, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces -describeMigration.skip = (...args) => _describeMigration(migrator.postKnex, describe.skip, ...args); // eslint-disable-line no-multi-spaces +function describeMigration(...args) { return _describeMigration(migrator.modern, describe, ...args); } // eslint-disable-line no-multi-spaces +describeMigration.only = (...args) => _describeMigration(migrator.modern, describe.only, ...args); // eslint-disable-line no-only-tests/no-only-tests, no-multi-spaces +describeMigration.skip = (...args) => _describeMigration(migrator.modern, describe.skip, ...args); // eslint-disable-line no-multi-spaces async function assertIndexExists(tableName, expected) { if (arguments.length !== 2) throw new Error('Incorrect arg count.'); From 9215950002587670792123253875720116079e29 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:18:33 +0000 Subject: [PATCH 057/133] move eslintrc --- lib/model/migrations/{legacy => }/.eslintrc.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/model/migrations/{legacy => }/.eslintrc.json (100%) diff --git a/lib/model/migrations/legacy/.eslintrc.json b/lib/model/migrations/.eslintrc.json similarity index 100% rename from lib/model/migrations/legacy/.eslintrc.json rename to lib/model/migrations/.eslintrc.json From 7d70054f4468fba69f3d5fb9bed49a74981dbcc7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:19:37 +0000 Subject: [PATCH 058/133] remove dead file --- lib/model/migrations-post-knex/.eslintrc.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 lib/model/migrations-post-knex/.eslintrc.json diff --git a/lib/model/migrations-post-knex/.eslintrc.json b/lib/model/migrations-post-knex/.eslintrc.json deleted file mode 100644 index 93a99d9dd..000000000 --- a/lib/model/migrations-post-knex/.eslintrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../../../.eslintrc.json", - "rules": { - "no-restricted-modules": [ "error", { "patterns": [ "../*" ] } ] - } -} From 7f6a8b66971e87bc0715add0d931d0af55b83b01 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:21:52 +0000 Subject: [PATCH 059/133] fix requires --- .../migrations/legacy/20180727-02-add-md5-to-blobs.js | 2 +- .../legacy/20180727-03-add-form-attachments-table.js | 2 +- .../migrations/legacy/20190520-01-add-form-versioning.js | 2 +- .../legacy/20191007-01-backfill-client-audits.js | 6 +++--- .../migrations/legacy/20191231-02-add-schema-storage.js | 4 ++-- .../legacy/20200220-01-repair-submission-parsing.js | 2 +- lib/model/migrations/legacy/20210120-01-instance-names.js | 2 +- .../legacy/20211008-01-track-select-many-options.js | 8 ++++---- .../migrations/legacy/20230109-01-add-form-schema.js | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js index c66eb52bb..5fa121135 100644 --- a/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js +++ b/lib/model/migrations/legacy/20180727-02-add-md5-to-blobs.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. // -const { md5sum } = require('../../util/crypto'); // eslint-disable-line no-restricted-modules +const { md5sum } = require('../../../util/crypto'); // eslint-disable-line no-restricted-modules const up = (knex) => knex.schema.table('blobs', (blobs) => { blobs.string('md5', 32); }) diff --git a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js index 33ebf322d..c48ceb758 100644 --- a/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js +++ b/lib/model/migrations/legacy/20180727-03-add-form-attachments-table.js @@ -23,7 +23,7 @@ const up = (knex) => fa.index([ 'formId' ]); }).then(() => { - const { expectedFormAttachments } = require('../../data/schema'); // eslint-disable-line no-restricted-modules + const { expectedFormAttachments } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules const { uniq, pluck } = require('ramda'); // now add all expected attachments on extant forms. diff --git a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js index 9148d1ac6..623e966c9 100644 --- a/lib/model/migrations/legacy/20190520-01-add-form-versioning.js +++ b/lib/model/migrations/legacy/20190520-01-add-form-versioning.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { shasum, sha256sum } = require('../../util/crypto'); // eslint-disable-line no-restricted-modules +const { shasum, sha256sum } = require('../../../util/crypto'); // eslint-disable-line no-restricted-modules const assert = require('assert').strict; const check = (message, query) => diff --git a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js index bb3c8ceef..5f79a3821 100644 --- a/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js +++ b/lib/model/migrations/legacy/20191007-01-backfill-client-audits.js @@ -7,9 +7,9 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { parseClientAudits } = require('../../data/client-audits'); // eslint-disable-line no-restricted-modules -const { getFormFields } = require('../../data/schema'); // eslint-disable-line no-restricted-modules -const { traverseXml, findOne, root, node, text } = require('../../util/xml'); // eslint-disable-line no-restricted-modules +const { parseClientAudits } = require('../../../data/client-audits'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules +const { traverseXml, findOne, root, node, text } = require('../../../util/xml'); // eslint-disable-line no-restricted-modules const up = (db) => new Promise((resolve, reject) => { const work = []; diff --git a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js index f99a37c7a..aff5ca728 100644 --- a/lib/model/migrations/legacy/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/legacy/20191231-02-add-schema-storage.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields } = require('../../data/schema'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules const up = async (db) => { await db.schema.createTable('form_fields', (fields) => { @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../knex-migrator').knexConnect(config); // eslint-disable-line no-restricted-modules + const db2 = require('../../knex-migrator').knexConnect(config); // eslint-disable-line no-restricted-modules return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js index 279977ce3..d4020bc25 100644 --- a/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js +++ b/lib/model/migrations/legacy/20200220-01-repair-submission-parsing.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../frames'); // eslint-disable-line no-restricted-modules +const { Submission } = require('../../frames'); // eslint-disable-line no-restricted-modules const up = async (db) => { const work = []; diff --git a/lib/model/migrations/legacy/20210120-01-instance-names.js b/lib/model/migrations/legacy/20210120-01-instance-names.js index a16d515b4..6c6cde9d9 100644 --- a/lib/model/migrations/legacy/20210120-01-instance-names.js +++ b/lib/model/migrations/legacy/20210120-01-instance-names.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../frames'); // eslint-disable-line no-restricted-modules +const { Submission } = require('../../frames'); // eslint-disable-line no-restricted-modules const up = async (db) => { await db.schema.table('submission_defs', (sds) => { diff --git a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js index 62397fc8f..09f1efa92 100644 --- a/lib/model/migrations/legacy/20211008-01-track-select-many-options.js +++ b/lib/model/migrations/legacy/20211008-01-track-select-many-options.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const { map } = require('ramda'); -const { getFormFields } = require('../../data/schema'); // eslint-disable-line no-restricted-modules -const { getSelectMultipleResponses } = require('../../data/submission'); // eslint-disable-line no-restricted-modules -const { Form } = require('../frames'); // eslint-disable-line no-restricted-modules -const { construct } = require('../../util/util'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules +const { getSelectMultipleResponses } = require('../../../data/submission'); // eslint-disable-line no-restricted-modules +const { Form } = require('../../frames'); // eslint-disable-line no-restricted-modules +const { construct } = require('../../../util/util'); // eslint-disable-line no-restricted-modules const up = async (db) => { // add select many flag, options field to fields diff --git a/lib/model/migrations/legacy/20230109-01-add-form-schema.js b/lib/model/migrations/legacy/20230109-01-add-form-schema.js index 8b0446e2e..63c2cd903 100644 --- a/lib/model/migrations/legacy/20230109-01-add-form-schema.js +++ b/lib/model/migrations/legacy/20230109-01-add-form-schema.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields, compare } = require('../../data/schema'); // eslint-disable-line no-restricted-modules +const { getFormFields, compare } = require('../../../data/schema'); // eslint-disable-line no-restricted-modules /* Steps of this migration 1. remove check field collision trigger From 6bf53ad877061457abd167a80d823a44b0ad43a7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:23:35 +0000 Subject: [PATCH 060/133] name --- test/db-migrations/migrator.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index fba935d81..cf654fcff 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -15,8 +15,8 @@ const fs = require('node:fs'); const { execSync } = require('node:child_process'); -const legacy = createMigrator('Legacy', './lib/model/migrations/legacy', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces -const modern = createMigrator('Post-knex', './lib/model/migrations', './test/db-migrations/.holding-pen/pg', legacy); // eslint-disable-line no-use-before-define, no-multi-spaces +const legacy = createMigrator('Legacy', './lib/model/migrations/legacy', './test/db-migrations/.holding-pen/legacy'); // eslint-disable-line no-use-before-define, no-multi-spaces +const modern = createMigrator('Modern', './lib/model/migrations', './test/db-migrations/.holding-pen/pg', legacy); // eslint-disable-line no-use-before-define, no-multi-spaces module.exports = { legacy, modern }; From c7fa35e179100755f44f7e5610a94a80bce22968 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:27:43 +0000 Subject: [PATCH 061/133] wip --- test/db-migrations/20241008-01-add-user_preferences.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/db-migrations/20241008-01-add-user_preferences.spec.js b/test/db-migrations/20241008-01-add-user_preferences.spec.js index 74a70dd20..8a89e1eea 100644 --- a/test/db-migrations/20241008-01-add-user_preferences.spec.js +++ b/test/db-migrations/20241008-01-add-user_preferences.spec.js @@ -2,10 +2,10 @@ const { // eslint-disable-line object-curly-newline assertIndexExists, assertTableDoesNotExist, assertTableSchema, - describeLegacyMigration, + describeMigration, } = require('./utils'); // eslint-disable-line object-curly-newline -describeLegacyMigration('20241008-01-add-user_preferences', ({ runMigrationBeingTested }) => { +describeMigration('20241008-01-add-user_preferences', ({ runMigrationBeingTested }) => { before(async () => { await assertTableDoesNotExist('user_site_preferences'); await assertTableDoesNotExist('user_project_preferences'); From 4275829db6329d69dbfb20f1dcc0d4fda1847205 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:30:37 +0000 Subject: [PATCH 062/133] raw -> query --- .../20230802-01-delete-orphan-submissions.js | 2 +- ...30818-01-remove-schemaId-from-dsPropertyFields.js | 2 +- .../migrations/20230824-01-add-entity-version.js | 6 +++--- .../20230830-01-remove-entity-label-from-audits.js | 2 +- lib/model/migrations/20230907-01-opened-form-verb.js | 4 ++-- .../migrations/20231002-01-add-conflict-details.js | 12 ++++++------ .../20231013-01-change-entity-error-action.js | 4 ++-- .../20231208-01-dataset-form-def-actions.js | 8 ++++---- .../migrations/20240215-01-entity-delete-verb.js | 4 ++-- lib/model/migrations/20240215-02-dedupe-verbs.js | 2 +- .../20240312-01-add-dataset-create-verb.js | 4 ++-- .../20240322-01-add-entity-source-index-to-audits.js | 8 ++++---- .../migrations/20240515-01-entity-tz-precision.js | 4 ++-- ...240607-01-add-offline-entity-branch-trunk-info.js | 4 ++-- .../migrations/20240607-02-add-submission-backlog.js | 4 ++-- .../20240715-01-backlog-add-event-entityuuid.js | 4 ++-- lib/model/migrations/20240913-01-add-blob-s3.js | 4 ++-- .../20240914-01-add-submission-delete-verb.js | 4 ++-- .../20240914-02-remove-orphaned-client-audits.js | 2 +- .../migrations/20241001-01-index-on-session-table.js | 4 ++-- .../migrations/20241008-01-add-user_preferences.js | 4 ++-- .../20241010-01-schedule-entity-form-upgrade.js | 2 +- ...9-01-schedule-entity-form-upgrade-create-forms.js | 2 +- .../20241030-01-add-force-entity-def-source.js | 4 ++-- .../migrations/20241224-01-entity-restore-verb.js | 4 ++-- .../migrations/20241224-02-cascade-entity-purge.js | 4 ++-- .../20241226-01-indices-for-purging-entities.js | 4 ++-- .../20241227-01-backfill-audit-entity-uuid.js | 2 +- 28 files changed, 57 insertions(+), 57 deletions(-) diff --git a/lib/model/migrations/20230802-01-delete-orphan-submissions.js b/lib/model/migrations/20230802-01-delete-orphan-submissions.js index 39cb1c8e3..9986e0969 100644 --- a/lib/model/migrations/20230802-01-delete-orphan-submissions.js +++ b/lib/model/migrations/20230802-01-delete-orphan-submissions.js @@ -9,7 +9,7 @@ // Delete draft Submissions that don't have any definition - cb#911 const up = async (db) => { - await db.raw(` + await db.query(` DELETE FROM submissions s WHERE draft AND id IN ( SELECT s.id FROM submissions s diff --git a/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js b/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js index 9ec11e119..506c8f924 100644 --- a/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js +++ b/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE ds_property_fields DROP COLUMN "schemaId"'); + await db.query('ALTER TABLE ds_property_fields DROP COLUMN "schemaId"'); }; const down = () => {}; diff --git a/lib/model/migrations/20230824-01-add-entity-version.js b/lib/model/migrations/20230824-01-add-entity-version.js index f5ddc8650..4f8437a4a 100644 --- a/lib/model/migrations/20230824-01-add-entity-version.js +++ b/lib/model/migrations/20230824-01-add-entity-version.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE entity_defs ADD COLUMN version INT4 NOT NULL DEFAULT 1'); + await db.query('ALTER TABLE entity_defs ADD COLUMN version INT4 NOT NULL DEFAULT 1'); // Sets the correct version number for existing entities - await db.raw(` + await db.query(` UPDATE entity_defs SET "version" = vt.rownumber FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY "entityId" ORDER BY id ) rownumber, id FROM entity_defs @@ -20,6 +20,6 @@ const up = async (db) => { `); }; -const down = (db) => db.raw('ALTER TABLE entity_defs DROP COLUMN version'); +const down = (db) => db.query('ALTER TABLE entity_defs DROP COLUMN version'); module.exports = { up, down }; diff --git a/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js b/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js index 0360602e3..5ab55b8cd 100644 --- a/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js +++ b/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` update audits set details=(details #- '{entity,label}') where action='entity.create'`); diff --git a/lib/model/migrations/20230907-01-opened-form-verb.js b/lib/model/migrations/20230907-01-opened-form-verb.js index be295a859..a86371e5e 100644 --- a/lib/model/migrations/20230907-01-opened-form-verb.js +++ b/lib/model/migrations/20230907-01-opened-form-verb.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = REPLACE(verbs ::TEXT, 'form', 'open_form')::JSONB WHERE system IN ('app-user', 'formview', 'formfill', 'pub-link')`); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = REPLACE(verbs ::TEXT, 'open_form', 'form')::JSONB WHERE system IN ('app-user', 'formview', 'formfill', 'pub-link')`); diff --git a/lib/model/migrations/20231002-01-add-conflict-details.js b/lib/model/migrations/20231002-01-add-conflict-details.js index 3c232d391..88004dab2 100644 --- a/lib/model/migrations/20231002-01-add-conflict-details.js +++ b/lib/model/migrations/20231002-01-add-conflict-details.js @@ -8,11 +8,11 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`CREATE TYPE "conflictType" AS ENUM ('soft', 'hard')`); + await db.query(`CREATE TYPE "conflictType" AS ENUM ('soft', 'hard')`); - await db.raw('ALTER TABLE entities ADD COLUMN conflict "conflictType" NULL'); + await db.query('ALTER TABLE entities ADD COLUMN conflict "conflictType" NULL'); - await db.raw(`ALTER TABLE entity_defs + await db.query(`ALTER TABLE entity_defs ADD COLUMN "dataReceived" JSONB NOT NULL DEFAULT '{}'::jsonb, -- null means, it's a first version @@ -25,13 +25,13 @@ const up = async (db) => { `); // Sets the value for "dataReceived" and "baseVersion" for existing row - await db.raw(`UPDATE entity_defs SET "dataReceived" = data || jsonb_build_object('label', "label"), "baseVersion" = CASE WHEN version > 1 THEN version - 1 ELSE NULL END`); + await db.query(`UPDATE entity_defs SET "dataReceived" = data || jsonb_build_object('label', "label"), "baseVersion" = CASE WHEN version > 1 THEN version - 1 ELSE NULL END`); }; const down = async (db) => { - await db.raw('ALTER TABLE entities DROP COLUMN conflict'); - await db.raw('ALTER TABLE entity_defs DROP COLUMN "dataReceived", DROP COLUMN "baseVersion"'); + await db.query('ALTER TABLE entities DROP COLUMN conflict'); + await db.query('ALTER TABLE entity_defs DROP COLUMN "dataReceived", DROP COLUMN "baseVersion"'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20231013-01-change-entity-error-action.js b/lib/model/migrations/20231013-01-change-entity-error-action.js index e52fbd6e8..fb4b198d3 100644 --- a/lib/model/migrations/20231013-01-change-entity-error-action.js +++ b/lib/model/migrations/20231013-01-change-entity-error-action.js @@ -8,12 +8,12 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('UPDATE audits SET "action" = \'entity.error\' WHERE "action" = \'entity.create.error\''); + await db.query('UPDATE audits SET "action" = \'entity.error\' WHERE "action" = \'entity.create.error\''); }; const down = async (db) => { // will set any error back to create error, which isn't necessarily right - await db.raw('UPDATE audits SET "action" = \'entity.create.error\' WHERE "action" = \'entity.error\''); + await db.query('UPDATE audits SET "action" = \'entity.create.error\' WHERE "action" = \'entity.error\''); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20231208-01-dataset-form-def-actions.js b/lib/model/migrations/20231208-01-dataset-form-def-actions.js index c6a3cf7bf..411efbccb 100644 --- a/lib/model/migrations/20231208-01-dataset-form-def-actions.js +++ b/lib/model/migrations/20231208-01-dataset-form-def-actions.js @@ -8,12 +8,12 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE dataset_form_defs ADD COLUMN actions jsonb'); - await db.raw(`UPDATE dataset_form_defs SET actions = '["create"]'`); - await db.raw('ALTER TABLE dataset_form_defs ALTER COLUMN actions SET NOT NULL'); + await db.query('ALTER TABLE dataset_form_defs ADD COLUMN actions jsonb'); + await db.query(`UPDATE dataset_form_defs SET actions = '["create"]'`); + await db.query('ALTER TABLE dataset_form_defs ALTER COLUMN actions SET NOT NULL'); }; const down = (db) => - db.raw('ALTER TABLE dataset_form_defs DROP COLUMN actions'); + db.query('ALTER TABLE dataset_form_defs DROP COLUMN actions'); module.exports = { up, down }; diff --git a/lib/model/migrations/20240215-01-entity-delete-verb.js b/lib/model/migrations/20240215-01-entity-delete-verb.js index da83905a9..c66cc8c84 100644 --- a/lib/model/migrations/20240215-01-entity-delete-verb.js +++ b/lib/model/migrations/20240215-01-entity-delete-verb.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["entity.delete"]'::jsonb WHERE system IN ('admin', 'manager')`); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = verbs - 'entity.delete' WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/20240215-02-dedupe-verbs.js b/lib/model/migrations/20240215-02-dedupe-verbs.js index cf81984ca..3287227a2 100644 --- a/lib/model/migrations/20240215-02-dedupe-verbs.js +++ b/lib/model/migrations/20240215-02-dedupe-verbs.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = (verbs - 'submission.update') || '["submission.update"]'::jsonb WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/20240312-01-add-dataset-create-verb.js b/lib/model/migrations/20240312-01-add-dataset-create-verb.js index 58d6e76c6..c02e770ed 100644 --- a/lib/model/migrations/20240312-01-add-dataset-create-verb.js +++ b/lib/model/migrations/20240312-01-add-dataset-create-verb.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["dataset.create"]'::jsonb WHERE system in ('admin', 'manager') `); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = (verbs - 'dataset.create') WHERE system in ('admin', 'manager') diff --git a/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js b/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js index a68d78c38..590411861 100644 --- a/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js +++ b/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw("CREATE INDEX audits_details_entity_def_index ON audits USING HASH (((details ->> 'entityDefId')::INTEGER))"); - await db.raw("CREATE INDEX audits_details_entity_source_index ON audits USING HASH (((details ->> 'sourceId')::INTEGER))"); + await db.query("CREATE INDEX audits_details_entity_def_index ON audits USING HASH (((details ->> 'entityDefId')::INTEGER))"); + await db.query("CREATE INDEX audits_details_entity_source_index ON audits USING HASH (((details ->> 'sourceId')::INTEGER))"); }; const down = async (db) => { - await db.raw('DROP INDEX audits_details_entity_def_index'); - await db.raw('DROP INDEX audits_details_entity_source_index'); + await db.query('DROP INDEX audits_details_entity_def_index'); + await db.query('DROP INDEX audits_details_entity_source_index'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20240515-01-entity-tz-precision.js b/lib/model/migrations/20240515-01-entity-tz-precision.js index 3b76190e8..1db2bdc63 100644 --- a/lib/model/migrations/20240515-01-entity-tz-precision.js +++ b/lib/model/migrations/20240515-01-entity-tz-precision.js @@ -8,11 +8,11 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamptz(3)'); + await db.query('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamptz(3)'); }; const down = async (db) => { - await db.raw('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamp'); + await db.query('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamp'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js b/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js index a0fe0acbd..873614b09 100644 --- a/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js +++ b/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`ALTER TABLE entity_defs + await db.query(`ALTER TABLE entity_defs ADD COLUMN "branchId" UUID, ADD COLUMN "trunkVersion" INT4, ADD COLUMN "branchBaseVersion" INT4`); }; -const down = (db) => db.raw(`ALTER TABLE entity_defs +const down = (db) => db.query(`ALTER TABLE entity_defs DROP COLUMN "branchId", DROP COLUMN "trunkVersion", DROP COLUMN "branchBaseVersion" diff --git a/lib/model/migrations/20240607-02-add-submission-backlog.js b/lib/model/migrations/20240607-02-add-submission-backlog.js index 0cda52ed5..5c712ebf1 100644 --- a/lib/model/migrations/20240607-02-add-submission-backlog.js +++ b/lib/model/migrations/20240607-02-add-submission-backlog.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`CREATE TABLE entity_submission_backlog ( + await db.query(`CREATE TABLE entity_submission_backlog ( "submissionId" INT4 NOT NULL, "submissionDefId" INT4 NOT NULL, "branchId" UUID NOT NULL, @@ -26,6 +26,6 @@ const up = async (db) => { )`); }; -const down = (db) => db.raw('DROP TABLE entity_submission_backlog'); +const down = (db) => db.query('DROP TABLE entity_submission_backlog'); module.exports = { up, down }; diff --git a/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js b/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js index 2915d90e8..284d6a3aa 100644 --- a/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js +++ b/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`ALTER TABLE entity_submission_backlog + await db.query(`ALTER TABLE entity_submission_backlog ADD COLUMN "auditId" INT4 NOT NULL, ADD COLUMN "entityUuid" UUID NOT NULL, ADD CONSTRAINT fk_audit_id @@ -17,7 +17,7 @@ const up = async (db) => { ON DELETE CASCADE`); }; -const down = (db) => db.raw(`ALTER TABLE entity_submission_backlog +const down = (db) => db.query(`ALTER TABLE entity_submission_backlog DROP COLUMN "auditId", DROP COLUMN "entityUuid" `); diff --git a/lib/model/migrations/20240913-01-add-blob-s3.js b/lib/model/migrations/20240913-01-add-blob-s3.js index 048f31b4a..a34590bf7 100644 --- a/lib/model/migrations/20240913-01-add-blob-s3.js +++ b/lib/model/migrations/20240913-01-add-blob-s3.js @@ -8,8 +8,8 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`CREATE TYPE S3_UPLOAD_STATUS AS ENUM ('pending', 'uploaded', 'failed')`); - await db.raw(` + await db.query(`CREATE TYPE S3_UPLOAD_STATUS AS ENUM ('pending', 'uploaded', 'failed')`); + await db.query(` ALTER TABLE blobs ADD COLUMN s3_status S3_UPLOAD_STATUS NOT NULL DEFAULT 'pending', ALTER COLUMN content DROP NOT NULL diff --git a/lib/model/migrations/20240914-01-add-submission-delete-verb.js b/lib/model/migrations/20240914-01-add-submission-delete-verb.js index d9bf1f7bd..7b308162c 100644 --- a/lib/model/migrations/20240914-01-add-submission-delete-verb.js +++ b/lib/model/migrations/20240914-01-add-submission-delete-verb.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["submission.delete", "submission.restore"]'::jsonb WHERE system in ('admin', 'manager') `); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = (verbs - 'submission.delete' - 'submission.restore') WHERE system in ('admin', 'manager') diff --git a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js index 9dd633a71..ee603c1f2 100644 --- a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js +++ b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js @@ -12,7 +12,7 @@ // This migration deletes those client audit rows, allowing the blobs to finally // be de-referenced and also eventually purged (by the puring cron job). -const up = (db) => db.raw(` +const up = (db) => db.query(` DELETE FROM client_audits WHERE "blobId" NOT IN ( SELECT "blobId" FROM submission_attachments diff --git a/lib/model/migrations/20241001-01-index-on-session-table.js b/lib/model/migrations/20241001-01-index-on-session-table.js index d1b8f00a4..6aa507330 100644 --- a/lib/model/migrations/20241001-01-index-on-session-table.js +++ b/lib/model/migrations/20241001-01-index-on-session-table.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` CREATE UNIQUE INDEX "sessions_token_index" ON sessions (token); `); -const down = (db) => db.raw(` +const down = (db) => db.query(` DROP INDEX "sessions_token_index"; `); diff --git a/lib/model/migrations/20241008-01-add-user_preferences.js b/lib/model/migrations/20241008-01-add-user_preferences.js index 94862cfba..3b7564883 100644 --- a/lib/model/migrations/20241008-01-add-user_preferences.js +++ b/lib/model/migrations/20241008-01-add-user_preferences.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` CREATE TABLE user_site_preferences ( "userId" integer NOT NULL REFERENCES users ("actorId"), "propertyName" text NOT NULL CHECK (length("propertyName") > 0), @@ -29,7 +29,7 @@ const up = (db) => db.raw(` CREATE INDEX ON "user_project_preferences" ("userId"); `); -const down = (db) => db.raw(` +const down = (db) => db.query(` DROP TABLE user_site_preferences; DROP TABLE user_project_preferences; `); diff --git a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js index 1aa35ac5f..1538cfd54 100644 --- a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js +++ b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` INSERT INTO audits ("action", "acteeId", "loggedAt", "details") SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' diff --git a/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js b/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js index 793898943..34b004ad7 100644 --- a/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js +++ b/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js @@ -15,7 +15,7 @@ // Basically, every existing form should be flagged, but I didn't want // to change an old migration. -const up = (db) => db.raw(` +const up = (db) => db.query(` INSERT INTO audits ("action", "acteeId", "loggedAt", "details") SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' diff --git a/lib/model/migrations/20241030-01-add-force-entity-def-source.js b/lib/model/migrations/20241030-01-add-force-entity-def-source.js index 1c54134c5..4b77c05d5 100644 --- a/lib/model/migrations/20241030-01-add-force-entity-def-source.js +++ b/lib/model/migrations/20241030-01-add-force-entity-def-source.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` ALTER TABLE entity_def_sources ADD COLUMN "forceProcessed" BOOLEAN `); -const down = (db) => db.raw(` +const down = (db) => db.query(` ALTER TABLE entity_def_sources DROP COLUMN "forceProcessed" `); diff --git a/lib/model/migrations/20241224-01-entity-restore-verb.js b/lib/model/migrations/20241224-01-entity-restore-verb.js index 5d948899c..7d73d48e0 100644 --- a/lib/model/migrations/20241224-01-entity-restore-verb.js +++ b/lib/model/migrations/20241224-01-entity-restore-verb.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["entity.restore"]'::jsonb WHERE system IN ('admin', 'manager')`); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = verbs - 'entity.restore' WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/20241224-02-cascade-entity-purge.js b/lib/model/migrations/20241224-02-cascade-entity-purge.js index 7d39083c2..4a359995b 100644 --- a/lib/model/migrations/20241224-02-cascade-entity-purge.js +++ b/lib/model/migrations/20241224-02-cascade-entity-purge.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` ALTER TABLE public.entity_defs DROP CONSTRAINT entity_defs_entityid_foreign; ALTER TABLE public.entity_defs ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id) ON DELETE CASCADE; `); -const down = ((db) => db.raw(` +const down = ((db) => db.query(` ALTER TABLE public.entity_defs DROP CONSTRAINT entity_defs_entityid_foreign; ALTER TABLE public.entity_defs ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id); `)); diff --git a/lib/model/migrations/20241226-01-indices-for-purging-entities.js b/lib/model/migrations/20241226-01-indices-for-purging-entities.js index 6ca38cc66..47ba7e551 100644 --- a/lib/model/migrations/20241226-01-indices-for-purging-entities.js +++ b/lib/model/migrations/20241226-01-indices-for-purging-entities.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` CREATE INDEX audits_details_entity_uuid ON public.audits USING hash ((details->'entity'->>'uuid')) WHERE ACTION IN ('entity.create', 'entity.update', 'entity.update.version', 'entity.update.resolve', 'entity.delete', 'entity.restore'); @@ -15,7 +15,7 @@ CREATE INDEX audits_details_entityUuids ON audits USING gin ((details -> 'entity WHERE ACTION = 'entity.purge'; `); -const down = ((db) => db.raw(` +const down = ((db) => db.query(` DROP INDEX audits_details_entity_uuid; DROP INDEX audits_details_entityUuids; `)); diff --git a/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js b/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js index 47ff576a5..6cfe7366f 100644 --- a/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js +++ b/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE audits SET details = ('{ "entity":{ "uuid":"' || (details->>'uuid') || '"}}')::JSONB WHERE action = 'entity.delete' AND details \\? 'uuid'; `); From 929a976a3a2f97e926f270eb0a8270f2a3773e91 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:36:23 +0000 Subject: [PATCH 063/133] fix? --- lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js b/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js index 6cfe7366f..0e4d8cbce 100644 --- a/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js +++ b/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js @@ -9,7 +9,7 @@ const up = (db) => db.query(` UPDATE audits SET details = ('{ "entity":{ "uuid":"' || (details->>'uuid') || '"}}')::JSONB -WHERE action = 'entity.delete' AND details \\? 'uuid'; +WHERE action = 'entity.delete' AND details ? 'uuid'; `); const down = () => {}; From d1802de923edbd44af8596b36c4402b28679cd3a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:38:09 +0000 Subject: [PATCH 064/133] remove old TODOs --- lib/model/knex-migrator.js | 2 -- test/integration/other/knex-migrations.js | 1 - 2 files changed, 3 deletions(-) diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 118ec8c86..9bec11942 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -10,8 +10,6 @@ // This is a variety of functions helpful for connecting to and performing // top-level operations with a database, like migrations. -// TODO move migration files to e.g. /migrations/legacy - const knex = require('knex'); const { knexConnection } = require('../util/db'); diff --git a/test/integration/other/knex-migrations.js b/test/integration/other/knex-migrations.js index 56e23c064..f1272bb46 100644 --- a/test/integration/other/knex-migrations.js +++ b/test/integration/other/knex-migrations.js @@ -1,4 +1,3 @@ -// TODO rename e.g. legacy-knex-migrations const { readFileSync } = require('fs'); const appRoot = require('app-root-path'); const uuid = require('uuid').v4; From 193f8375fb87ca4952053fbf49204600c16ecff9 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:51:03 +0000 Subject: [PATCH 065/133] rename migrations tests --- test/integration/other/knex-migrations.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/integration/other/knex-migrations.js b/test/integration/other/knex-migrations.js index f1272bb46..f652a0c0a 100644 --- a/test/integration/other/knex-migrations.js +++ b/test/integration/other/knex-migrations.js @@ -15,7 +15,7 @@ const populateForms = require('../fixtures/02-forms'); const { getFormFields } = require('../../../lib/data/schema'); const withTestDatabase = withKnex(config.get('test.database')); -const migrationsDir = appRoot + '/lib/model/migrations'; +const migrationsDir = appRoot + '/lib/model/migrations/legacy'; const upToMigration = (toName, inclusive = true) => withTestDatabase(async (migrator) => { await migrator.raw('drop owned by current_user'); const migrations = await migrator.migrate.list({ directory: migrationsDir }); @@ -41,7 +41,7 @@ const testMigration = (filename, tests, options = {}) => { // eslint-disable-next-line no-only-tests/no-only-tests ? describe.only.bind(describe) : (skip ? describe.skip.bind(describe) : describe); - f(`database migrations: ${filename}`, function() { + f(`knex migrations: ${filename}`, function() { this.timeout(20000); beforeEach(() => upToMigration(filename, false)); @@ -59,7 +59,7 @@ testMigration.skip = (filename, tests) => // column to projects and forms, it is not possible to migrate part way // (before the new column) and populate the data when frames expect the // new column to exist. -describe.skip('database migrations', function() { +describe.skip('knex migrations', function() { this.timeout(8000); it('should purge deleted forms via migration', testServiceFullTrx(async (service, container) => { @@ -218,7 +218,7 @@ describe.skip('database migrations', function() { }); -describe('database migrations: removing default project', function() { +describe('knex migrations: removing default project', function() { this.timeout(8000); it('should put old forms into project', testServiceFullTrx(async (service, container) => { @@ -255,7 +255,7 @@ describe('database migrations: removing default project', function() { })); }); -describe('database migrations: intermediate form schema', function() { +describe('knex migrations: intermediate form schema', function() { this.timeout(20000); it('should test migration', testServiceFullTrx(async (service, container) => { @@ -384,7 +384,7 @@ describe('database migrations: intermediate form schema', function() { })); }); -describe('database migrations: 20230123-01-remove-google-backups', function() { +describe('knex migrations: 20230123-01-remove-google-backups', function() { this.timeout(20000); beforeEach(() => upToMigration('20230123-01-remove-google-backups.js', false)); @@ -478,7 +478,7 @@ describe('database migrations: 20230123-01-remove-google-backups', function() { })); }); -describe.skip('database migrations: 20230324-01-edit-dataset-verbs.js', function () { +describe.skip('knex migrations: 20230324-01-edit-dataset-verbs.js', function () { this.timeout(20000); it('should add dataset/entity read verbs with raw sql', testServiceFullTrx(async (service, container) => { @@ -514,7 +514,7 @@ describe.skip('database migrations: 20230324-01-edit-dataset-verbs.js', function })); }); -describe.skip('database migrations from 20230406: altering entities and entity_defs', function () { +describe.skip('knex migrations from 20230406: altering entities and entity_defs', function () { this.timeout(20000); const createEntity = async (service, container) => { @@ -608,7 +608,7 @@ describe.skip('database migrations from 20230406: altering entities and entity_d })); }); -describe('database migrations from 20230512: adding entity_def_sources table', function () { +describe('knex migrations from 20230512: adding entity_def_sources table', function () { this.timeout(20000); it('should backfill entityId and entityDefId in audit log', testServiceFullTrx(async (service, container) => { From 0c9610bfe8b723e5a24f13bf13ddbd7f20367e67 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 10:58:52 +0000 Subject: [PATCH 066/133] skip migration tests --- test/integration/other/knex-migrations.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/integration/other/knex-migrations.js b/test/integration/other/knex-migrations.js index f652a0c0a..e475f95d1 100644 --- a/test/integration/other/knex-migrations.js +++ b/test/integration/other/knex-migrations.js @@ -39,7 +39,7 @@ const testMigration = (filename, tests, options = {}) => { const { only = false, skip = false } = options; const f = only // eslint-disable-next-line no-only-tests/no-only-tests - ? describe.only.bind(describe) + ? describe.bind(describe) : (skip ? describe.skip.bind(describe) : describe); f(`knex migrations: ${filename}`, function() { this.timeout(20000); @@ -922,7 +922,8 @@ describe.skip('database migration: 20231002-01-add-conflict-details.js', functio })); }); -testMigration('20240215-01-entity-delete-verb.js', () => { +// Skip because 1. this migration now runs on new migrator, and (2) it relies on application code. +testMigration.skip('20240215-01-entity-delete-verb.js', () => { it('should add entity.delete verb to correct roles', testServiceFullTrx(async (service) => { const verbsByRole = async () => { const { body: roles } = await service.get('/v1/roles').expect(200); @@ -951,7 +952,8 @@ testMigration('20240215-01-entity-delete-verb.js', () => { })); }); -testMigration('20240215-02-dedupe-verbs.js', () => { +// Skip because 1. this migration now runs on new migrator, and (2) it relies on application code. +testMigration.skip('20240215-02-dedupe-verbs.js', () => { it('should remove duplicate submission.update verb', testServiceFullTrx(async (service) => { const verbsByRole = async () => { const { body: roles } = await service.get('/v1/roles').expect(200); @@ -984,7 +986,8 @@ testMigration('20240215-02-dedupe-verbs.js', () => { })); }); -testMigration('20240914-02-remove-orphaned-client-audits.js', () => { +// Skip because 1. this migration now runs on new migrator, and (2) it relies on application code. +testMigration.skip('20240914-02-remove-orphaned-client-audits.js', () => { it('should remove orphaned client audits', testServiceFullTrx(async (service, container) => { await populateUsers(container); await populateForms(container); @@ -1238,7 +1241,8 @@ testMigration('20240914-02-remove-orphaned-client-audits.js', () => { }); }); -testMigration('20241227-01-backfill-audit-entity-uuid.js', () => { +// Skip because 1. this migration now runs on new migrator, and (2) it relies on application code. +testMigration.skip('20241227-01-backfill-audit-entity-uuid.js', () => { it('should update the format of detail for entity.delete audits', testServiceFullTrx(async (service, container) => { await populateUsers(container); await populateForms(container); From de23f43946a463387d51869b3b2fd894aece6c0c Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 11:12:09 +0000 Subject: [PATCH 067/133] resolve REVIEW comment --- lib/bin/run-migrations.js | 8 +- lib/model/pg-migrator.js | 211 +++++++++++++++++++------------------- 2 files changed, 108 insertions(+), 111 deletions(-) diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index e59f6f983..e9e2f5ced 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { withKnex, migrate } = require('../model/knex-migrator'); -const { pgMigrations } = require('../model/pg-migrator'); +const { withKnex, migrate: knexMigrate } = require('../model/knex-migrator'); +const { withPg, migrate: pgMigrate } = require('../model/pg-migrator'); (async () => { try { - await withKnex(require('config').get('default.database'))(migrate); - await pgMigrations(require('config').get('default.database')); + await withKnex(require('config').get('default.database'))(knexMigrate); + await withPg(require('config').get('default.database'))(pgMigrate); // REVIEW should the new migrator follow the same function signature? e.g. // withPg(config)(migrate)? } catch (err) { diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 44340d974..3082d16b9 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -61,122 +61,119 @@ const getMigrationsToRun = async client => { return toRun; }; -const pgMigrations = async (config) => { +// In the main, this migrator is written to behave similarly to knex's: +// +// * uses existing knex_migrations and knex_migrations_lock tables +// * expects transaction property async .up({ raw }) +// * provides implementation of db.raw() +// * runs all new migrations in the same transaction +// +// Notable differences +// +// * ONLY provides db.raw()-equivalent function to transactions - no knex query builder etc. +// * ONLY implements up(); will throw if a transaction has other properties, except for `down()` +// which is currently ignored TODO implement this if it's useful to devs +// * gets list of migrations to run _after_ acquiring db lock (knex checks before acquiring lock, +// and then has to re-check afterwards) +// * sets migration_time to be the start of the migration batch's transaction rather than some +// other intermediate time +// * instead of attempting to acquire a lock on the single row in the knex_migrations_lock table, +// this code takes the simpler approach of locking the whole table. This table could be +// discarded completely by instead locking the knex_migrations table, but backwards- +// compatibility is essential to prevent concurrent running of knex-based and pg-based +// migrators. +// * does not check that all migrations listed in the database table actually exist in the +// filesystem +const migrate = async (client) => { const log = (...args) => console.log('[pgMigrations]', ...args); // eslint-disable-line no-console - log('ENTRY'); - - // In the main, this migrator is written to behave similarly to knex's: - // - // * uses existing knex_migrations and knex_migrations_lock tables - // * expects transaction property async .up({ raw }) - // * provides implementation of db.raw() - // * runs all new migrations in the same transaction - // - // Notable differences - // - // * ONLY provides db.raw()-equivalent function to transactions - no knex query builder etc. - // * ONLY implements up(); will throw if a transaction has other properties, except for `down()` - // which is currently ignored TODO implement this if it's useful to devs - // * gets list of migrations to run _after_ acquiring db lock (knex checks before acquiring - // lock, and then has to re-check afterwards) - // * sets migration_time to be the start of the migration batch's transaction rather than some - // other intermediate time - // * instead of attempting to acquire a lock on the single row in the knex_migrations_lock - // table, this code takes the simpler approach of locking the whole table. This table could - // be discarded completely by instead locking the knex_migrations table, but backwards- - // compatibility is essential to prevent concurrent running of knex-based and pg-based - // migrators. - // * does not check that all migrations listed in the database table actually exist in the - // filesystem - await withPg(config, async client => { - try { - log('Starting transaction...'); - await client.query('BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE'); - log('Transaction started.'); - - log('Creating tables if they do not exist...'); - // N.B. these tables are created to be similar to the legacy knex-created table. - const nameMaxLen = 255; - await client.query(` - CREATE TABLE IF NOT EXISTS knex_migrations ( - id SERIAL PRIMARY KEY, - name VARCHAR(${nameMaxLen}) NOT NULL, - batch INTEGER, - migration_time TIMESTAMP(3) WITH TIME ZONE - ); - CREATE TABLE IF NOT EXISTS knex_migrations_lock ( - index SERIAL PRIMARY KEY, - is_locked INTEGER NOT NULL - ); - `); - log('Tables now definitely exists.'); - - log('Acquiring lock on knex_migrations_lock table...'); - await client.query('LOCK TABLE knex_migrations_lock IN EXCLUSIVE MODE NOWAIT'); - log('Lock acquired.'); - - const toRun = await getMigrationsToRun(client); - - if (!toRun.length) { - log('No migrations to run - exiting.'); - await client.query('ROLLBACK'); - return; - } - log('Validating', toRun.length, 'migrations...'); - for (const { migration, name } of toRun) { - log('Validating migration:', name, '...'); - - if (name.length > nameMaxLen) throw new Error(`Migration name '${name}' is too long - max length is ${nameMaxLen}, but got ${name.length}`); + try { + log('Starting transaction...'); + await client.query('BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE'); + log('Transaction started.'); + + log('Creating tables if they do not exist...'); + // N.B. these tables are created to be similar to the legacy knex-created table. + const nameMaxLen = 255; + await client.query(` + CREATE TABLE IF NOT EXISTS knex_migrations ( + id SERIAL PRIMARY KEY, + name VARCHAR(${nameMaxLen}) NOT NULL, + batch INTEGER, + migration_time TIMESTAMP(3) WITH TIME ZONE + ); + CREATE TABLE IF NOT EXISTS knex_migrations_lock ( + index SERIAL PRIMARY KEY, + is_locked INTEGER NOT NULL + ); + `); + log('Tables now definitely exists.'); + + log('Acquiring lock on knex_migrations_lock table...'); + await client.query('LOCK TABLE knex_migrations_lock IN EXCLUSIVE MODE NOWAIT'); + log('Lock acquired.'); + + const toRun = await getMigrationsToRun(client); + + if (!toRun.length) { + log('No migrations to run - exiting.'); + await client.query('ROLLBACK'); + return; + } - // TODO check for illegal chars in name? + log('Validating', toRun.length, 'migrations...'); + for (const { migration, name } of toRun) { + log('Validating migration:', name, '...'); - const keys = Object.keys(migration); - const unexpectedKeys = _.omit(keys, 'up', 'down'); - if (unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); + if (name.length > nameMaxLen) throw new Error(`Migration name '${name}' is too long - max length is ${nameMaxLen}, but got ${name.length}`); - if (!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); - if (typeof migration.up !== 'function') { - throw new Error(`Required prop .up of migration ${name} has incorrect type - expected 'function', but got '${typeof migration.up}'`); - } + // TODO check for illegal chars in name? - if (migration.down && typeof migration.down !== 'function') { - throw new Error(`Optional prop .down of migration ${name} has incorrect type - expected 'function' but got '${typeof migration.down}'`); - } + const keys = Object.keys(migration); + const unexpectedKeys = _.omit(keys, 'up', 'down'); + if (unexpectedKeys.length) throw new Error(`Unexpected key(s) found in migration ${name}: ${unexpectedKeys}`); - log('Migration', name, 'looks valid.'); + if (!migration.up) throw new Error(`Required prop .up not found in migration ${name}`); + if (typeof migration.up !== 'function') { + throw new Error(`Required prop .up of migration ${name} has incorrect type - expected 'function', but got '${typeof migration.up}'`); } - log(toRun.length, 'migrations look valid.'); - - log('Running', toRun.length, 'migrations...'); - const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM knex_migrations`)).rows[0]; - const batchNumber = lastBatch + 1; - log(' batch number:', batchNumber); - - /* eslint-disable no-await-in-loop */ - for (const { migration, name } of toRun) { - log('Running migration:', name); - await migration.up(client); - // `CLOCK_TIMESTAMP()` used to match knex migrator's `new Date()`. - await client.query(` - INSERT INTO knex_migrations - (name, batch, migration_time) - VALUES($1, $2, CLOCK_TIMESTAMP()) - `, [ name, batchNumber ]); - log('Migration complete:', name); + + if (migration.down && typeof migration.down !== 'function') { + throw new Error(`Optional prop .down of migration ${name} has incorrect type - expected 'function' but got '${typeof migration.down}'`); } - /* eslint-enable no-await-in-loop */ - log(toRun.length, 'migrations ran OK.'); - - log('Committing migrations...'); - await client.query('COMMIT'); - log('Migrations committed.'); - } catch (err) { - log('Caught error; rolling back', err); - await client.query('ROLLBACK'); - throw err; + + log('Migration', name, 'looks valid.'); } - }); + log(toRun.length, 'migrations look valid.'); + + log('Running', toRun.length, 'migrations...'); + const { lastBatch } = (await client.query(`SELECT COALESCE(MAX(batch), 0) AS "lastBatch" FROM knex_migrations`)).rows[0]; + const batchNumber = lastBatch + 1; + log(' batch number:', batchNumber); + + /* eslint-disable no-await-in-loop */ + for (const { migration, name } of toRun) { + log('Running migration:', name); + await migration.up(client); + // `CLOCK_TIMESTAMP()` used to match knex migrator's `new Date()`. + await client.query(` + INSERT INTO knex_migrations + (name, batch, migration_time) + VALUES($1, $2, CLOCK_TIMESTAMP()) + `, [ name, batchNumber ]); + log('Migration complete:', name); + } + /* eslint-enable no-await-in-loop */ + log(toRun.length, 'migrations ran OK.'); + + log('Committing migrations...'); + await client.query('COMMIT'); + log('Migrations committed.'); + } catch (err) { + log('Caught error; rolling back', err); + await client.query('ROLLBACK'); + throw err; + } }; -module.exports = { withPg, pgMigrations }; +module.exports = { withPg, migrate }; From 398960f4c22ec74bdce5eaf273c7a7399ac96f1c Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 11:16:03 +0000 Subject: [PATCH 068/133] resolve REVIEW --- lib/bin/run-migrations.js | 2 -- lib/model/pg-migrator.js | 2 +- test/integration/setup.js | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/bin/run-migrations.js b/lib/bin/run-migrations.js index e9e2f5ced..497cba8f1 100644 --- a/lib/bin/run-migrations.js +++ b/lib/bin/run-migrations.js @@ -14,8 +14,6 @@ const { withPg, migrate: pgMigrate } = require('../model/pg-migrator'); try { await withKnex(require('config').get('default.database'))(knexMigrate); await withPg(require('config').get('default.database'))(pgMigrate); - // REVIEW should the new migrator follow the same function signature? e.g. - // withPg(config)(migrate)? } catch (err) { console.error('Error:', err.message); process.exit(1); diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 3082d16b9..4b73667c2 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -14,7 +14,7 @@ const pg = require('pg'); const migrationsDir = `${__dirname}/migrations`; -const withPg = async (config, fn) => { +const withPg = (config) => async fn => { const log = (...args) => console.log('[withPg]', ...args); // eslint-disable-line no-console log('ENTRY'); diff --git a/test/integration/setup.js b/test/integration/setup.js index 586eccfc8..498551e58 100644 --- a/test/integration/setup.js +++ b/test/integration/setup.js @@ -73,7 +73,7 @@ const populate = (container, [ head, ...tail ] = fixtures) => // this hook won't run if `test-unit` is called, as this directory is skipped // in that case. const initialize = async () => { - await withPg(dbConfig, client => client.query('DROP OWNED BY CURRENT_USER')); + await withPg(dbConfig)(client => client.query('DROP OWNED BY CURRENT_USER')); execSync('make migrations', { env: { ...process.env, NODE_CONFIG: JSON.stringify({ default: { database: dbConfig } }) } }); return withDefaults({ db, context, enketo, env, s3 }).transacting(populate); }; From f908b9e63dacae55271ce8c0dbd2a8dabb139c24 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 11:22:00 +0000 Subject: [PATCH 069/133] resolve TODO --- lib/model/pg-migrator.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 4b73667c2..36339cc73 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -71,8 +71,12 @@ const getMigrationsToRun = async client => { // Notable differences // // * ONLY provides db.raw()-equivalent function to transactions - no knex query builder etc. -// * ONLY implements up(); will throw if a transaction has other properties, except for `down()` -// which is currently ignored TODO implement this if it's useful to devs +// * ONLY implements up(); will throw if a transaction has other properties, except for `down()`. +// To reverse a migration, run e.g.: +// await require('./lib/model/pg-migrator') +// .withPg(require('config').get('default.database'))( +// require('./lib/model/migrations/20231208-01-dataset-form-def-actions').down, +// ) // * gets list of migrations to run _after_ acquiring db lock (knex checks before acquiring lock, // and then has to re-check afterwards) // * sets migration_time to be the start of the migration batch's transaction rather than some From 38fdb4bb0a62d9d8942221d2478dcb98ddf8cd15 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 11:25:45 +0000 Subject: [PATCH 070/133] resolve TODO: validate migration names --- lib/model/pg-migrator.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 36339cc73..46af0779d 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -14,6 +14,12 @@ const pg = require('pg'); const migrationsDir = `${__dirname}/migrations`; +const validateName = name => { + if (!name.match(/^\d{8}-\d{2}-[a-zA-Z0-9_-]+.js/)) { + throw new Error(`Illegal name format for migration '${name}'`); + } +}; + const withPg = (config) => async fn => { const log = (...args) => console.log('[withPg]', ...args); // eslint-disable-line no-console log('ENTRY'); @@ -131,7 +137,7 @@ const migrate = async (client) => { if (name.length > nameMaxLen) throw new Error(`Migration name '${name}' is too long - max length is ${nameMaxLen}, but got ${name.length}`); - // TODO check for illegal chars in name? + validateName(name); const keys = Object.keys(migration); const unexpectedKeys = _.omit(keys, 'up', 'down'); From ed6bb5e2305d6970f015437ec7da49d80a4e2681 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 18 Feb 2025 11:28:17 +0000 Subject: [PATCH 071/133] resolve TODO with better comments --- lib/model/pg-migrator.js | 2 +- test/db-migrations/migrator.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/model/pg-migrator.js b/lib/model/pg-migrator.js index 46af0779d..e92c3a30e 100644 --- a/lib/model/pg-migrator.js +++ b/lib/model/pg-migrator.js @@ -48,7 +48,7 @@ const getMigrationsToRun = async client => { const allMigrations = readdirSync(migrationsDir) .filter(f => f.endsWith('.js') && lstatSync(`${migrationsDir}/${f}`).isFile()) - .sort(); + .sort(); // match sorting in knex/lib/migrate/sources/fs-migrations.js log('allMigrations:', allMigrations); const alreadyRun = (await client.query('SELECT name FROM knex_migrations')).rows.map(r => r.name); diff --git a/test/db-migrations/migrator.js b/test/db-migrations/migrator.js index cf654fcff..c84c85534 100644 --- a/test/db-migrations/migrator.js +++ b/test/db-migrations/migrator.js @@ -88,7 +88,7 @@ function createMigrator(name, migrationsDir, holdingPen, previousMigrator) { const migrations = fs.readdirSync(migrationsDir) .filter(f => f.endsWith('.js')) .map(f => f.replace(/\.js$/, '')) - .sort(); // TODO check that this is how knex sorts migration files + .sort(); // match sorting in pg-migrator and knex's fs-migrations.js log(); log(`${name} migrations:`); log(); From de0608003dbe0343fe3c250248aacae44164ba55 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 19 Feb 2025 11:13:30 +0000 Subject: [PATCH 072/133] remove dead comment --- test/integration/setup.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/integration/setup.js b/test/integration/setup.js index 498551e58..5a9db1794 100644 --- a/test/integration/setup.js +++ b/test/integration/setup.js @@ -9,8 +9,6 @@ const request = require('supertest'); const { task } = require(appRoot + '/lib/task/task'); const authenticateUser = require('../util/authenticate-user'); const testData = require('../data/xml'); - -// knex things. const config = require('config'); const { withPg } = require(appRoot + '/lib/model/pg-migrator'); From ee1e3f822fad055d1235ca3f7aafdb4ea168bd17 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 19 Mar 2025 11:26:49 +0000 Subject: [PATCH 073/133] new migration: raw -> query --- .../20250113-01-add-webformsenabled-formtable-column.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/model/migrations/20250113-01-add-webformsenabled-formtable-column.js b/lib/model/migrations/20250113-01-add-webformsenabled-formtable-column.js index b79162a2f..50bd28c1e 100644 --- a/lib/model/migrations/20250113-01-add-webformsenabled-formtable-column.js +++ b/lib/model/migrations/20250113-01-add-webformsenabled-formtable-column.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` ALTER TABLE forms ADD COLUMN "webformsEnabled" boolean NOT NULL DEFAULT FALSE; `); -const down = (db) => db.raw(` +const down = (db) => db.query(` ALTER TABLE forms DROP COLUMN "webformsEnabled"; `); From eb14edb090e50cdcbe5c9afa012f1f900545daf8 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 19 Mar 2025 12:51:48 +0000 Subject: [PATCH 074/133] qyer --- .../migrations/20250221-01-deletedAt-index-entity.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/model/migrations/20250221-01-deletedAt-index-entity.js b/lib/model/migrations/20250221-01-deletedAt-index-entity.js index b0fc599b8..5c092eb13 100644 --- a/lib/model/migrations/20250221-01-deletedAt-index-entity.js +++ b/lib/model/migrations/20250221-01-deletedAt-index-entity.js @@ -9,13 +9,13 @@ const up = async (db) => { - await db.raw('CREATE INDEX entities_deletedat_index ON public.entities USING btree ("deletedAt")'); - await db.raw('CREATE INDEX entity_defs_sourceid_index ON public.entity_defs USING btree ("sourceId");'); + await db.query('CREATE INDEX entities_deletedat_index ON public.entities USING btree ("deletedAt")'); + await db.query('CREATE INDEX entity_defs_sourceid_index ON public.entity_defs USING btree ("sourceId");'); }; const down = async (db) => { - await db.raw('DROP INDEX entities_deletedat_index'); - await db.raw('DROP INDEX entity_defs_sourceid_index'); + await db.query('DROP INDEX entities_deletedat_index'); + await db.query('DROP INDEX entity_defs_sourceid_index'); }; module.exports = { up, down }; From 176bc73e9d5d31c5ead0ae942a58f9500d00e49a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 25 Mar 2025 04:33:53 +0000 Subject: [PATCH 075/133] fix name! --- ...ypes.js => 20250113-01-disable-nullable-blob-content-types.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/model/migrations/{20250204-01-disable-nullable-blob-content-types.js => 20250113-01-disable-nullable-blob-content-types.js} (100%) diff --git a/lib/model/migrations/20250204-01-disable-nullable-blob-content-types.js b/lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js similarity index 100% rename from lib/model/migrations/20250204-01-disable-nullable-blob-content-types.js rename to lib/model/migrations/20250113-01-disable-nullable-blob-content-types.js From d2849184ab55c5a8bf3a328b08b0f77bda22fe2d Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 25 Mar 2025 04:56:53 +0000 Subject: [PATCH 076/133] reduce changeset --- test/integration/other/knex-migrations.js | 24 +++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/test/integration/other/knex-migrations.js b/test/integration/other/knex-migrations.js index 9edb12248..124d1dffc 100644 --- a/test/integration/other/knex-migrations.js +++ b/test/integration/other/knex-migrations.js @@ -39,7 +39,7 @@ const testMigration = (filename, tests, options = {}) => { const { only = false, skip = false } = options; const f = only // eslint-disable-next-line no-only-tests/no-only-tests - ? describe.bind(describe) + ? describe.only.bind(describe) : (skip ? describe.skip.bind(describe) : describe); f(`knex migrations: ${filename}`, function() { this.timeout(20000); @@ -218,7 +218,7 @@ describe.skip('knex migrations', function() { }); -describe('knex migrations: removing default project', function() { +describe('database migrations: removing default project', function() { this.timeout(8000); it('should put old forms into project', testServiceFullTrx(async (service, container) => { @@ -255,7 +255,7 @@ describe('knex migrations: removing default project', function() { })); }); -describe('knex migrations: intermediate form schema', function() { +describe('database migrations: intermediate form schema', function() { this.timeout(20000); it('should test migration', testServiceFullTrx(async (service, container) => { @@ -384,7 +384,7 @@ describe('knex migrations: intermediate form schema', function() { })); }); -describe('knex migrations: 20230123-01-remove-google-backups', function() { +describe('database migrations: 20230123-01-remove-google-backups', function() { this.timeout(20000); beforeEach(() => upToMigration('20230123-01-remove-google-backups.js', false)); @@ -478,7 +478,7 @@ describe('knex migrations: 20230123-01-remove-google-backups', function() { })); }); -describe.skip('knex migrations: 20230324-01-edit-dataset-verbs.js', function () { +describe.skip('database migrations: 20230324-01-edit-dataset-verbs.js', function () { this.timeout(20000); it('should add dataset/entity read verbs with raw sql', testServiceFullTrx(async (service, container) => { @@ -514,7 +514,7 @@ describe.skip('knex migrations: 20230324-01-edit-dataset-verbs.js', function () })); }); -describe.skip('knex migrations from 20230406: altering entities and entity_defs', function () { +describe.skip('database migrations from 20230406: altering entities and entity_defs', function () { this.timeout(20000); const createEntity = async (service, container) => { @@ -608,7 +608,7 @@ describe.skip('knex migrations from 20230406: altering entities and entity_defs' })); }); -describe('knex migrations from 20230512: adding entity_def_sources table', function () { +describe('database migrations from 20230512: adding entity_def_sources table', function () { this.timeout(20000); it.skip('should backfill entityId and entityDefId in audit log', testServiceFullTrx(async (service, container) => { @@ -986,9 +986,8 @@ testMigration.skip('20240215-02-dedupe-verbs.js', () => { })); }); -// Skip because 1. this migration now runs on new migrator, and (2) it relies on application code. -testMigration.skip('20240914-02-remove-orphaned-client-audits.js', () => { - it('should remove orphaned client audits', testServiceFullTrx(async (service, container) => { +testMigration('20240914-02-remove-orphaned-client-audits.js', () => { + it.skip('should remove orphaned client audits', testServiceFullTrx(async (service, container) => { await populateUsers(container); await populateForms(container); @@ -1241,9 +1240,8 @@ testMigration.skip('20240914-02-remove-orphaned-client-audits.js', () => { }); }); -// Skip because 1. this migration now runs on new migrator, and (2) it relies on application code. -testMigration.skip('20241227-01-backfill-audit-entity-uuid.js', () => { - it('should update the format of detail for entity.delete audits', testServiceFullTrx(async (service, container) => { +testMigration('20241227-01-backfill-audit-entity-uuid.js', () => { + it.skip('should update the format of detail for entity.delete audits', testServiceFullTrx(async (service, container) => { await populateUsers(container); await populateForms(container); From 0b289d1eddd2735f42fad794e7e52a123b92d503 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 25 Mar 2025 05:01:24 +0000 Subject: [PATCH 077/133] fix migration name --- ... => 20250113-01-disable-nullable-blob-content-types.spec.js} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/db-migrations/{20250204-01-disable-nullable-blob-content-types.spec.js => 20250113-01-disable-nullable-blob-content-types.spec.js} (96%) diff --git a/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js similarity index 96% rename from test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js rename to test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js index e9b27d750..bbb1d0eda 100644 --- a/test/db-migrations/20250204-01-disable-nullable-blob-content-types.spec.js +++ b/test/db-migrations/20250113-01-disable-nullable-blob-content-types.spec.js @@ -7,7 +7,7 @@ const { // eslint-disable-line object-curly-newline rowsExistFor, } = require('./utils'); // eslint-disable-line object-curly-newline -describeMigration('20250204-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { +describeMigration('20250113-01-disable-nullable-blob-content-types', ({ runMigrationBeingTested }) => { const aBlobWith = props => { const randomContent = randomBytes(100); const md5 = hash('md5', randomContent); // eslint-disable-line no-multi-spaces From 7cc1b19adf77deb637dc9ab974da2a134e59069a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 25 Mar 2025 05:09:12 +0000 Subject: [PATCH 078/133] Try removing disableMigrationsListValidation --- lib/model/knex-migrator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 9bec11942..0dfddb938 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -23,8 +23,7 @@ const withKnex = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -// Ignore missing migrations, as they probably came from the new migrator. -const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy`, disableMigrationsListValidation: true }); +const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy` }); module.exports = { knexConnect, withKnex, migrate }; From cd0ff441f1d0163113ba40164a2a969a0a009993 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 25 Mar 2025 05:14:59 +0000 Subject: [PATCH 079/133] Revert "Try removing disableMigrationsListValidation" This reverts commit 7cc1b19adf77deb637dc9ab974da2a134e59069a. --- lib/model/knex-migrator.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 0dfddb938..9bec11942 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -23,7 +23,8 @@ const withKnex = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy` }); +// Ignore missing migrations, as they probably came from the new migrator. +const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy`, disableMigrationsListValidation: true }); module.exports = { knexConnect, withKnex, migrate }; From e97f81fec525338948366ea5b7f0ad0f76327650 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Tue, 25 Mar 2025 05:18:21 +0000 Subject: [PATCH 080/133] expand comment ref disableMigrationsListValidation --- lib/model/knex-migrator.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/model/knex-migrator.js b/lib/model/knex-migrator.js index 9bec11942..e568262b1 100644 --- a/lib/model/knex-migrator.js +++ b/lib/model/knex-migrator.js @@ -23,7 +23,11 @@ const withKnex = (config) => (mutator) => { }; // Given a database, initiates migrations on it. -// Ignore missing migrations, as they probably came from the new migrator. +// disableMigrationsListValidation: because knex-migrator now shares a DB table +// with pg-migrator, knex's built-in check that all migrations found in the db +// have corresponding migration files in `directory` will fail. +// REVIEW note that we could maintain this check if we duplicate migration +// tables and store pg migrations separately. const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations/legacy`, disableMigrationsListValidation: true }); module.exports = { knexConnect, withKnex, migrate }; From f219a7bb76c7a1d40ee4a7ddfee3eba9ab53ec44 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 30 Apr 2025 10:51:05 +0000 Subject: [PATCH 081/133] raw -> query --- lib/model/migrations/20250307-01-purged-entities-table.js | 6 +++--- .../migrations/20250415-01-client-audit-remainder.js | 8 ++++---- lib/model/migrations/20250428-01-audit-indices.js | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/model/migrations/20250307-01-purged-entities-table.js b/lib/model/migrations/20250307-01-purged-entities-table.js index e3a8cc476..c8952fb45 100644 --- a/lib/model/migrations/20250307-01-purged-entities-table.js +++ b/lib/model/migrations/20250307-01-purged-entities-table.js @@ -8,18 +8,18 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(` + await db.query(` CREATE TABLE purged_entities ( "entityUuid" varchar NOT NULL, "acteeId" varchar NOT NULL, "auditId" serial4 NOT NULL, CONSTRAINT purged_entities_pkey PRIMARY KEY ("entityUuid") );`); - await db.raw(`CREATE INDEX purged_entities_actee_uuid_index ON purged_entities ("acteeId", "entityUuid");`); + await db.query(`CREATE INDEX purged_entities_actee_uuid_index ON purged_entities ("acteeId", "entityUuid");`); }; const down = async (db) => { - await db.raw(`DROP TABLE purged_entities`); + await db.query(`DROP TABLE purged_entities`); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20250415-01-client-audit-remainder.js b/lib/model/migrations/20250415-01-client-audit-remainder.js index 2476771ad..78c5e9935 100644 --- a/lib/model/migrations/20250415-01-client-audit-remainder.js +++ b/lib/model/migrations/20250415-01-client-audit-remainder.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(` + await db.query(` ALTER TABLE client_audits ADD COLUMN "user" TEXT, ADD COLUMN "change-reason" TEXT `); - await db.raw(` + await db.query(` UPDATE client_audits SET "user" = remainder->>'user', @@ -25,7 +25,7 @@ const up = async (db) => { }; const down = async (db) => { - await db.raw(` + await db.query(` UPDATE client_audits SET remainder = jsonb_set( @@ -40,7 +40,7 @@ const down = async (db) => { WHERE "user" IS NOT NULL OR "change-reason" IS NOT NULL `); - await db.raw(` + await db.query(` ALTER TABLE client_audits DROP COLUMN "user", DROP COLUMN "change-reason" diff --git a/lib/model/migrations/20250428-01-audit-indices.js b/lib/model/migrations/20250428-01-audit-indices.js index 93ff5f8c7..ded31c542 100644 --- a/lib/model/migrations/20250428-01-audit-indices.js +++ b/lib/model/migrations/20250428-01-audit-indices.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(` + await db.query(` CREATE INDEX audits_details_entity_uuid_index ON audits USING hash ((details->'entity'->>'uuid')); DROP INDEX audits_details_submission_index; CREATE INDEX audits_details_submission_index ON audits USING hash (((details -> 'submissionId')::integer)); @@ -16,7 +16,7 @@ const up = async (db) => { }; const down = async (db) => { - await db.raw(` + await db.query(` DROP INDEX audits_details_entity_uuid_index; DROP INDEX audits_details_submission_index; CREATE INDEX audits_details_submission_index ON audits USING gin (((details -> 'submissionId'::text))); From 26583da1766a204af9b2f5e9067f522224794dbf Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 30 Apr 2025 11:00:16 +0000 Subject: [PATCH 082/133] build up full matrix --- .github/workflows/db-partial-migrations.yml | 49 +++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .github/workflows/db-partial-migrations.yml diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml new file mode 100644 index 000000000..30e6c0341 --- /dev/null +++ b/.github/workflows/db-partial-migrations.yml @@ -0,0 +1,49 @@ +# This is a test of legacy migrations in various states. +# This test workflow should not be required after knex has been removed. + +name: Partial Database Migrations + +jobs: + db-partial-migration-tests: + strategy: + matrix: + previous-migrations: + - none + - legacy-first-1 + - legacy-first-10 + - legacy-first-100 + - legacy-all + - new-first-1-as-legacy + - new-first-10-as-legacy + - new-first-1 + - new-first-10 + - all + timeout-minutes: 2 + # TODO should we use the same container as circle & central? + runs-on: ubuntu-latest + services: + # see: https://docs.github.com/en/enterprise-server@3.5/actions/using-containerized-services/creating-postgresql-service-containers + postgres: + image: postgres:14.10 + env: + POSTGRES_PASSWORD: odktest + ports: + - 5432:5432 + # Set health checks to wait until postgres has started + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v4 + - name: Set node version + uses: actions/setup-node@v4 + with: + node-version: 22.14.0 + cache: 'npm' + - run: npm ci + - run: node lib/bin/create-docker-databases.js + - run: test/db-partial-migrations/prepare ${{ matrix.previous-migrations }} + - run: make migrations + - run: test/db-partial-migrations/assert-final-schema From ea9dfcf93d1d43ffa9e2ca33d6e967ab446bf52a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 30 Apr 2025 11:01:47 +0000 Subject: [PATCH 083/133] ci: add on: section --- .github/workflows/db-partial-migrations.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index 30e6c0341..c7068b520 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -3,6 +3,10 @@ name: Partial Database Migrations +on: + push: + pull_request: + jobs: db-partial-migration-tests: strategy: From ef1f0f420b0494ce53514545d3161f8ec1d60eb5 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Wed, 30 Apr 2025 11:10:21 +0000 Subject: [PATCH 084/133] add failing outline of tests --- .github/workflows/db-partial-migrations.yml | 1 + .../db-partial-migrations/assert-final-schema | 11 +++++++++ test/db-partial-migrations/prepare | 24 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 test/db-partial-migrations/assert-final-schema create mode 100644 test/db-partial-migrations/prepare diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index c7068b520..75753f610 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -40,6 +40,7 @@ jobs: --health-timeout 5s --health-retries 5 steps: + - run: apt-get install tree - uses: actions/checkout@v4 - name: Set node version uses: actions/setup-node@v4 diff --git a/test/db-partial-migrations/assert-final-schema b/test/db-partial-migrations/assert-final-schema new file mode 100644 index 000000000..961e3dd1d --- /dev/null +++ b/test/db-partial-migrations/assert-final-schema @@ -0,0 +1,11 @@ +#!/bin/bash -eu +set -o pipefail + +log() { echo "[test/db-partial-migrations/assert-final-schema] $*"; } + +if ! diff test/db-partial-migrations/expected-schema.sql <(./test/db-partial-migrations/dump-postgres-schema); then + log "!!!" + log "!!! Schema differences detected. See above for details." + log "!!!" + exit 1 +fi diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare new file mode 100644 index 000000000..88f74b6de --- /dev/null +++ b/test/db-partial-migrations/prepare @@ -0,0 +1,24 @@ +#!/bin/bash -eu +set -o pipefail + +log() { echo "[test/db-partial-migrations/prepare] $*"; } + +show_migrations() { + tree lib/model/migrations +} + +prerun="$1" +log "Requested for prerun: $prerun" + +log "Re-arranging migrations..." +make migrations +log "Initial migrations structure:" +show_migrations + +log "Re-instating unrun migrations..." +# TODO + +log "Final migrations structure:" +show_migrations + +log "Completed OK." From 45e4fbe6e50d35c170985295a386b4b1d1475db3 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:09:36 +0000 Subject: [PATCH 085/133] update and install --- .github/workflows/db-partial-migrations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index 75753f610..949bbf1e9 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -40,7 +40,7 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - run: apt-get install tree + - run: sudo apt-get update && sudo apt-get install tree - uses: actions/checkout@v4 - name: Set node version uses: actions/setup-node@v4 From b6803ba547890231364e41ebddbc0b36a3238932 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:09:58 +0000 Subject: [PATCH 086/133] without update --- .github/workflows/db-partial-migrations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index 949bbf1e9..5cb18b071 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -40,7 +40,7 @@ jobs: --health-timeout 5s --health-retries 5 steps: - - run: sudo apt-get update && sudo apt-get install tree + - run: sudo apt-get install tree - uses: actions/checkout@v4 - name: Set node version uses: actions/setup-node@v4 From 14f3650062a5b61457c201cfd9aa919e503b9c8e Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:11:08 +0000 Subject: [PATCH 087/133] make executable --- test/db-partial-migrations/prepare | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/db-partial-migrations/prepare diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare old mode 100644 new mode 100755 From a5207d8e6cdc0aa9263930ca18a7e006c662cdd5 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:38:37 +0000 Subject: [PATCH 088/133] wip --- Makefile | 3 +++ lib/bin/run-migrations-legacy.js | 20 +++++++++++++++ test/db-partial-migrations/prepare | 39 ++++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 lib/bin/run-migrations-legacy.js diff --git a/Makefile b/Makefile index 2710b4899..f45143277 100644 --- a/Makefile +++ b/Makefile @@ -73,6 +73,9 @@ fake-s3-server-persistent: .PHONY: migrations migrations: node_version node lib/bin/run-migrations.js +.PHONY: migrations-legacy +migrations-legacy: node_version + node lib/bin/run-migrations-legacy.js ################################################################################ diff --git a/lib/bin/run-migrations-legacy.js b/lib/bin/run-migrations-legacy.js new file mode 100644 index 000000000..c9d2170f9 --- /dev/null +++ b/lib/bin/run-migrations-legacy.js @@ -0,0 +1,20 @@ +// Copyright 2022 ODK Central Developers +// See the NOTICE file at the top-level directory of this distribution and at +// https://github.com/getodk/central-backend/blob/master/NOTICE. +// This file is part of ODK Central. It is subject to the license terms in +// the LICENSE file found in the top-level directory of this distribution and at +// https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, +// including this file, may be copied, modified, propagated, or distributed +// except according to the terms contained in the LICENSE file. + +const { withKnex, migrate } = require('../model/knex-migrator-legacy'); + +(async () => { + try { + await withKnex(require('config').get('default.database'))(migrate); + } catch (err) { + if (err.detail) console.error('Error:', err.message, `(${err.detail})`); + else console.error('Error:', err.message); // eslint-disable-line no-multi-spaces + process.exit(1); + } +})(); diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare index 88f74b6de..37d897b0f 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/prepare @@ -4,17 +4,52 @@ set -o pipefail log() { echo "[test/db-partial-migrations/prepare] $*"; } show_migrations() { - tree lib/model/migrations + echo TODO + #tree lib/model/migrations # TODO reinstate } prerun="$1" log "Requested for prerun: $prerun" +migrations_legacy=./lib/model/migrations/legacy +migrations_new=./lib/model/migrations + +rmExceptFirst() { + local skipCount="$1" + local src="$2" + local dest="$3" + find "$src" -maxdepth 1 -type f -name \*.js -printf '%p\n' | + sort | + tail -n +$((skipCount+1)) | + xargs -I{} echo mv "{}" "$dest" +} + log "Re-arranging migrations..." -make migrations +case "$prerun" in + none) + echo rm "$migrations_legacy"/* + echo rm "$migrations_new"/* + ;; + legacy-all) + echo rm "$migrations_new"/* + ;; + legacy-first-*) + rmExceptFirst "$(sed s/legacy-first-// <<<"$prerun")" "$migrations_legacy" + ;; + *) + log "!!!" + log "!!! No rule found matching '$prerun'" + log "!!!" + exit 1 + ;; +esac +exit # TODO remove this log "Initial migrations structure:" show_migrations +# FIXME an ideal test would run this with the legacy migrator +make migrations-legacy + log "Re-instating unrun migrations..." # TODO From 5648c473506046232c94039a005312f6eafb8dd7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:39:33 +0000 Subject: [PATCH 089/133] actually run migrations in the legacy style --- lib/model/knex-migrator-legacy.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 lib/model/knex-migrator-legacy.js diff --git a/lib/model/knex-migrator-legacy.js b/lib/model/knex-migrator-legacy.js new file mode 100644 index 000000000..d2c3f8bd7 --- /dev/null +++ b/lib/model/knex-migrator-legacy.js @@ -0,0 +1,29 @@ +// Copyright 2017 ODK Central Developers +// See the NOTICE file at the top-level directory of this distribution and at +// https://github.com/getodk/central-backend/blob/master/NOTICE. +// This file is part of ODK Central. It is subject to the license terms in +// the LICENSE file found in the top-level directory of this distribution and at +// https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central, +// including this file, may be copied, modified, propagated, or distributed +// except according to the terms contained in the LICENSE file. +// +// This is a variety of functions helpful for connecting to and performing +// top-level operations with a database, like migrations. + +const knex = require('knex'); +const { knexConnection } = require('../util/db'); + +// Connects to the postgres database specified in configuration and returns it. +const knexConnect = (config) => knex({ client: 'pg', connection: knexConnection(config) }); + +// Connects to a database, passes it to a function for operations, then ensures its closure. +const withKnex = (config) => (mutator) => { + const db = knexConnect(config); + return mutator(db).finally(() => db.destroy()); +}; + +// Given a database, initiates migrations on it. +const migrate = (db) => db.migrate.latest({ directory: `${__dirname}/migrations` }); + +module.exports = { knexConnect, withKnex, migrate }; + From 6116ba03f59865c95e616723f648f33814171242 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:46:57 +0000 Subject: [PATCH 090/133] more prep --- test/db-partial-migrations/prepare | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare index 37d897b0f..d9a26ea3a 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/prepare @@ -17,25 +17,29 @@ migrations_new=./lib/model/migrations rmExceptFirst() { local skipCount="$1" local src="$2" - local dest="$3" find "$src" -maxdepth 1 -type f -name \*.js -printf '%p\n' | sort | tail -n +$((skipCount+1)) | - xargs -I{} echo mv "{}" "$dest" + xargs echo rm } log "Re-arranging migrations..." case "$prerun" in none) - echo rm "$migrations_legacy"/* echo rm "$migrations_new"/* + echo rm "$migrations_legacy"/* ;; legacy-all) echo rm "$migrations_new"/* ;; legacy-first-*) + echo rm "$migrations_new"/* rmExceptFirst "$(sed s/legacy-first-// <<<"$prerun")" "$migrations_legacy" ;; + new-first-*-as-legacy) + rmExceptFirst "$(sed s/new-first-\(.*\)-as-legacy/\1/ <<<"$prerun")" "$migrations_new" + sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js + ;; *) log "!!!" log "!!! No rule found matching '$prerun'" @@ -43,11 +47,11 @@ case "$prerun" in exit 1 ;; esac +sed -i s/db\.query/db\.raw/ -- "$migrations_new"/*.js exit # TODO remove this log "Initial migrations structure:" show_migrations -# FIXME an ideal test would run this with the legacy migrator make migrations-legacy log "Re-instating unrun migrations..." From e9ef7d2cbb04f5f84714ff4565825c2c6fe32147 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:47:22 +0000 Subject: [PATCH 091/133] wip --- .github/workflows/db-partial-migrations.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index 5cb18b071..61f814c61 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -19,9 +19,6 @@ jobs: - legacy-all - new-first-1-as-legacy - new-first-10-as-legacy - - new-first-1 - - new-first-10 - - all timeout-minutes: 2 # TODO should we use the same container as circle & central? runs-on: ubuntu-latest From 332c69b80c5ee489f001d713bcf808da670be9a6 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:52:20 +0000 Subject: [PATCH 092/133] wip --- test/db-partial-migrations/prepare | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare index d9a26ea3a..0ac422c44 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/prepare @@ -3,9 +3,19 @@ set -o pipefail log() { echo "[test/db-partial-migrations/prepare] $*"; } +if ! [[ "$(git status --porcelain)" = "" ]]; then + log "!!!" + log "!!! You have uncomitted changes in your local git repo." + log "!!!" + log "!!! This command will make destructive changes." + log "!!!" + log "!!! Please revert or commit these changes before continuing." + log "!!!" + exit 1 +fi + show_migrations() { - echo TODO - #tree lib/model/migrations # TODO reinstate + tree lib/model/migrations # TODO reinstate } prerun="$1" @@ -20,20 +30,20 @@ rmExceptFirst() { find "$src" -maxdepth 1 -type f -name \*.js -printf '%p\n' | sort | tail -n +$((skipCount+1)) | - xargs echo rm + xargs rm } log "Re-arranging migrations..." case "$prerun" in none) - echo rm "$migrations_new"/* - echo rm "$migrations_legacy"/* + rm "$migrations_new"/* + rm "$migrations_legacy"/* ;; legacy-all) - echo rm "$migrations_new"/* + rm "$migrations_new"/* ;; legacy-first-*) - echo rm "$migrations_new"/* + rm "$migrations_new"/* rmExceptFirst "$(sed s/legacy-first-// <<<"$prerun")" "$migrations_legacy" ;; new-first-*-as-legacy) @@ -48,14 +58,13 @@ case "$prerun" in ;; esac sed -i s/db\.query/db\.raw/ -- "$migrations_new"/*.js -exit # TODO remove this log "Initial migrations structure:" show_migrations make migrations-legacy log "Re-instating unrun migrations..." -# TODO +git reset --hard log "Final migrations structure:" show_migrations From fbdc6fb74cb22f070b5aa1779c5aa4be7f35f177 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:52:47 +0000 Subject: [PATCH 093/133] show output --- test/db-partial-migrations/prepare | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare index 0ac422c44..2df2898d3 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/prepare @@ -1,4 +1,4 @@ -#!/bin/bash -eu +#!/bin/bash -eux set -o pipefail log() { echo "[test/db-partial-migrations/prepare] $*"; } From 54fbde826bf8d4a1dcc41409e183041c1cdea9ba Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:53:30 +0000 Subject: [PATCH 094/133] remove js --- test/db-partial-migrations/prepare | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare index 2df2898d3..af300572b 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/prepare @@ -36,14 +36,14 @@ rmExceptFirst() { log "Re-arranging migrations..." case "$prerun" in none) - rm "$migrations_new"/* - rm "$migrations_legacy"/* + rm "$migrations_new"/*.js + rm "$migrations_legacy"/*.js ;; legacy-all) - rm "$migrations_new"/* + rm "$migrations_new"/*.js ;; legacy-first-*) - rm "$migrations_new"/* + rm "$migrations_new"/*.js rmExceptFirst "$(sed s/legacy-first-// <<<"$prerun")" "$migrations_legacy" ;; new-first-*-as-legacy) From 6fbeb3720330a5725aeb0102be6172eb50f416bd Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:56:19 +0000 Subject: [PATCH 095/133] wip --- test/db-partial-migrations/prepare | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/prepare index af300572b..43c526394 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/prepare @@ -41,14 +41,17 @@ case "$prerun" in ;; legacy-all) rm "$migrations_new"/*.js + mv "$migrations_legacy"/*.js "$migrations_new/" ;; legacy-first-*) rm "$migrations_new"/*.js rmExceptFirst "$(sed s/legacy-first-// <<<"$prerun")" "$migrations_legacy" + mv "$migrations_legacy"/*.js "$migrations_new/" ;; new-first-*-as-legacy) rmExceptFirst "$(sed s/new-first-\(.*\)-as-legacy/\1/ <<<"$prerun")" "$migrations_new" sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js + mv "$migrations_legacy"/*.js "$migrations_new/" ;; *) log "!!!" @@ -57,7 +60,6 @@ case "$prerun" in exit 1 ;; esac -sed -i s/db\.query/db\.raw/ -- "$migrations_new"/*.js log "Initial migrations structure:" show_migrations From 4d8da90cf2acb36bce8eb6be01d63e7ee603ce6d Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 13:59:41 +0000 Subject: [PATCH 096/133] test all in one --- .github/workflows/db-partial-migrations.yml | 5 ++--- test/db-partial-migrations/assert-final-schema | 11 ----------- test/db-partial-migrations/{prepare => test.sh} | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 14 deletions(-) delete mode 100644 test/db-partial-migrations/assert-final-schema rename test/db-partial-migrations/{prepare => test.sh} (78%) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index 61f814c61..b6bd22395 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -19,6 +19,7 @@ jobs: - legacy-all - new-first-1-as-legacy - new-first-10-as-legacy + - all timeout-minutes: 2 # TODO should we use the same container as circle & central? runs-on: ubuntu-latest @@ -46,6 +47,4 @@ jobs: cache: 'npm' - run: npm ci - run: node lib/bin/create-docker-databases.js - - run: test/db-partial-migrations/prepare ${{ matrix.previous-migrations }} - - run: make migrations - - run: test/db-partial-migrations/assert-final-schema + - run: test/db-partial-migrations/test.sh ${{ matrix.previous-migrations }} diff --git a/test/db-partial-migrations/assert-final-schema b/test/db-partial-migrations/assert-final-schema deleted file mode 100644 index 961e3dd1d..000000000 --- a/test/db-partial-migrations/assert-final-schema +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -eu -set -o pipefail - -log() { echo "[test/db-partial-migrations/assert-final-schema] $*"; } - -if ! diff test/db-partial-migrations/expected-schema.sql <(./test/db-partial-migrations/dump-postgres-schema); then - log "!!!" - log "!!! Schema differences detected. See above for details." - log "!!!" - exit 1 -fi diff --git a/test/db-partial-migrations/prepare b/test/db-partial-migrations/test.sh similarity index 78% rename from test/db-partial-migrations/prepare rename to test/db-partial-migrations/test.sh index 43c526394..77353fa6f 100755 --- a/test/db-partial-migrations/prepare +++ b/test/db-partial-migrations/test.sh @@ -53,6 +53,10 @@ case "$prerun" in sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js mv "$migrations_legacy"/*.js "$migrations_new/" ;; + all) + sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js + mv "$migrations_legacy"/*.js "$migrations_new/" + ;; *) log "!!!" log "!!! No rule found matching '$prerun'" @@ -63,6 +67,7 @@ esac log "Initial migrations structure:" show_migrations +log "Running legacy migrations..." make migrations-legacy log "Re-instating unrun migrations..." @@ -71,4 +76,15 @@ git reset --hard log "Final migrations structure:" show_migrations +log "Running modern migrations..." +make migrations + +log "Checking final database schema..." +if ! diff test/db-partial-migrations/expected-schema.sql <(./test/db-partial-migrations/dump-postgres-schema); then + log "!!!" + log "!!! Schema differences detected. See above for details." + log "!!!" + exit 1 +fi + log "Completed OK." From d50aed3cd78ab958a40ea4f4a3fc5fb4cecc8ec9 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:01:56 +0000 Subject: [PATCH 097/133] better cleran --- test/db-partial-migrations/test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 77353fa6f..d22f1ddaf 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -71,7 +71,8 @@ log "Running legacy migrations..." make migrations-legacy log "Re-instating unrun migrations..." -git reset --hard +git checkout -- lib/model/migrations +git clean -dfx -- lib/model/migrations log "Final migrations structure:" show_migrations From b4b92f1def61fbba92c7a1aa19724b61688607b3 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:03:09 +0000 Subject: [PATCH 098/133] new filrst --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index d22f1ddaf..68a647a16 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -49,7 +49,7 @@ case "$prerun" in mv "$migrations_legacy"/*.js "$migrations_new/" ;; new-first-*-as-legacy) - rmExceptFirst "$(sed s/new-first-\(.*\)-as-legacy/\1/ <<<"$prerun")" "$migrations_new" + rmExceptFirst "$(sed "s/new-first-\(.*\)-as-legacy/\1/" <<<"$prerun")" "$migrations_new" sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js mv "$migrations_legacy"/*.js "$migrations_new/" ;; From 2c7abdd5bd5edd927f1f472a7fc3475600c87ad2 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:07:23 +0000 Subject: [PATCH 099/133] fix requires in legacy migrations --- test/db-partial-migrations/test.sh | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 68a647a16..59e4cb6f1 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -33,6 +33,15 @@ rmExceptFirst() { xargs rm } +fixLegacyMigrations() { + sed -E -i -e "s:../../:../:" -- "$migrations_legacy"/*.js + mv "$migrations_legacy"/*.js "$migrations_new/" +} + +fixNewMigrations() { + sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js +} + log "Re-arranging migrations..." case "$prerun" in none) @@ -41,21 +50,21 @@ case "$prerun" in ;; legacy-all) rm "$migrations_new"/*.js - mv "$migrations_legacy"/*.js "$migrations_new/" + fixLegacyMigrations ;; legacy-first-*) rm "$migrations_new"/*.js rmExceptFirst "$(sed s/legacy-first-// <<<"$prerun")" "$migrations_legacy" - mv "$migrations_legacy"/*.js "$migrations_new/" + fixLegacyMigrations ;; new-first-*-as-legacy) rmExceptFirst "$(sed "s/new-first-\(.*\)-as-legacy/\1/" <<<"$prerun")" "$migrations_new" - sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js - mv "$migrations_legacy"/*.js "$migrations_new/" + fixNewMigrations + fixLegacyMigrations ;; all) - sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js - mv "$migrations_legacy"/*.js "$migrations_new/" + fixNewMigrations + fixLegacyMigrations ;; *) log "!!!" From c4dfd9a60aea5a6becfdc1e3eae62fb86e98a0e8 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:08:53 +0000 Subject: [PATCH 100/133] rebuild --- lib/model/migrations/legacy/rebuild | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/model/migrations/legacy/rebuild diff --git a/lib/model/migrations/legacy/rebuild b/lib/model/migrations/legacy/rebuild new file mode 100644 index 000000000..e69de29bb From efb9ade1cf83ad976c47554cea2fa49ab7e3b1b8 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:09:13 +0000 Subject: [PATCH 101/133] build please --- lib/model/migrations/legacy/rebuild | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/model/migrations/legacy/rebuild diff --git a/lib/model/migrations/legacy/rebuild b/lib/model/migrations/legacy/rebuild deleted file mode 100644 index e69de29bb..000000000 From 2ae8b034c795baea280b7a0e41d89b687f46ec87 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:17:52 +0000 Subject: [PATCH 102/133] get connection string --- test/db-partial-migrations/test.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 59e4cb6f1..2fe9686b7 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -90,7 +90,14 @@ log "Running modern migrations..." make migrations log "Checking final database schema..." -if ! diff test/db-partial-migrations/expected-schema.sql <(./test/db-partial-migrations/dump-postgres-schema); then +if ! diff \ + test/db-partial-migrations/expected-schema.sql \ + <( + pg_dump --schema-only "$(node -e " + const { host, database, user, password } = require('config').get('default.database'); + console.log(\`postgres://\${user}:\${password}@\${host}/\${database}\`); + ")" + ); then log "!!!" log "!!! Schema differences detected. See above for details." log "!!!" From c21187a017d1e59f1bc4a432d576447a963a168d Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:18:31 +0000 Subject: [PATCH 103/133] nicer esxcaping --- test/db-partial-migrations/test.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 2fe9686b7..45286ff20 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -93,10 +93,10 @@ log "Checking final database schema..." if ! diff \ test/db-partial-migrations/expected-schema.sql \ <( - pg_dump --schema-only "$(node -e " - const { host, database, user, password } = require('config').get('default.database'); - console.log(\`postgres://\${user}:\${password}@\${host}/\${database}\`); - ")" + pg_dump --schema-only "$(node -e ' + const { host, database, user, password } = require("config").get("default.database"); + console.log(\`postgres://${user}:${password}@${host}/${database}\`); + ')" ); then log "!!!" log "!!! Schema differences detected. See above for details." From ba81777a3082626a6db89eebf6ff200135b418fa Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:19:48 +0000 Subject: [PATCH 104/133] more logging? --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 45286ff20..972af92bb 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -77,7 +77,7 @@ log "Initial migrations structure:" show_migrations log "Running legacy migrations..." -make migrations-legacy +DEBUG="knex:*" make migrations-legacy log "Re-instating unrun migrations..." git checkout -- lib/model/migrations From 7b9acbb72a3373f3b3b94b46a4ba729a80d469d0 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:22:09 +0000 Subject: [PATCH 105/133] flush output --- test/db-partial-migrations/test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 972af92bb..5c395f264 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -15,7 +15,8 @@ if ! [[ "$(git status --porcelain)" = "" ]]; then fi show_migrations() { - tree lib/model/migrations # TODO reinstate + tree lib/model/migrations + sleep 1 # wait for output to flush - seems slow in CI } prerun="$1" From 95b2b14ffab9810aef1b13e2fc99d9654a24b85a Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:29:06 +0000 Subject: [PATCH 106/133] fix fix --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 5c395f264..ad00fabc8 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -35,7 +35,7 @@ rmExceptFirst() { } fixLegacyMigrations() { - sed -E -i -e "s:../../:../:" -- "$migrations_legacy"/*.js + sed -E -i -e "s:\.\./\.\./:../:" -- "$migrations_legacy"/*.js mv "$migrations_legacy"/*.js "$migrations_new/" } From 1fccd8bfe25ea969f7ed5efd8ff28ce323ad4a1b Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:29:38 +0000 Subject: [PATCH 107/133] helpful comments --- test/db-partial-migrations/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index ad00fabc8..d721caaa9 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -35,11 +35,13 @@ rmExceptFirst() { } fixLegacyMigrations() { + # fix relative require() paths sed -E -i -e "s:\.\./\.\./:../:" -- "$migrations_legacy"/*.js mv "$migrations_legacy"/*.js "$migrations_new/" } fixNewMigrations() { + # convert pg API to knex API sed -E -i -e "s/db\.query/db.raw/" -- "$migrations_new"/*.js } From c1df6859adfe3a538128c0d97864ef4d58247600 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:32:33 +0000 Subject: [PATCH 108/133] no escape backtick --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index d721caaa9..019d1901b 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -98,7 +98,7 @@ if ! diff \ <( pg_dump --schema-only "$(node -e ' const { host, database, user, password } = require("config").get("default.database"); - console.log(\`postgres://${user}:${password}@${host}/${database}\`); + console.log(`postgres://${user}:${password}@${host}/${database}`); ')" ); then log "!!!" From 9f2f4b041aa00120580a14ff312c3544804fc815 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:34:29 +0000 Subject: [PATCH 109/133] add missing schema file --- test/db-partial-migrations/expected-schema.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/db-partial-migrations/expected-schema.sql diff --git a/test/db-partial-migrations/expected-schema.sql b/test/db-partial-migrations/expected-schema.sql new file mode 100644 index 000000000..e69de29bb From 18ef0e1dbd33958d17e38d70892969476f8b7396 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:39:05 +0000 Subject: [PATCH 110/133] expect table contnets --- test/db-partial-migrations/expected-migrations-table-contents.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/db-partial-migrations/expected-migrations-table-contents.sql diff --git a/test/db-partial-migrations/expected-migrations-table-contents.sql b/test/db-partial-migrations/expected-migrations-table-contents.sql new file mode 100644 index 000000000..e69de29bb From 962c6a80f4ef3ef36d71edc3df7ea73fda92f578 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:40:02 +0000 Subject: [PATCH 111/133] ye --- test/db-partial-migrations/test.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 019d1901b..20638a118 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -92,19 +92,27 @@ show_migrations log "Running modern migrations..." make migrations +pgConnectionString= + log "Checking final database schema..." if ! diff \ test/db-partial-migrations/expected-schema.sql \ - <( - pg_dump --schema-only "$(node -e ' - const { host, database, user, password } = require("config").get("default.database"); - console.log(`postgres://${user}:${password}@${host}/${database}`); - ')" - ); then + <(pg_dump --schema-only "$pgConnectionString"); then log "!!!" log "!!! Schema differences detected. See above for details." log "!!!" exit 1 fi +log "Checking migrations table..." +tableName="knex_migrations" +if ! diff \ + test/db-partial-migrations/expected-migrations-table-contents.sql \ + <(psql "$pgConnectionString" -c "SELECT * FROM $tableName"); then + log "!!!" + log "!!! $tableName table content differences detected. See above for details." + log "!!!" + exit 1 +fi + log "Completed OK." From f984324d6c275144ab12ca7602950b08c97b8378 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:45:34 +0000 Subject: [PATCH 112/133] revert some legacy to legacy --- .../20230802-01-delete-orphan-submissions.js | 2 +- ...30818-01-remove-schemaId-from-dsPropertyFields.js | 2 +- .../{ => legacy}/20230824-01-add-entity-version.js | 6 +++--- .../20230830-01-remove-entity-label-from-audits.js | 2 +- .../{ => legacy}/20230907-01-opened-form-verb.js | 4 ++-- .../{ => legacy}/20231002-01-add-conflict-details.js | 12 ++++++------ .../20231013-01-change-entity-error-action.js | 4 ++-- .../20231208-01-dataset-form-def-actions.js | 8 ++++---- .../{ => legacy}/20240215-01-entity-delete-verb.js | 4 ++-- .../{ => legacy}/20240215-02-dedupe-verbs.js | 2 +- .../20240312-01-add-dataset-create-verb.js | 4 ++-- .../20240322-01-add-entity-source-index-to-audits.js | 8 ++++---- .../{ => legacy}/20240515-01-entity-tz-precision.js | 4 ++-- ...240607-01-add-offline-entity-branch-trunk-info.js | 4 ++-- .../20240607-02-add-submission-backlog.js | 4 ++-- .../20240715-01-backlog-add-event-entityuuid.js | 4 ++-- .../{ => legacy}/20240913-01-add-blob-s3.js | 4 ++-- .../20240914-01-add-submission-delete-verb.js | 4 ++-- .../20240914-02-remove-orphaned-client-audits.js | 2 +- .../20241001-01-index-on-session-table.js | 4 ++-- .../{ => legacy}/20241008-01-add-user_preferences.js | 4 ++-- .../20241010-01-schedule-entity-form-upgrade.js | 2 +- ...9-01-schedule-entity-form-upgrade-create-forms.js | 2 +- .../20241030-01-add-force-entity-def-source.js | 4 ++-- .../{ => legacy}/20241224-01-entity-restore-verb.js | 4 ++-- .../{ => legacy}/20241224-02-cascade-entity-purge.js | 4 ++-- .../20241226-01-indices-for-purging-entities.js | 4 ++-- .../20241227-01-backfill-audit-entity-uuid.js | 2 +- 28 files changed, 57 insertions(+), 57 deletions(-) rename lib/model/migrations/{ => legacy}/20230802-01-delete-orphan-submissions.js (97%) rename lib/model/migrations/{ => legacy}/20230818-01-remove-schemaId-from-dsPropertyFields.js (89%) rename lib/model/migrations/{ => legacy}/20230824-01-add-entity-version.js (82%) rename lib/model/migrations/{ => legacy}/20230830-01-remove-entity-label-from-audits.js (95%) rename lib/model/migrations/{ => legacy}/20230907-01-opened-form-verb.js (93%) rename lib/model/migrations/{ => legacy}/20231002-01-add-conflict-details.js (66%) rename lib/model/migrations/{ => legacy}/20231013-01-change-entity-error-action.js (77%) rename lib/model/migrations/{ => legacy}/20231208-01-dataset-form-def-actions.js (68%) rename lib/model/migrations/{ => legacy}/20240215-01-entity-delete-verb.js (92%) rename lib/model/migrations/{ => legacy}/20240215-02-dedupe-verbs.js (96%) rename lib/model/migrations/{ => legacy}/20240312-01-add-dataset-create-verb.js (92%) rename lib/model/migrations/{ => legacy}/20240322-01-add-entity-source-index-to-audits.js (62%) rename lib/model/migrations/{ => legacy}/20240515-01-entity-tz-precision.js (79%) rename lib/model/migrations/{ => legacy}/20240607-01-add-offline-entity-branch-trunk-info.js (89%) rename lib/model/migrations/{ => legacy}/20240607-02-add-submission-backlog.js (89%) rename lib/model/migrations/{ => legacy}/20240715-01-backlog-add-event-entityuuid.js (87%) rename lib/model/migrations/{ => legacy}/20240913-01-add-blob-s3.js (87%) rename lib/model/migrations/{ => legacy}/20240914-01-add-submission-delete-verb.js (93%) rename lib/model/migrations/{ => legacy}/20240914-02-remove-orphaned-client-audits.js (97%) rename lib/model/migrations/{ => legacy}/20241001-01-index-on-session-table.js (91%) rename lib/model/migrations/{ => legacy}/20241008-01-add-user_preferences.js (96%) rename lib/model/migrations/{ => legacy}/20241010-01-schedule-entity-form-upgrade.js (97%) rename lib/model/migrations/{ => legacy}/20241029-01-schedule-entity-form-upgrade-create-forms.js (98%) rename lib/model/migrations/{ => legacy}/20241030-01-add-force-entity-def-source.js (92%) rename lib/model/migrations/{ => legacy}/20241224-01-entity-restore-verb.js (92%) rename lib/model/migrations/{ => legacy}/20241224-02-cascade-entity-purge.js (94%) rename lib/model/migrations/{ => legacy}/20241226-01-indices-for-purging-entities.js (94%) rename lib/model/migrations/{ => legacy}/20241227-01-backfill-audit-entity-uuid.js (96%) diff --git a/lib/model/migrations/20230802-01-delete-orphan-submissions.js b/lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js similarity index 97% rename from lib/model/migrations/20230802-01-delete-orphan-submissions.js rename to lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js index 9986e0969..39cb1c8e3 100644 --- a/lib/model/migrations/20230802-01-delete-orphan-submissions.js +++ b/lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js @@ -9,7 +9,7 @@ // Delete draft Submissions that don't have any definition - cb#911 const up = async (db) => { - await db.query(` + await db.raw(` DELETE FROM submissions s WHERE draft AND id IN ( SELECT s.id FROM submissions s diff --git a/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js b/lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js similarity index 89% rename from lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js rename to lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js index 506c8f924..9ec11e119 100644 --- a/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js +++ b/lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query('ALTER TABLE ds_property_fields DROP COLUMN "schemaId"'); + await db.raw('ALTER TABLE ds_property_fields DROP COLUMN "schemaId"'); }; const down = () => {}; diff --git a/lib/model/migrations/20230824-01-add-entity-version.js b/lib/model/migrations/legacy/20230824-01-add-entity-version.js similarity index 82% rename from lib/model/migrations/20230824-01-add-entity-version.js rename to lib/model/migrations/legacy/20230824-01-add-entity-version.js index 4f8437a4a..f5ddc8650 100644 --- a/lib/model/migrations/20230824-01-add-entity-version.js +++ b/lib/model/migrations/legacy/20230824-01-add-entity-version.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query('ALTER TABLE entity_defs ADD COLUMN version INT4 NOT NULL DEFAULT 1'); + await db.raw('ALTER TABLE entity_defs ADD COLUMN version INT4 NOT NULL DEFAULT 1'); // Sets the correct version number for existing entities - await db.query(` + await db.raw(` UPDATE entity_defs SET "version" = vt.rownumber FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY "entityId" ORDER BY id ) rownumber, id FROM entity_defs @@ -20,6 +20,6 @@ const up = async (db) => { `); }; -const down = (db) => db.query('ALTER TABLE entity_defs DROP COLUMN version'); +const down = (db) => db.raw('ALTER TABLE entity_defs DROP COLUMN version'); module.exports = { up, down }; diff --git a/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js b/lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js similarity index 95% rename from lib/model/migrations/20230830-01-remove-entity-label-from-audits.js rename to lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js index 5ab55b8cd..0360602e3 100644 --- a/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js +++ b/lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` update audits set details=(details #- '{entity,label}') where action='entity.create'`); diff --git a/lib/model/migrations/20230907-01-opened-form-verb.js b/lib/model/migrations/legacy/20230907-01-opened-form-verb.js similarity index 93% rename from lib/model/migrations/20230907-01-opened-form-verb.js rename to lib/model/migrations/legacy/20230907-01-opened-form-verb.js index a86371e5e..be295a859 100644 --- a/lib/model/migrations/20230907-01-opened-form-verb.js +++ b/lib/model/migrations/legacy/20230907-01-opened-form-verb.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE roles SET verbs = REPLACE(verbs ::TEXT, 'form', 'open_form')::JSONB WHERE system IN ('app-user', 'formview', 'formfill', 'pub-link')`); -const down = (db) => db.query(` +const down = (db) => db.raw(` UPDATE roles SET verbs = REPLACE(verbs ::TEXT, 'open_form', 'form')::JSONB WHERE system IN ('app-user', 'formview', 'formfill', 'pub-link')`); diff --git a/lib/model/migrations/20231002-01-add-conflict-details.js b/lib/model/migrations/legacy/20231002-01-add-conflict-details.js similarity index 66% rename from lib/model/migrations/20231002-01-add-conflict-details.js rename to lib/model/migrations/legacy/20231002-01-add-conflict-details.js index 88004dab2..3c232d391 100644 --- a/lib/model/migrations/20231002-01-add-conflict-details.js +++ b/lib/model/migrations/legacy/20231002-01-add-conflict-details.js @@ -8,11 +8,11 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query(`CREATE TYPE "conflictType" AS ENUM ('soft', 'hard')`); + await db.raw(`CREATE TYPE "conflictType" AS ENUM ('soft', 'hard')`); - await db.query('ALTER TABLE entities ADD COLUMN conflict "conflictType" NULL'); + await db.raw('ALTER TABLE entities ADD COLUMN conflict "conflictType" NULL'); - await db.query(`ALTER TABLE entity_defs + await db.raw(`ALTER TABLE entity_defs ADD COLUMN "dataReceived" JSONB NOT NULL DEFAULT '{}'::jsonb, -- null means, it's a first version @@ -25,13 +25,13 @@ const up = async (db) => { `); // Sets the value for "dataReceived" and "baseVersion" for existing row - await db.query(`UPDATE entity_defs SET "dataReceived" = data || jsonb_build_object('label', "label"), "baseVersion" = CASE WHEN version > 1 THEN version - 1 ELSE NULL END`); + await db.raw(`UPDATE entity_defs SET "dataReceived" = data || jsonb_build_object('label', "label"), "baseVersion" = CASE WHEN version > 1 THEN version - 1 ELSE NULL END`); }; const down = async (db) => { - await db.query('ALTER TABLE entities DROP COLUMN conflict'); - await db.query('ALTER TABLE entity_defs DROP COLUMN "dataReceived", DROP COLUMN "baseVersion"'); + await db.raw('ALTER TABLE entities DROP COLUMN conflict'); + await db.raw('ALTER TABLE entity_defs DROP COLUMN "dataReceived", DROP COLUMN "baseVersion"'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20231013-01-change-entity-error-action.js b/lib/model/migrations/legacy/20231013-01-change-entity-error-action.js similarity index 77% rename from lib/model/migrations/20231013-01-change-entity-error-action.js rename to lib/model/migrations/legacy/20231013-01-change-entity-error-action.js index fb4b198d3..e52fbd6e8 100644 --- a/lib/model/migrations/20231013-01-change-entity-error-action.js +++ b/lib/model/migrations/legacy/20231013-01-change-entity-error-action.js @@ -8,12 +8,12 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query('UPDATE audits SET "action" = \'entity.error\' WHERE "action" = \'entity.create.error\''); + await db.raw('UPDATE audits SET "action" = \'entity.error\' WHERE "action" = \'entity.create.error\''); }; const down = async (db) => { // will set any error back to create error, which isn't necessarily right - await db.query('UPDATE audits SET "action" = \'entity.create.error\' WHERE "action" = \'entity.error\''); + await db.raw('UPDATE audits SET "action" = \'entity.create.error\' WHERE "action" = \'entity.error\''); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20231208-01-dataset-form-def-actions.js b/lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js similarity index 68% rename from lib/model/migrations/20231208-01-dataset-form-def-actions.js rename to lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js index 411efbccb..c6a3cf7bf 100644 --- a/lib/model/migrations/20231208-01-dataset-form-def-actions.js +++ b/lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js @@ -8,12 +8,12 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query('ALTER TABLE dataset_form_defs ADD COLUMN actions jsonb'); - await db.query(`UPDATE dataset_form_defs SET actions = '["create"]'`); - await db.query('ALTER TABLE dataset_form_defs ALTER COLUMN actions SET NOT NULL'); + await db.raw('ALTER TABLE dataset_form_defs ADD COLUMN actions jsonb'); + await db.raw(`UPDATE dataset_form_defs SET actions = '["create"]'`); + await db.raw('ALTER TABLE dataset_form_defs ALTER COLUMN actions SET NOT NULL'); }; const down = (db) => - db.query('ALTER TABLE dataset_form_defs DROP COLUMN actions'); + db.raw('ALTER TABLE dataset_form_defs DROP COLUMN actions'); module.exports = { up, down }; diff --git a/lib/model/migrations/20240215-01-entity-delete-verb.js b/lib/model/migrations/legacy/20240215-01-entity-delete-verb.js similarity index 92% rename from lib/model/migrations/20240215-01-entity-delete-verb.js rename to lib/model/migrations/legacy/20240215-01-entity-delete-verb.js index c66cc8c84..da83905a9 100644 --- a/lib/model/migrations/20240215-01-entity-delete-verb.js +++ b/lib/model/migrations/legacy/20240215-01-entity-delete-verb.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE roles SET verbs = verbs || '["entity.delete"]'::jsonb WHERE system IN ('admin', 'manager')`); -const down = (db) => db.query(` +const down = (db) => db.raw(` UPDATE roles SET verbs = verbs - 'entity.delete' WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/20240215-02-dedupe-verbs.js b/lib/model/migrations/legacy/20240215-02-dedupe-verbs.js similarity index 96% rename from lib/model/migrations/20240215-02-dedupe-verbs.js rename to lib/model/migrations/legacy/20240215-02-dedupe-verbs.js index 3287227a2..cf81984ca 100644 --- a/lib/model/migrations/20240215-02-dedupe-verbs.js +++ b/lib/model/migrations/legacy/20240215-02-dedupe-verbs.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE roles SET verbs = (verbs - 'submission.update') || '["submission.update"]'::jsonb WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/20240312-01-add-dataset-create-verb.js b/lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js similarity index 92% rename from lib/model/migrations/20240312-01-add-dataset-create-verb.js rename to lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js index c02e770ed..58d6e76c6 100644 --- a/lib/model/migrations/20240312-01-add-dataset-create-verb.js +++ b/lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE roles SET verbs = verbs || '["dataset.create"]'::jsonb WHERE system in ('admin', 'manager') `); -const down = (db) => db.query(` +const down = (db) => db.raw(` UPDATE roles SET verbs = (verbs - 'dataset.create') WHERE system in ('admin', 'manager') diff --git a/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js b/lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js similarity index 62% rename from lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js rename to lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js index 590411861..a68d78c38 100644 --- a/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js +++ b/lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query("CREATE INDEX audits_details_entity_def_index ON audits USING HASH (((details ->> 'entityDefId')::INTEGER))"); - await db.query("CREATE INDEX audits_details_entity_source_index ON audits USING HASH (((details ->> 'sourceId')::INTEGER))"); + await db.raw("CREATE INDEX audits_details_entity_def_index ON audits USING HASH (((details ->> 'entityDefId')::INTEGER))"); + await db.raw("CREATE INDEX audits_details_entity_source_index ON audits USING HASH (((details ->> 'sourceId')::INTEGER))"); }; const down = async (db) => { - await db.query('DROP INDEX audits_details_entity_def_index'); - await db.query('DROP INDEX audits_details_entity_source_index'); + await db.raw('DROP INDEX audits_details_entity_def_index'); + await db.raw('DROP INDEX audits_details_entity_source_index'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20240515-01-entity-tz-precision.js b/lib/model/migrations/legacy/20240515-01-entity-tz-precision.js similarity index 79% rename from lib/model/migrations/20240515-01-entity-tz-precision.js rename to lib/model/migrations/legacy/20240515-01-entity-tz-precision.js index 1db2bdc63..3b76190e8 100644 --- a/lib/model/migrations/20240515-01-entity-tz-precision.js +++ b/lib/model/migrations/legacy/20240515-01-entity-tz-precision.js @@ -8,11 +8,11 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamptz(3)'); + await db.raw('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamptz(3)'); }; const down = async (db) => { - await db.query('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamp'); + await db.raw('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamp'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js b/lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js similarity index 89% rename from lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js rename to lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js index 873614b09..a0fe0acbd 100644 --- a/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js +++ b/lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query(`ALTER TABLE entity_defs + await db.raw(`ALTER TABLE entity_defs ADD COLUMN "branchId" UUID, ADD COLUMN "trunkVersion" INT4, ADD COLUMN "branchBaseVersion" INT4`); }; -const down = (db) => db.query(`ALTER TABLE entity_defs +const down = (db) => db.raw(`ALTER TABLE entity_defs DROP COLUMN "branchId", DROP COLUMN "trunkVersion", DROP COLUMN "branchBaseVersion" diff --git a/lib/model/migrations/20240607-02-add-submission-backlog.js b/lib/model/migrations/legacy/20240607-02-add-submission-backlog.js similarity index 89% rename from lib/model/migrations/20240607-02-add-submission-backlog.js rename to lib/model/migrations/legacy/20240607-02-add-submission-backlog.js index 5c712ebf1..0cda52ed5 100644 --- a/lib/model/migrations/20240607-02-add-submission-backlog.js +++ b/lib/model/migrations/legacy/20240607-02-add-submission-backlog.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query(`CREATE TABLE entity_submission_backlog ( + await db.raw(`CREATE TABLE entity_submission_backlog ( "submissionId" INT4 NOT NULL, "submissionDefId" INT4 NOT NULL, "branchId" UUID NOT NULL, @@ -26,6 +26,6 @@ const up = async (db) => { )`); }; -const down = (db) => db.query('DROP TABLE entity_submission_backlog'); +const down = (db) => db.raw('DROP TABLE entity_submission_backlog'); module.exports = { up, down }; diff --git a/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js b/lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js similarity index 87% rename from lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js rename to lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js index 284d6a3aa..2915d90e8 100644 --- a/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js +++ b/lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query(`ALTER TABLE entity_submission_backlog + await db.raw(`ALTER TABLE entity_submission_backlog ADD COLUMN "auditId" INT4 NOT NULL, ADD COLUMN "entityUuid" UUID NOT NULL, ADD CONSTRAINT fk_audit_id @@ -17,7 +17,7 @@ const up = async (db) => { ON DELETE CASCADE`); }; -const down = (db) => db.query(`ALTER TABLE entity_submission_backlog +const down = (db) => db.raw(`ALTER TABLE entity_submission_backlog DROP COLUMN "auditId", DROP COLUMN "entityUuid" `); diff --git a/lib/model/migrations/20240913-01-add-blob-s3.js b/lib/model/migrations/legacy/20240913-01-add-blob-s3.js similarity index 87% rename from lib/model/migrations/20240913-01-add-blob-s3.js rename to lib/model/migrations/legacy/20240913-01-add-blob-s3.js index a34590bf7..048f31b4a 100644 --- a/lib/model/migrations/20240913-01-add-blob-s3.js +++ b/lib/model/migrations/legacy/20240913-01-add-blob-s3.js @@ -8,8 +8,8 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.query(`CREATE TYPE S3_UPLOAD_STATUS AS ENUM ('pending', 'uploaded', 'failed')`); - await db.query(` + await db.raw(`CREATE TYPE S3_UPLOAD_STATUS AS ENUM ('pending', 'uploaded', 'failed')`); + await db.raw(` ALTER TABLE blobs ADD COLUMN s3_status S3_UPLOAD_STATUS NOT NULL DEFAULT 'pending', ALTER COLUMN content DROP NOT NULL diff --git a/lib/model/migrations/20240914-01-add-submission-delete-verb.js b/lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js similarity index 93% rename from lib/model/migrations/20240914-01-add-submission-delete-verb.js rename to lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js index 7b308162c..d9bf1f7bd 100644 --- a/lib/model/migrations/20240914-01-add-submission-delete-verb.js +++ b/lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE roles SET verbs = verbs || '["submission.delete", "submission.restore"]'::jsonb WHERE system in ('admin', 'manager') `); -const down = (db) => db.query(` +const down = (db) => db.raw(` UPDATE roles SET verbs = (verbs - 'submission.delete' - 'submission.restore') WHERE system in ('admin', 'manager') diff --git a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js b/lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js similarity index 97% rename from lib/model/migrations/20240914-02-remove-orphaned-client-audits.js rename to lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js index ee603c1f2..9dd633a71 100644 --- a/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js +++ b/lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js @@ -12,7 +12,7 @@ // This migration deletes those client audit rows, allowing the blobs to finally // be de-referenced and also eventually purged (by the puring cron job). -const up = (db) => db.query(` +const up = (db) => db.raw(` DELETE FROM client_audits WHERE "blobId" NOT IN ( SELECT "blobId" FROM submission_attachments diff --git a/lib/model/migrations/20241001-01-index-on-session-table.js b/lib/model/migrations/legacy/20241001-01-index-on-session-table.js similarity index 91% rename from lib/model/migrations/20241001-01-index-on-session-table.js rename to lib/model/migrations/legacy/20241001-01-index-on-session-table.js index 6aa507330..d1b8f00a4 100644 --- a/lib/model/migrations/20241001-01-index-on-session-table.js +++ b/lib/model/migrations/legacy/20241001-01-index-on-session-table.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` CREATE UNIQUE INDEX "sessions_token_index" ON sessions (token); `); -const down = (db) => db.query(` +const down = (db) => db.raw(` DROP INDEX "sessions_token_index"; `); diff --git a/lib/model/migrations/20241008-01-add-user_preferences.js b/lib/model/migrations/legacy/20241008-01-add-user_preferences.js similarity index 96% rename from lib/model/migrations/20241008-01-add-user_preferences.js rename to lib/model/migrations/legacy/20241008-01-add-user_preferences.js index 3b7564883..94862cfba 100644 --- a/lib/model/migrations/20241008-01-add-user_preferences.js +++ b/lib/model/migrations/legacy/20241008-01-add-user_preferences.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` CREATE TABLE user_site_preferences ( "userId" integer NOT NULL REFERENCES users ("actorId"), "propertyName" text NOT NULL CHECK (length("propertyName") > 0), @@ -29,7 +29,7 @@ const up = (db) => db.query(` CREATE INDEX ON "user_project_preferences" ("userId"); `); -const down = (db) => db.query(` +const down = (db) => db.raw(` DROP TABLE user_site_preferences; DROP TABLE user_project_preferences; `); diff --git a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js b/lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js similarity index 97% rename from lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js rename to lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js index 1538cfd54..1aa35ac5f 100644 --- a/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js +++ b/lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` INSERT INTO audits ("action", "acteeId", "loggedAt", "details") SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' diff --git a/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js b/lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js similarity index 98% rename from lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js rename to lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js index 34b004ad7..793898943 100644 --- a/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js +++ b/lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js @@ -15,7 +15,7 @@ // Basically, every existing form should be flagged, but I didn't want // to change an old migration. -const up = (db) => db.query(` +const up = (db) => db.raw(` INSERT INTO audits ("action", "acteeId", "loggedAt", "details") SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' diff --git a/lib/model/migrations/20241030-01-add-force-entity-def-source.js b/lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js similarity index 92% rename from lib/model/migrations/20241030-01-add-force-entity-def-source.js rename to lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js index 4b77c05d5..1c54134c5 100644 --- a/lib/model/migrations/20241030-01-add-force-entity-def-source.js +++ b/lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` ALTER TABLE entity_def_sources ADD COLUMN "forceProcessed" BOOLEAN `); -const down = (db) => db.query(` +const down = (db) => db.raw(` ALTER TABLE entity_def_sources DROP COLUMN "forceProcessed" `); diff --git a/lib/model/migrations/20241224-01-entity-restore-verb.js b/lib/model/migrations/legacy/20241224-01-entity-restore-verb.js similarity index 92% rename from lib/model/migrations/20241224-01-entity-restore-verb.js rename to lib/model/migrations/legacy/20241224-01-entity-restore-verb.js index 7d73d48e0..5d948899c 100644 --- a/lib/model/migrations/20241224-01-entity-restore-verb.js +++ b/lib/model/migrations/legacy/20241224-01-entity-restore-verb.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE roles SET verbs = verbs || '["entity.restore"]'::jsonb WHERE system IN ('admin', 'manager')`); -const down = (db) => db.query(` +const down = (db) => db.raw(` UPDATE roles SET verbs = verbs - 'entity.restore' WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/20241224-02-cascade-entity-purge.js b/lib/model/migrations/legacy/20241224-02-cascade-entity-purge.js similarity index 94% rename from lib/model/migrations/20241224-02-cascade-entity-purge.js rename to lib/model/migrations/legacy/20241224-02-cascade-entity-purge.js index 4a359995b..7d39083c2 100644 --- a/lib/model/migrations/20241224-02-cascade-entity-purge.js +++ b/lib/model/migrations/legacy/20241224-02-cascade-entity-purge.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` ALTER TABLE public.entity_defs DROP CONSTRAINT entity_defs_entityid_foreign; ALTER TABLE public.entity_defs ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id) ON DELETE CASCADE; `); -const down = ((db) => db.query(` +const down = ((db) => db.raw(` ALTER TABLE public.entity_defs DROP CONSTRAINT entity_defs_entityid_foreign; ALTER TABLE public.entity_defs ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id); `)); diff --git a/lib/model/migrations/20241226-01-indices-for-purging-entities.js b/lib/model/migrations/legacy/20241226-01-indices-for-purging-entities.js similarity index 94% rename from lib/model/migrations/20241226-01-indices-for-purging-entities.js rename to lib/model/migrations/legacy/20241226-01-indices-for-purging-entities.js index 47ba7e551..6ca38cc66 100644 --- a/lib/model/migrations/20241226-01-indices-for-purging-entities.js +++ b/lib/model/migrations/legacy/20241226-01-indices-for-purging-entities.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` CREATE INDEX audits_details_entity_uuid ON public.audits USING hash ((details->'entity'->>'uuid')) WHERE ACTION IN ('entity.create', 'entity.update', 'entity.update.version', 'entity.update.resolve', 'entity.delete', 'entity.restore'); @@ -15,7 +15,7 @@ CREATE INDEX audits_details_entityUuids ON audits USING gin ((details -> 'entity WHERE ACTION = 'entity.purge'; `); -const down = ((db) => db.query(` +const down = ((db) => db.raw(` DROP INDEX audits_details_entity_uuid; DROP INDEX audits_details_entityUuids; `)); diff --git a/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js b/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js similarity index 96% rename from lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js rename to lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js index 0e4d8cbce..1284d58b5 100644 --- a/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js +++ b/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.query(` +const up = (db) => db.raw(` UPDATE audits SET details = ('{ "entity":{ "uuid":"' || (details->>'uuid') || '"}}')::JSONB WHERE action = 'entity.delete' AND details ? 'uuid'; `); From 514d18067e286857a25030815aaaaec56256ce31 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:46:08 +0000 Subject: [PATCH 113/133] partial --- .github/workflows/db-partial-migrations.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index b6bd22395..f3875541f 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -18,7 +18,10 @@ jobs: - legacy-first-100 - legacy-all - new-first-1-as-legacy - - new-first-10-as-legacy + - new-first-2-as-legacy + - new-first-3-as-legacy + - new-first-4-as-legacy + - new-first-5-as-legacy - all timeout-minutes: 2 # TODO should we use the same container as circle & central? From 201515aeb1d16260c0ee4debb7d223d38530d070 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:52:09 +0000 Subject: [PATCH 114/133] try different syntax for JSONB_EXISTS --- .../migrations/legacy/20241227-01-backfill-audit-entity-uuid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js b/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js index 1284d58b5..e944d0054 100644 --- a/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js +++ b/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js @@ -9,7 +9,7 @@ const up = (db) => db.raw(` UPDATE audits SET details = ('{ "entity":{ "uuid":"' || (details->>'uuid') || '"}}')::JSONB -WHERE action = 'entity.delete' AND details ? 'uuid'; +WHERE action = 'entity.delete' AND JSONB_EXISTS(details, 'uuid'); `); const down = () => {}; From 19c8eadcfaeb2efc21b23860cd35a2d4ddab5bd2 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:53:02 +0000 Subject: [PATCH 115/133] Revert "revert some legacy to legacy" This reverts commit f984324d6c275144ab12ca7602950b08c97b8378. --- .../20230802-01-delete-orphan-submissions.js | 2 +- ...30818-01-remove-schemaId-from-dsPropertyFields.js | 2 +- .../{legacy => }/20230824-01-add-entity-version.js | 6 +++--- .../20230830-01-remove-entity-label-from-audits.js | 2 +- .../{legacy => }/20230907-01-opened-form-verb.js | 4 ++-- .../{legacy => }/20231002-01-add-conflict-details.js | 12 ++++++------ .../20231013-01-change-entity-error-action.js | 4 ++-- .../20231208-01-dataset-form-def-actions.js | 8 ++++---- .../{legacy => }/20240215-01-entity-delete-verb.js | 4 ++-- .../{legacy => }/20240215-02-dedupe-verbs.js | 2 +- .../20240312-01-add-dataset-create-verb.js | 4 ++-- .../20240322-01-add-entity-source-index-to-audits.js | 8 ++++---- .../{legacy => }/20240515-01-entity-tz-precision.js | 4 ++-- ...240607-01-add-offline-entity-branch-trunk-info.js | 4 ++-- .../20240607-02-add-submission-backlog.js | 4 ++-- .../20240715-01-backlog-add-event-entityuuid.js | 4 ++-- .../{legacy => }/20240913-01-add-blob-s3.js | 4 ++-- .../20240914-01-add-submission-delete-verb.js | 4 ++-- .../20240914-02-remove-orphaned-client-audits.js | 2 +- .../20241001-01-index-on-session-table.js | 4 ++-- .../{legacy => }/20241008-01-add-user_preferences.js | 4 ++-- .../20241010-01-schedule-entity-form-upgrade.js | 2 +- ...9-01-schedule-entity-form-upgrade-create-forms.js | 2 +- .../20241030-01-add-force-entity-def-source.js | 4 ++-- .../{legacy => }/20241224-01-entity-restore-verb.js | 4 ++-- .../{legacy => }/20241224-02-cascade-entity-purge.js | 4 ++-- .../20241226-01-indices-for-purging-entities.js | 4 ++-- .../20241227-01-backfill-audit-entity-uuid.js | 2 +- 28 files changed, 57 insertions(+), 57 deletions(-) rename lib/model/migrations/{legacy => }/20230802-01-delete-orphan-submissions.js (97%) rename lib/model/migrations/{legacy => }/20230818-01-remove-schemaId-from-dsPropertyFields.js (89%) rename lib/model/migrations/{legacy => }/20230824-01-add-entity-version.js (82%) rename lib/model/migrations/{legacy => }/20230830-01-remove-entity-label-from-audits.js (95%) rename lib/model/migrations/{legacy => }/20230907-01-opened-form-verb.js (93%) rename lib/model/migrations/{legacy => }/20231002-01-add-conflict-details.js (66%) rename lib/model/migrations/{legacy => }/20231013-01-change-entity-error-action.js (77%) rename lib/model/migrations/{legacy => }/20231208-01-dataset-form-def-actions.js (68%) rename lib/model/migrations/{legacy => }/20240215-01-entity-delete-verb.js (92%) rename lib/model/migrations/{legacy => }/20240215-02-dedupe-verbs.js (96%) rename lib/model/migrations/{legacy => }/20240312-01-add-dataset-create-verb.js (92%) rename lib/model/migrations/{legacy => }/20240322-01-add-entity-source-index-to-audits.js (62%) rename lib/model/migrations/{legacy => }/20240515-01-entity-tz-precision.js (79%) rename lib/model/migrations/{legacy => }/20240607-01-add-offline-entity-branch-trunk-info.js (89%) rename lib/model/migrations/{legacy => }/20240607-02-add-submission-backlog.js (89%) rename lib/model/migrations/{legacy => }/20240715-01-backlog-add-event-entityuuid.js (87%) rename lib/model/migrations/{legacy => }/20240913-01-add-blob-s3.js (87%) rename lib/model/migrations/{legacy => }/20240914-01-add-submission-delete-verb.js (93%) rename lib/model/migrations/{legacy => }/20240914-02-remove-orphaned-client-audits.js (97%) rename lib/model/migrations/{legacy => }/20241001-01-index-on-session-table.js (91%) rename lib/model/migrations/{legacy => }/20241008-01-add-user_preferences.js (96%) rename lib/model/migrations/{legacy => }/20241010-01-schedule-entity-form-upgrade.js (97%) rename lib/model/migrations/{legacy => }/20241029-01-schedule-entity-form-upgrade-create-forms.js (98%) rename lib/model/migrations/{legacy => }/20241030-01-add-force-entity-def-source.js (92%) rename lib/model/migrations/{legacy => }/20241224-01-entity-restore-verb.js (92%) rename lib/model/migrations/{legacy => }/20241224-02-cascade-entity-purge.js (94%) rename lib/model/migrations/{legacy => }/20241226-01-indices-for-purging-entities.js (94%) rename lib/model/migrations/{legacy => }/20241227-01-backfill-audit-entity-uuid.js (96%) diff --git a/lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js b/lib/model/migrations/20230802-01-delete-orphan-submissions.js similarity index 97% rename from lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js rename to lib/model/migrations/20230802-01-delete-orphan-submissions.js index 39cb1c8e3..9986e0969 100644 --- a/lib/model/migrations/legacy/20230802-01-delete-orphan-submissions.js +++ b/lib/model/migrations/20230802-01-delete-orphan-submissions.js @@ -9,7 +9,7 @@ // Delete draft Submissions that don't have any definition - cb#911 const up = async (db) => { - await db.raw(` + await db.query(` DELETE FROM submissions s WHERE draft AND id IN ( SELECT s.id FROM submissions s diff --git a/lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js b/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js similarity index 89% rename from lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js rename to lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js index 9ec11e119..506c8f924 100644 --- a/lib/model/migrations/legacy/20230818-01-remove-schemaId-from-dsPropertyFields.js +++ b/lib/model/migrations/20230818-01-remove-schemaId-from-dsPropertyFields.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE ds_property_fields DROP COLUMN "schemaId"'); + await db.query('ALTER TABLE ds_property_fields DROP COLUMN "schemaId"'); }; const down = () => {}; diff --git a/lib/model/migrations/legacy/20230824-01-add-entity-version.js b/lib/model/migrations/20230824-01-add-entity-version.js similarity index 82% rename from lib/model/migrations/legacy/20230824-01-add-entity-version.js rename to lib/model/migrations/20230824-01-add-entity-version.js index f5ddc8650..4f8437a4a 100644 --- a/lib/model/migrations/legacy/20230824-01-add-entity-version.js +++ b/lib/model/migrations/20230824-01-add-entity-version.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE entity_defs ADD COLUMN version INT4 NOT NULL DEFAULT 1'); + await db.query('ALTER TABLE entity_defs ADD COLUMN version INT4 NOT NULL DEFAULT 1'); // Sets the correct version number for existing entities - await db.raw(` + await db.query(` UPDATE entity_defs SET "version" = vt.rownumber FROM ( SELECT ROW_NUMBER() OVER(PARTITION BY "entityId" ORDER BY id ) rownumber, id FROM entity_defs @@ -20,6 +20,6 @@ const up = async (db) => { `); }; -const down = (db) => db.raw('ALTER TABLE entity_defs DROP COLUMN version'); +const down = (db) => db.query('ALTER TABLE entity_defs DROP COLUMN version'); module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js b/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js similarity index 95% rename from lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js rename to lib/model/migrations/20230830-01-remove-entity-label-from-audits.js index 0360602e3..5ab55b8cd 100644 --- a/lib/model/migrations/legacy/20230830-01-remove-entity-label-from-audits.js +++ b/lib/model/migrations/20230830-01-remove-entity-label-from-audits.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` update audits set details=(details #- '{entity,label}') where action='entity.create'`); diff --git a/lib/model/migrations/legacy/20230907-01-opened-form-verb.js b/lib/model/migrations/20230907-01-opened-form-verb.js similarity index 93% rename from lib/model/migrations/legacy/20230907-01-opened-form-verb.js rename to lib/model/migrations/20230907-01-opened-form-verb.js index be295a859..a86371e5e 100644 --- a/lib/model/migrations/legacy/20230907-01-opened-form-verb.js +++ b/lib/model/migrations/20230907-01-opened-form-verb.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = REPLACE(verbs ::TEXT, 'form', 'open_form')::JSONB WHERE system IN ('app-user', 'formview', 'formfill', 'pub-link')`); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = REPLACE(verbs ::TEXT, 'open_form', 'form')::JSONB WHERE system IN ('app-user', 'formview', 'formfill', 'pub-link')`); diff --git a/lib/model/migrations/legacy/20231002-01-add-conflict-details.js b/lib/model/migrations/20231002-01-add-conflict-details.js similarity index 66% rename from lib/model/migrations/legacy/20231002-01-add-conflict-details.js rename to lib/model/migrations/20231002-01-add-conflict-details.js index 3c232d391..88004dab2 100644 --- a/lib/model/migrations/legacy/20231002-01-add-conflict-details.js +++ b/lib/model/migrations/20231002-01-add-conflict-details.js @@ -8,11 +8,11 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`CREATE TYPE "conflictType" AS ENUM ('soft', 'hard')`); + await db.query(`CREATE TYPE "conflictType" AS ENUM ('soft', 'hard')`); - await db.raw('ALTER TABLE entities ADD COLUMN conflict "conflictType" NULL'); + await db.query('ALTER TABLE entities ADD COLUMN conflict "conflictType" NULL'); - await db.raw(`ALTER TABLE entity_defs + await db.query(`ALTER TABLE entity_defs ADD COLUMN "dataReceived" JSONB NOT NULL DEFAULT '{}'::jsonb, -- null means, it's a first version @@ -25,13 +25,13 @@ const up = async (db) => { `); // Sets the value for "dataReceived" and "baseVersion" for existing row - await db.raw(`UPDATE entity_defs SET "dataReceived" = data || jsonb_build_object('label', "label"), "baseVersion" = CASE WHEN version > 1 THEN version - 1 ELSE NULL END`); + await db.query(`UPDATE entity_defs SET "dataReceived" = data || jsonb_build_object('label', "label"), "baseVersion" = CASE WHEN version > 1 THEN version - 1 ELSE NULL END`); }; const down = async (db) => { - await db.raw('ALTER TABLE entities DROP COLUMN conflict'); - await db.raw('ALTER TABLE entity_defs DROP COLUMN "dataReceived", DROP COLUMN "baseVersion"'); + await db.query('ALTER TABLE entities DROP COLUMN conflict'); + await db.query('ALTER TABLE entity_defs DROP COLUMN "dataReceived", DROP COLUMN "baseVersion"'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20231013-01-change-entity-error-action.js b/lib/model/migrations/20231013-01-change-entity-error-action.js similarity index 77% rename from lib/model/migrations/legacy/20231013-01-change-entity-error-action.js rename to lib/model/migrations/20231013-01-change-entity-error-action.js index e52fbd6e8..fb4b198d3 100644 --- a/lib/model/migrations/legacy/20231013-01-change-entity-error-action.js +++ b/lib/model/migrations/20231013-01-change-entity-error-action.js @@ -8,12 +8,12 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('UPDATE audits SET "action" = \'entity.error\' WHERE "action" = \'entity.create.error\''); + await db.query('UPDATE audits SET "action" = \'entity.error\' WHERE "action" = \'entity.create.error\''); }; const down = async (db) => { // will set any error back to create error, which isn't necessarily right - await db.raw('UPDATE audits SET "action" = \'entity.create.error\' WHERE "action" = \'entity.error\''); + await db.query('UPDATE audits SET "action" = \'entity.create.error\' WHERE "action" = \'entity.error\''); }; module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js b/lib/model/migrations/20231208-01-dataset-form-def-actions.js similarity index 68% rename from lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js rename to lib/model/migrations/20231208-01-dataset-form-def-actions.js index c6a3cf7bf..411efbccb 100644 --- a/lib/model/migrations/legacy/20231208-01-dataset-form-def-actions.js +++ b/lib/model/migrations/20231208-01-dataset-form-def-actions.js @@ -8,12 +8,12 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE dataset_form_defs ADD COLUMN actions jsonb'); - await db.raw(`UPDATE dataset_form_defs SET actions = '["create"]'`); - await db.raw('ALTER TABLE dataset_form_defs ALTER COLUMN actions SET NOT NULL'); + await db.query('ALTER TABLE dataset_form_defs ADD COLUMN actions jsonb'); + await db.query(`UPDATE dataset_form_defs SET actions = '["create"]'`); + await db.query('ALTER TABLE dataset_form_defs ALTER COLUMN actions SET NOT NULL'); }; const down = (db) => - db.raw('ALTER TABLE dataset_form_defs DROP COLUMN actions'); + db.query('ALTER TABLE dataset_form_defs DROP COLUMN actions'); module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20240215-01-entity-delete-verb.js b/lib/model/migrations/20240215-01-entity-delete-verb.js similarity index 92% rename from lib/model/migrations/legacy/20240215-01-entity-delete-verb.js rename to lib/model/migrations/20240215-01-entity-delete-verb.js index da83905a9..c66cc8c84 100644 --- a/lib/model/migrations/legacy/20240215-01-entity-delete-verb.js +++ b/lib/model/migrations/20240215-01-entity-delete-verb.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["entity.delete"]'::jsonb WHERE system IN ('admin', 'manager')`); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = verbs - 'entity.delete' WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/legacy/20240215-02-dedupe-verbs.js b/lib/model/migrations/20240215-02-dedupe-verbs.js similarity index 96% rename from lib/model/migrations/legacy/20240215-02-dedupe-verbs.js rename to lib/model/migrations/20240215-02-dedupe-verbs.js index cf81984ca..3287227a2 100644 --- a/lib/model/migrations/legacy/20240215-02-dedupe-verbs.js +++ b/lib/model/migrations/20240215-02-dedupe-verbs.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = (verbs - 'submission.update') || '["submission.update"]'::jsonb WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js b/lib/model/migrations/20240312-01-add-dataset-create-verb.js similarity index 92% rename from lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js rename to lib/model/migrations/20240312-01-add-dataset-create-verb.js index 58d6e76c6..c02e770ed 100644 --- a/lib/model/migrations/legacy/20240312-01-add-dataset-create-verb.js +++ b/lib/model/migrations/20240312-01-add-dataset-create-verb.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["dataset.create"]'::jsonb WHERE system in ('admin', 'manager') `); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = (verbs - 'dataset.create') WHERE system in ('admin', 'manager') diff --git a/lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js b/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js similarity index 62% rename from lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js rename to lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js index a68d78c38..590411861 100644 --- a/lib/model/migrations/legacy/20240322-01-add-entity-source-index-to-audits.js +++ b/lib/model/migrations/20240322-01-add-entity-source-index-to-audits.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw("CREATE INDEX audits_details_entity_def_index ON audits USING HASH (((details ->> 'entityDefId')::INTEGER))"); - await db.raw("CREATE INDEX audits_details_entity_source_index ON audits USING HASH (((details ->> 'sourceId')::INTEGER))"); + await db.query("CREATE INDEX audits_details_entity_def_index ON audits USING HASH (((details ->> 'entityDefId')::INTEGER))"); + await db.query("CREATE INDEX audits_details_entity_source_index ON audits USING HASH (((details ->> 'sourceId')::INTEGER))"); }; const down = async (db) => { - await db.raw('DROP INDEX audits_details_entity_def_index'); - await db.raw('DROP INDEX audits_details_entity_source_index'); + await db.query('DROP INDEX audits_details_entity_def_index'); + await db.query('DROP INDEX audits_details_entity_source_index'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20240515-01-entity-tz-precision.js b/lib/model/migrations/20240515-01-entity-tz-precision.js similarity index 79% rename from lib/model/migrations/legacy/20240515-01-entity-tz-precision.js rename to lib/model/migrations/20240515-01-entity-tz-precision.js index 3b76190e8..1db2bdc63 100644 --- a/lib/model/migrations/legacy/20240515-01-entity-tz-precision.js +++ b/lib/model/migrations/20240515-01-entity-tz-precision.js @@ -8,11 +8,11 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamptz(3)'); + await db.query('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamptz(3)'); }; const down = async (db) => { - await db.raw('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamp'); + await db.query('ALTER TABLE entities ALTER COLUMN "deletedAt" TYPE timestamp'); }; module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js b/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js similarity index 89% rename from lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js rename to lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js index a0fe0acbd..873614b09 100644 --- a/lib/model/migrations/legacy/20240607-01-add-offline-entity-branch-trunk-info.js +++ b/lib/model/migrations/20240607-01-add-offline-entity-branch-trunk-info.js @@ -8,13 +8,13 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`ALTER TABLE entity_defs + await db.query(`ALTER TABLE entity_defs ADD COLUMN "branchId" UUID, ADD COLUMN "trunkVersion" INT4, ADD COLUMN "branchBaseVersion" INT4`); }; -const down = (db) => db.raw(`ALTER TABLE entity_defs +const down = (db) => db.query(`ALTER TABLE entity_defs DROP COLUMN "branchId", DROP COLUMN "trunkVersion", DROP COLUMN "branchBaseVersion" diff --git a/lib/model/migrations/legacy/20240607-02-add-submission-backlog.js b/lib/model/migrations/20240607-02-add-submission-backlog.js similarity index 89% rename from lib/model/migrations/legacy/20240607-02-add-submission-backlog.js rename to lib/model/migrations/20240607-02-add-submission-backlog.js index 0cda52ed5..5c712ebf1 100644 --- a/lib/model/migrations/legacy/20240607-02-add-submission-backlog.js +++ b/lib/model/migrations/20240607-02-add-submission-backlog.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`CREATE TABLE entity_submission_backlog ( + await db.query(`CREATE TABLE entity_submission_backlog ( "submissionId" INT4 NOT NULL, "submissionDefId" INT4 NOT NULL, "branchId" UUID NOT NULL, @@ -26,6 +26,6 @@ const up = async (db) => { )`); }; -const down = (db) => db.raw('DROP TABLE entity_submission_backlog'); +const down = (db) => db.query('DROP TABLE entity_submission_backlog'); module.exports = { up, down }; diff --git a/lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js b/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js similarity index 87% rename from lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js rename to lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js index 2915d90e8..284d6a3aa 100644 --- a/lib/model/migrations/legacy/20240715-01-backlog-add-event-entityuuid.js +++ b/lib/model/migrations/20240715-01-backlog-add-event-entityuuid.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`ALTER TABLE entity_submission_backlog + await db.query(`ALTER TABLE entity_submission_backlog ADD COLUMN "auditId" INT4 NOT NULL, ADD COLUMN "entityUuid" UUID NOT NULL, ADD CONSTRAINT fk_audit_id @@ -17,7 +17,7 @@ const up = async (db) => { ON DELETE CASCADE`); }; -const down = (db) => db.raw(`ALTER TABLE entity_submission_backlog +const down = (db) => db.query(`ALTER TABLE entity_submission_backlog DROP COLUMN "auditId", DROP COLUMN "entityUuid" `); diff --git a/lib/model/migrations/legacy/20240913-01-add-blob-s3.js b/lib/model/migrations/20240913-01-add-blob-s3.js similarity index 87% rename from lib/model/migrations/legacy/20240913-01-add-blob-s3.js rename to lib/model/migrations/20240913-01-add-blob-s3.js index 048f31b4a..a34590bf7 100644 --- a/lib/model/migrations/legacy/20240913-01-add-blob-s3.js +++ b/lib/model/migrations/20240913-01-add-blob-s3.js @@ -8,8 +8,8 @@ // except according to the terms contained in the LICENSE file. const up = async (db) => { - await db.raw(`CREATE TYPE S3_UPLOAD_STATUS AS ENUM ('pending', 'uploaded', 'failed')`); - await db.raw(` + await db.query(`CREATE TYPE S3_UPLOAD_STATUS AS ENUM ('pending', 'uploaded', 'failed')`); + await db.query(` ALTER TABLE blobs ADD COLUMN s3_status S3_UPLOAD_STATUS NOT NULL DEFAULT 'pending', ALTER COLUMN content DROP NOT NULL diff --git a/lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js b/lib/model/migrations/20240914-01-add-submission-delete-verb.js similarity index 93% rename from lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js rename to lib/model/migrations/20240914-01-add-submission-delete-verb.js index d9bf1f7bd..7b308162c 100644 --- a/lib/model/migrations/legacy/20240914-01-add-submission-delete-verb.js +++ b/lib/model/migrations/20240914-01-add-submission-delete-verb.js @@ -7,13 +7,13 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["submission.delete", "submission.restore"]'::jsonb WHERE system in ('admin', 'manager') `); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = (verbs - 'submission.delete' - 'submission.restore') WHERE system in ('admin', 'manager') diff --git a/lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js similarity index 97% rename from lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js rename to lib/model/migrations/20240914-02-remove-orphaned-client-audits.js index 9dd633a71..ee603c1f2 100644 --- a/lib/model/migrations/legacy/20240914-02-remove-orphaned-client-audits.js +++ b/lib/model/migrations/20240914-02-remove-orphaned-client-audits.js @@ -12,7 +12,7 @@ // This migration deletes those client audit rows, allowing the blobs to finally // be de-referenced and also eventually purged (by the puring cron job). -const up = (db) => db.raw(` +const up = (db) => db.query(` DELETE FROM client_audits WHERE "blobId" NOT IN ( SELECT "blobId" FROM submission_attachments diff --git a/lib/model/migrations/legacy/20241001-01-index-on-session-table.js b/lib/model/migrations/20241001-01-index-on-session-table.js similarity index 91% rename from lib/model/migrations/legacy/20241001-01-index-on-session-table.js rename to lib/model/migrations/20241001-01-index-on-session-table.js index d1b8f00a4..6aa507330 100644 --- a/lib/model/migrations/legacy/20241001-01-index-on-session-table.js +++ b/lib/model/migrations/20241001-01-index-on-session-table.js @@ -7,11 +7,11 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` CREATE UNIQUE INDEX "sessions_token_index" ON sessions (token); `); -const down = (db) => db.raw(` +const down = (db) => db.query(` DROP INDEX "sessions_token_index"; `); diff --git a/lib/model/migrations/legacy/20241008-01-add-user_preferences.js b/lib/model/migrations/20241008-01-add-user_preferences.js similarity index 96% rename from lib/model/migrations/legacy/20241008-01-add-user_preferences.js rename to lib/model/migrations/20241008-01-add-user_preferences.js index 94862cfba..3b7564883 100644 --- a/lib/model/migrations/legacy/20241008-01-add-user_preferences.js +++ b/lib/model/migrations/20241008-01-add-user_preferences.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` CREATE TABLE user_site_preferences ( "userId" integer NOT NULL REFERENCES users ("actorId"), "propertyName" text NOT NULL CHECK (length("propertyName") > 0), @@ -29,7 +29,7 @@ const up = (db) => db.raw(` CREATE INDEX ON "user_project_preferences" ("userId"); `); -const down = (db) => db.raw(` +const down = (db) => db.query(` DROP TABLE user_site_preferences; DROP TABLE user_project_preferences; `); diff --git a/lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js similarity index 97% rename from lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js rename to lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js index 1aa35ac5f..1538cfd54 100644 --- a/lib/model/migrations/legacy/20241010-01-schedule-entity-form-upgrade.js +++ b/lib/model/migrations/20241010-01-schedule-entity-form-upgrade.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` INSERT INTO audits ("action", "acteeId", "loggedAt", "details") SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' diff --git a/lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js b/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js similarity index 98% rename from lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js rename to lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js index 793898943..34b004ad7 100644 --- a/lib/model/migrations/legacy/20241029-01-schedule-entity-form-upgrade-create-forms.js +++ b/lib/model/migrations/20241029-01-schedule-entity-form-upgrade-create-forms.js @@ -15,7 +15,7 @@ // Basically, every existing form should be flagged, but I didn't want // to change an old migration. -const up = (db) => db.raw(` +const up = (db) => db.query(` INSERT INTO audits ("action", "acteeId", "loggedAt", "details") SELECT 'upgrade.process.form.entities_version', forms."acteeId", clock_timestamp(), '{"upgrade": "As part of upgrading Central to v2024.3, this form is being updated to the latest entities-version spec."}' diff --git a/lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js b/lib/model/migrations/20241030-01-add-force-entity-def-source.js similarity index 92% rename from lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js rename to lib/model/migrations/20241030-01-add-force-entity-def-source.js index 1c54134c5..4b77c05d5 100644 --- a/lib/model/migrations/legacy/20241030-01-add-force-entity-def-source.js +++ b/lib/model/migrations/20241030-01-add-force-entity-def-source.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` ALTER TABLE entity_def_sources ADD COLUMN "forceProcessed" BOOLEAN `); -const down = (db) => db.raw(` +const down = (db) => db.query(` ALTER TABLE entity_def_sources DROP COLUMN "forceProcessed" `); diff --git a/lib/model/migrations/legacy/20241224-01-entity-restore-verb.js b/lib/model/migrations/20241224-01-entity-restore-verb.js similarity index 92% rename from lib/model/migrations/legacy/20241224-01-entity-restore-verb.js rename to lib/model/migrations/20241224-01-entity-restore-verb.js index 5d948899c..7d73d48e0 100644 --- a/lib/model/migrations/legacy/20241224-01-entity-restore-verb.js +++ b/lib/model/migrations/20241224-01-entity-restore-verb.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE roles SET verbs = verbs || '["entity.restore"]'::jsonb WHERE system IN ('admin', 'manager')`); -const down = (db) => db.raw(` +const down = (db) => db.query(` UPDATE roles SET verbs = verbs - 'entity.restore' WHERE system IN ('admin', 'manager')`); diff --git a/lib/model/migrations/legacy/20241224-02-cascade-entity-purge.js b/lib/model/migrations/20241224-02-cascade-entity-purge.js similarity index 94% rename from lib/model/migrations/legacy/20241224-02-cascade-entity-purge.js rename to lib/model/migrations/20241224-02-cascade-entity-purge.js index 7d39083c2..4a359995b 100644 --- a/lib/model/migrations/legacy/20241224-02-cascade-entity-purge.js +++ b/lib/model/migrations/20241224-02-cascade-entity-purge.js @@ -7,12 +7,12 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` ALTER TABLE public.entity_defs DROP CONSTRAINT entity_defs_entityid_foreign; ALTER TABLE public.entity_defs ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id) ON DELETE CASCADE; `); -const down = ((db) => db.raw(` +const down = ((db) => db.query(` ALTER TABLE public.entity_defs DROP CONSTRAINT entity_defs_entityid_foreign; ALTER TABLE public.entity_defs ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id); `)); diff --git a/lib/model/migrations/legacy/20241226-01-indices-for-purging-entities.js b/lib/model/migrations/20241226-01-indices-for-purging-entities.js similarity index 94% rename from lib/model/migrations/legacy/20241226-01-indices-for-purging-entities.js rename to lib/model/migrations/20241226-01-indices-for-purging-entities.js index 6ca38cc66..47ba7e551 100644 --- a/lib/model/migrations/legacy/20241226-01-indices-for-purging-entities.js +++ b/lib/model/migrations/20241226-01-indices-for-purging-entities.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` CREATE INDEX audits_details_entity_uuid ON public.audits USING hash ((details->'entity'->>'uuid')) WHERE ACTION IN ('entity.create', 'entity.update', 'entity.update.version', 'entity.update.resolve', 'entity.delete', 'entity.restore'); @@ -15,7 +15,7 @@ CREATE INDEX audits_details_entityUuids ON audits USING gin ((details -> 'entity WHERE ACTION = 'entity.purge'; `); -const down = ((db) => db.raw(` +const down = ((db) => db.query(` DROP INDEX audits_details_entity_uuid; DROP INDEX audits_details_entityUuids; `)); diff --git a/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js b/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js similarity index 96% rename from lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js rename to lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js index e944d0054..464b37cb6 100644 --- a/lib/model/migrations/legacy/20241227-01-backfill-audit-entity-uuid.js +++ b/lib/model/migrations/20241227-01-backfill-audit-entity-uuid.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const up = (db) => db.raw(` +const up = (db) => db.query(` UPDATE audits SET details = ('{ "entity":{ "uuid":"' || (details->>'uuid') || '"}}')::JSONB WHERE action = 'entity.delete' AND JSONB_EXISTS(details, 'uuid'); `); From c63e4fafc48cd15282865e7f3f7895fd0ef82159 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:53:13 +0000 Subject: [PATCH 116/133] Revert "partial" This reverts commit 514d18067e286857a25030815aaaaec56256ce31. --- .github/workflows/db-partial-migrations.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/db-partial-migrations.yml b/.github/workflows/db-partial-migrations.yml index f3875541f..b6bd22395 100644 --- a/.github/workflows/db-partial-migrations.yml +++ b/.github/workflows/db-partial-migrations.yml @@ -18,10 +18,7 @@ jobs: - legacy-first-100 - legacy-all - new-first-1-as-legacy - - new-first-2-as-legacy - - new-first-3-as-legacy - - new-first-4-as-legacy - - new-first-5-as-legacy + - new-first-10-as-legacy - all timeout-minutes: 2 # TODO should we use the same container as circle & central? From b82c47e437012090abb89498e84f79d8e85cc3e2 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:54:54 +0000 Subject: [PATCH 117/133] add missing pgConnectionString --- test/db-partial-migrations/test.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 20638a118..20e6e1612 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -92,7 +92,10 @@ show_migrations log "Running modern migrations..." make migrations -pgConnectionString= +pgConnectionString="$(node -e ' + const { host, database, user, password } = require("config").get("default.database"); + console.log(`postgres://${user}:${password}@${host}/${database}`); +')" log "Checking final database schema..." if ! diff \ From 757bb936aabf5dfb9bb83097ac2c565bf75c89b7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:55:21 +0000 Subject: [PATCH 118/133] tryail --- test/db-partial-migrations/test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 20e6e1612..73de6cb0d 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -1,5 +1,6 @@ #!/bin/bash -eux set -o pipefail +shopt -s inherit_errexit log() { echo "[test/db-partial-migrations/prepare] $*"; } From edfc3fc6e16da6b5690f242a64ae220a8152f7de Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 14:57:29 +0000 Subject: [PATCH 119/133] add expected schema --- .../db-partial-migrations/expected-schema.sql | 2682 +++++++++++++++++ 1 file changed, 2682 insertions(+) diff --git a/test/db-partial-migrations/expected-schema.sql b/test/db-partial-migrations/expected-schema.sql index e69de29bb..16a66b3b1 100644 --- a/test/db-partial-migrations/expected-schema.sql +++ b/test/db-partial-migrations/expected-schema.sql @@ -0,0 +1,2682 @@ +-- +-- PostgreSQL database dump +-- + +-- Dumped from database version 14.10 (Debian 14.10-1.pgdg120+1) +-- Dumped by pg_dump version 16.8 (Ubuntu 16.8-1.pgdg24.04+1) + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: postgres +-- + +-- *not* creating schema, since initdb creates it + + +ALTER SCHEMA public OWNER TO postgres; + +-- +-- Name: citext; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS citext WITH SCHEMA public; + + +-- +-- Name: EXTENSION citext; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION citext IS 'data type for case-insensitive character strings'; + + +-- +-- Name: pg_trgm; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public; + + +-- +-- Name: EXTENSION pg_trgm; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams'; + + +-- +-- Name: pgrowlocks; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS pgrowlocks WITH SCHEMA public; + + +-- +-- Name: EXTENSION pgrowlocks; Type: COMMENT; Schema: -; Owner: +-- + +COMMENT ON EXTENSION pgrowlocks IS 'show row-level locking information'; + + +-- +-- Name: conflictType; Type: TYPE; Schema: public; Owner: jubilant +-- + +CREATE TYPE public."conflictType" AS ENUM ( + 'soft', + 'hard' +); + + +ALTER TYPE public."conflictType" OWNER TO jubilant; + +-- +-- Name: s3_upload_status; Type: TYPE; Schema: public; Owner: jubilant +-- + +CREATE TYPE public.s3_upload_status AS ENUM ( + 'pending', + 'uploaded', + 'failed' +); + + +ALTER TYPE public.s3_upload_status OWNER TO jubilant; + +-- +-- Name: check_email(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_email() RETURNS trigger + LANGUAGE plpgsql + AS $$ + declare extant int; + begin + select count(*) into extant from users inner join + (select id from actors where "deletedAt" is null and id != NEW."actorId") + as actors on actors.id=users."actorId" + where email=NEW.email limit 1; + if extant > 0 then + raise exception 'ODK01:%', NEW.email; + end if; + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_email() OWNER TO jubilant; + +-- +-- Name: check_field_collisions(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_field_collisions() RETURNS trigger + LANGUAGE plpgsql + AS $$ + declare extant int; + declare extformid int; + declare extpath text; + declare exttype text; + begin + -- factoring the repeated joins here into a CTE explodes the cost by 10x + + select count(distinct type), form_fields."formId", form_fields.path into extant, extformid, extpath + from form_fields + + -- finds canonical formDefIds (published, or active draft) + left outer join (select id from form_defs where "publishedAt" is not null) as form_defs + on form_defs.id = form_fields."formDefId" + left outer join (select id, "draftDefId" from forms) as forms + on forms."draftDefId" = form_fields."formDefId" + + -- weeds out paths whose latest def indicates they are a string. first figure + -- out latest def, then knock out latest strings from conflict detection. + inner join + (select form_fields."formId", max("formDefId") as "latestDefId" from form_fields + -- this is a repeat of the above canonical-def subquery + left outer join (select id from form_defs where "publishedAt" is not null) as ifds + on ifds.id = form_fields."formDefId" + left outer join (select id, "draftDefId" from forms) as ifs + on ifs."draftDefId" = form_fields."formDefId" + where ifs.id is not null or ifds.id is not null + group by form_fields."formId" + ) as tail + on tail."formId" = form_fields."formId" + inner join + (select "formDefId", path from form_fields where type != 'string') as nonstring + on "latestDefId" = nonstring."formDefId" and form_fields.path = nonstring.path + + where forms.id is not null or form_defs.id is not null + group by form_fields."formId", form_fields.path having count(distinct type) > 1; + + if extant > 0 then + select type into exttype + from form_fields + where "formId" = extformid and path = extpath + order by "formDefId" desc + limit 1 + offset 1; + + raise exception using message = format('ODK05:%s:%s', extpath, exttype); + end if; + + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_field_collisions() OWNER TO jubilant; + +-- +-- Name: check_form_state(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_form_state() RETURNS trigger + LANGUAGE plpgsql + AS $$ + begin + if NEW.state is null or NEW.state not in ('open', 'closing', 'closed') then + raise exception 'ODK03:%', NEW.state; + end if; + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_form_state() OWNER TO jubilant; + +-- +-- Name: check_form_version(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_form_version() RETURNS trigger + LANGUAGE plpgsql + AS $$ + declare extant int; + declare pid int; + declare xmlid text; + declare vstr text; + begin + select count(*), "projectId", "xmlFormId", version into extant, pid, xmlid, vstr + from form_defs + inner join (select id, "xmlFormId", "projectId" from forms) + as forms on forms.id = form_defs."formId" + where "publishedAt" is not null + group by "projectId", "xmlFormId", version + having count(form_defs.id) > 1; + + if extant > 0 then + raise exception using message = format('ODK02:%s:%L:%L', pid, xmlid, vstr); + end if; + + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_form_version() OWNER TO jubilant; + +-- +-- Name: check_instanceid_unique(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_instanceid_unique() RETURNS trigger + LANGUAGE plpgsql + AS $$ + declare fid int; + declare drft boolean; + declare found int; + begin + select "formId", draft into fid, drft from submissions where submissions.id=NEW."submissionId"; + select count(*) into found from submissions + join submission_defs on submissions.id=submission_defs."submissionId" + where "formId"=fid and submission_defs."instanceId"=NEW."instanceId" and draft=drft; + + if found > 1 then + raise exception using message = format('ODK06:%s', NEW."instanceId"); + end if; + + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_instanceid_unique() OWNER TO jubilant; + +-- +-- Name: check_managed_key(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_managed_key() RETURNS trigger + LANGUAGE plpgsql + AS $$ + declare "projectKeyId" int; + begin + select "keyId" into "projectKeyId" from forms + inner join projects on projects.id = forms."projectId" + where forms.id = NEW."formId"; + if "projectKeyId" is not null and NEW."keyId" is null then + raise exception 'ODK04'; + end if; + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_managed_key() OWNER TO jubilant; + +-- +-- Name: check_review_state(); Type: FUNCTION; Schema: public; Owner: jubilant +-- + +CREATE FUNCTION public.check_review_state() RETURNS trigger + LANGUAGE plpgsql + AS $$ + begin + if NEW."reviewState" is not null and NEW."reviewState" not in ('hasIssues', 'edited', 'approved', 'rejected') then + raise exception 'ODK03:%', NEW."reviewState"; + end if; + return NEW; + end; +$$; + + +ALTER FUNCTION public.check_review_state() OWNER TO jubilant; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: actees; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.actees ( + id character varying(36) NOT NULL, + species character varying(36), + parent character varying(36), + "purgedAt" timestamp(3) with time zone, + "purgedName" text, + details jsonb +); + + +ALTER TABLE public.actees OWNER TO jubilant; + +-- +-- Name: actors; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.actors ( + id integer NOT NULL, + type character varying(15), + "acteeId" character varying(36) NOT NULL, + "displayName" character varying(64) NOT NULL, + meta jsonb, + "createdAt" timestamp(3) with time zone, + "updatedAt" timestamp(3) with time zone, + "deletedAt" timestamp(3) with time zone, + "expiresAt" timestamp(3) with time zone +); + + +ALTER TABLE public.actors OWNER TO jubilant; + +-- +-- Name: actors_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.actors_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.actors_id_seq OWNER TO jubilant; + +-- +-- Name: actors_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.actors_id_seq OWNED BY public.actors.id; + + +-- +-- Name: assignments; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.assignments ( + "actorId" integer NOT NULL, + "roleId" integer NOT NULL, + "acteeId" character varying(36) NOT NULL +); + + +ALTER TABLE public.assignments OWNER TO jubilant; + +-- +-- Name: audits; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.audits ( + "actorId" integer, + action text NOT NULL, + "acteeId" character varying(36), + details jsonb, + "loggedAt" timestamp(3) with time zone, + claimed timestamp(3) with time zone, + processed timestamp(3) with time zone, + "lastFailure" timestamp(3) with time zone, + failures integer DEFAULT 0, + id integer NOT NULL, + notes text +); + + +ALTER TABLE public.audits OWNER TO jubilant; + +-- +-- Name: audits_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.audits_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.audits_id_seq OWNER TO jubilant; + +-- +-- Name: audits_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.audits_id_seq OWNED BY public.audits.id; + + +-- +-- Name: blobs; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.blobs ( + id integer NOT NULL, + sha character varying(40) NOT NULL, + content bytea, + "contentType" text DEFAULT 'application/octet-stream'::text NOT NULL, + md5 character varying(32) NOT NULL, + s3_status public.s3_upload_status DEFAULT 'pending'::public.s3_upload_status NOT NULL +); + + +ALTER TABLE public.blobs OWNER TO jubilant; + +-- +-- Name: blobs_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.blobs_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.blobs_id_seq OWNER TO jubilant; + +-- +-- Name: blobs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.blobs_id_seq OWNED BY public.blobs.id; + + +-- +-- Name: client_audits; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.client_audits ( + "blobId" integer NOT NULL, + event text, + node text, + start text, + "end" text, + latitude text, + longitude text, + accuracy text, + "old-value" text, + "new-value" text, + remainder jsonb, + "user" text, + "change-reason" text +); + + +ALTER TABLE public.client_audits OWNER TO jubilant; + +-- +-- Name: comments; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.comments ( + id integer NOT NULL, + "submissionId" integer NOT NULL, + "actorId" integer NOT NULL, + body text NOT NULL, + "createdAt" timestamp(3) with time zone +); + + +ALTER TABLE public.comments OWNER TO jubilant; + +-- +-- Name: comments_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.comments_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.comments_id_seq OWNER TO jubilant; + +-- +-- Name: comments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.comments_id_seq OWNED BY public.comments.id; + + +-- +-- Name: config; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.config ( + key character varying(40) NOT NULL, + value jsonb, + "setAt" timestamp(3) with time zone +); + + +ALTER TABLE public.config OWNER TO jubilant; + +-- +-- Name: dataset_form_defs; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.dataset_form_defs ( + "datasetId" integer NOT NULL, + "formDefId" integer NOT NULL, + actions jsonb NOT NULL +); + + +ALTER TABLE public.dataset_form_defs OWNER TO jubilant; + +-- +-- Name: datasets; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.datasets ( + id integer NOT NULL, + name text NOT NULL, + "acteeId" character varying(36) NOT NULL, + "createdAt" timestamp(3) with time zone NOT NULL, + "projectId" integer NOT NULL, + "publishedAt" timestamp(3) with time zone, + "approvalRequired" boolean DEFAULT false NOT NULL +); + + +ALTER TABLE public.datasets OWNER TO jubilant; + +-- +-- Name: datasets_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.datasets_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.datasets_id_seq OWNER TO jubilant; + +-- +-- Name: datasets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.datasets_id_seq OWNED BY public.datasets.id; + + +-- +-- Name: ds_properties; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.ds_properties ( + id integer NOT NULL, + name text NOT NULL, + "datasetId" integer NOT NULL, + "publishedAt" timestamp(3) with time zone +); + + +ALTER TABLE public.ds_properties OWNER TO jubilant; + +-- +-- Name: ds_properties_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.ds_properties_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.ds_properties_id_seq OWNER TO jubilant; + +-- +-- Name: ds_properties_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.ds_properties_id_seq OWNED BY public.ds_properties.id; + + +-- +-- Name: ds_property_fields; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.ds_property_fields ( + "dsPropertyId" integer, + "formDefId" integer, + path text +); + + +ALTER TABLE public.ds_property_fields OWNER TO jubilant; + +-- +-- Name: entities; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.entities ( + id integer NOT NULL, + uuid character varying(255) NOT NULL, + "datasetId" integer, + "createdAt" timestamp(3) with time zone NOT NULL, + "creatorId" integer NOT NULL, + "updatedAt" timestamp(3) with time zone, + "deletedAt" timestamp(3) with time zone, + conflict public."conflictType" +); + + +ALTER TABLE public.entities OWNER TO jubilant; + +-- +-- Name: entities_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.entities_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.entities_id_seq OWNER TO jubilant; + +-- +-- Name: entities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.entities_id_seq OWNED BY public.entities.id; + + +-- +-- Name: entity_def_sources; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.entity_def_sources ( + id integer NOT NULL, + type character varying(36) NOT NULL, + "auditId" integer, + "submissionDefId" integer, + details jsonb, + "forceProcessed" boolean +); + + +ALTER TABLE public.entity_def_sources OWNER TO jubilant; + +-- +-- Name: entity_def_sources_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.entity_def_sources_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.entity_def_sources_id_seq OWNER TO jubilant; + +-- +-- Name: entity_def_sources_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.entity_def_sources_id_seq OWNED BY public.entity_def_sources.id; + + +-- +-- Name: entity_defs; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.entity_defs ( + id integer NOT NULL, + "entityId" integer NOT NULL, + "createdAt" timestamp(3) with time zone NOT NULL, + current boolean, + data jsonb NOT NULL, + "creatorId" integer NOT NULL, + "userAgent" character varying(255), + label text NOT NULL, + root boolean DEFAULT false NOT NULL, + "sourceId" integer, + version integer DEFAULT 1 NOT NULL, + "dataReceived" jsonb DEFAULT '{}'::jsonb NOT NULL, + "baseVersion" integer, + "conflictingProperties" jsonb, + "branchId" uuid, + "trunkVersion" integer, + "branchBaseVersion" integer +); + + +ALTER TABLE public.entity_defs OWNER TO jubilant; + +-- +-- Name: entity_defs_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.entity_defs_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.entity_defs_id_seq OWNER TO jubilant; + +-- +-- Name: entity_defs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.entity_defs_id_seq OWNED BY public.entity_defs.id; + + +-- +-- Name: entity_submission_backlog; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.entity_submission_backlog ( + "submissionId" integer NOT NULL, + "submissionDefId" integer NOT NULL, + "branchId" uuid NOT NULL, + "branchBaseVersion" integer NOT NULL, + "loggedAt" timestamp(3) with time zone NOT NULL, + "auditId" integer NOT NULL, + "entityUuid" uuid NOT NULL +); + + +ALTER TABLE public.entity_submission_backlog OWNER TO jubilant; + +-- +-- Name: field_keys; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.field_keys ( + "actorId" integer NOT NULL, + "createdBy" integer NOT NULL, + "projectId" integer +); + + +ALTER TABLE public.field_keys OWNER TO jubilant; + +-- +-- Name: form_attachments; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.form_attachments ( + "formId" integer NOT NULL, + "blobId" integer, + name text NOT NULL, + type text, + "formDefId" integer NOT NULL, + "updatedAt" timestamp(3) with time zone, + "datasetId" integer, + CONSTRAINT "check_blobId_or_datasetId_is_null" CHECK ((("blobId" IS NULL) OR ("datasetId" IS NULL))), + CONSTRAINT "check_datasetId_is_null_for_non_file" CHECK (((type = 'file'::text) OR ("datasetId" IS NULL))) +); + + +ALTER TABLE public.form_attachments OWNER TO jubilant; + +-- +-- Name: form_defs; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.form_defs ( + id integer NOT NULL, + "formId" integer, + xml text NOT NULL, + hash character varying(32) NOT NULL, + sha character varying(40) NOT NULL, + sha256 character varying(64) NOT NULL, + version text NOT NULL, + "createdAt" timestamp(3) with time zone, + "keyId" integer, + "xlsBlobId" integer, + "publishedAt" timestamp(3) with time zone, + "draftToken" character varying(64), + "enketoId" character varying(255), + name text, + "schemaId" integer +); + + +ALTER TABLE public.form_defs OWNER TO jubilant; + +-- +-- Name: form_defs_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.form_defs_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.form_defs_id_seq OWNER TO jubilant; + +-- +-- Name: form_defs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.form_defs_id_seq OWNED BY public.form_defs.id; + + +-- +-- Name: form_field_values; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.form_field_values ( + "formId" integer NOT NULL, + "submissionDefId" integer NOT NULL, + path text NOT NULL, + value text +); + + +ALTER TABLE public.form_field_values OWNER TO jubilant; + +-- +-- Name: form_fields; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.form_fields ( + "formId" integer NOT NULL, + path text NOT NULL, + name text NOT NULL, + type character varying(32) NOT NULL, + "binary" boolean, + "order" integer NOT NULL, + "selectMultiple" boolean, + "schemaId" integer NOT NULL +); + + +ALTER TABLE public.form_fields OWNER TO jubilant; + +-- +-- Name: form_schemas; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.form_schemas ( + id integer NOT NULL +); + + +ALTER TABLE public.form_schemas OWNER TO jubilant; + +-- +-- Name: form_schemas_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.form_schemas_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.form_schemas_id_seq OWNER TO jubilant; + +-- +-- Name: form_schemas_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.form_schemas_id_seq OWNED BY public.form_schemas.id; + + +-- +-- Name: forms; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.forms ( + id integer NOT NULL, + "xmlFormId" character varying(64) NOT NULL, + "createdAt" timestamp(3) with time zone, + "updatedAt" timestamp(3) with time zone, + "deletedAt" timestamp(3) with time zone, + "acteeId" character varying(36) NOT NULL, + state text DEFAULT 'open'::text, + "projectId" integer NOT NULL, + "currentDefId" integer, + "draftDefId" integer, + "enketoId" character varying(255), + "enketoOnceId" text, + "webformsEnabled" boolean DEFAULT false NOT NULL +); + + +ALTER TABLE public.forms OWNER TO jubilant; + +-- +-- Name: forms_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.forms_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.forms_id_seq OWNER TO jubilant; + +-- +-- Name: forms_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.forms_id_seq OWNED BY public.forms.id; + + +-- +-- Name: keys; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.keys ( + id integer NOT NULL, + public text NOT NULL, + private jsonb, + managed boolean, + hint text, + "createdAt" timestamp(3) with time zone +); + + +ALTER TABLE public.keys OWNER TO jubilant; + +-- +-- Name: keys_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.keys_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.keys_id_seq OWNER TO jubilant; + +-- +-- Name: keys_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.keys_id_seq OWNED BY public.keys.id; + + +-- +-- Name: knex_migrations; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.knex_migrations ( + id integer NOT NULL, + name character varying(255), + batch integer, + migration_time timestamp(3) with time zone +); + + +ALTER TABLE public.knex_migrations OWNER TO jubilant; + +-- +-- Name: knex_migrations_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.knex_migrations_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.knex_migrations_id_seq OWNER TO jubilant; + +-- +-- Name: knex_migrations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.knex_migrations_id_seq OWNED BY public.knex_migrations.id; + + +-- +-- Name: knex_migrations_lock; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.knex_migrations_lock ( + index integer NOT NULL, + is_locked integer +); + + +ALTER TABLE public.knex_migrations_lock OWNER TO jubilant; + +-- +-- Name: knex_migrations_lock_index_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.knex_migrations_lock_index_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.knex_migrations_lock_index_seq OWNER TO jubilant; + +-- +-- Name: knex_migrations_lock_index_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.knex_migrations_lock_index_seq OWNED BY public.knex_migrations_lock.index; + + +-- +-- Name: projects; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.projects ( + id integer NOT NULL, + name text NOT NULL, + "acteeId" character varying(36) NOT NULL, + "createdAt" timestamp(3) with time zone, + "updatedAt" timestamp(3) with time zone, + "deletedAt" timestamp(3) with time zone, + archived boolean, + "keyId" integer, + description text +); + + +ALTER TABLE public.projects OWNER TO jubilant; + +-- +-- Name: projects_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.projects_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.projects_id_seq OWNER TO jubilant; + +-- +-- Name: projects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.projects_id_seq OWNED BY public.projects.id; + + +-- +-- Name: public_links; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.public_links ( + "actorId" integer NOT NULL, + "createdBy" integer NOT NULL, + "formId" integer NOT NULL, + once boolean +); + + +ALTER TABLE public.public_links OWNER TO jubilant; + +-- +-- Name: purged_entities; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.purged_entities ( + "entityUuid" character varying NOT NULL, + "acteeId" character varying NOT NULL, + "auditId" integer NOT NULL +); + + +ALTER TABLE public.purged_entities OWNER TO jubilant; + +-- +-- Name: purged_entities_auditId_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public."purged_entities_auditId_seq" + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public."purged_entities_auditId_seq" OWNER TO jubilant; + +-- +-- Name: purged_entities_auditId_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public."purged_entities_auditId_seq" OWNED BY public.purged_entities."auditId"; + + +-- +-- Name: roles; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.roles ( + id integer NOT NULL, + name text NOT NULL, + system character varying(8), + "createdAt" timestamp(3) with time zone, + "updatedAt" timestamp(3) with time zone, + verbs jsonb +); + + +ALTER TABLE public.roles OWNER TO jubilant; + +-- +-- Name: roles_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.roles_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.roles_id_seq OWNER TO jubilant; + +-- +-- Name: roles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.roles_id_seq OWNED BY public.roles.id; + + +-- +-- Name: sessions; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.sessions ( + "actorId" integer NOT NULL, + token character varying(64) NOT NULL, + "expiresAt" timestamp(3) with time zone NOT NULL, + "createdAt" timestamp(3) with time zone, + csrf character varying(64) +); + + +ALTER TABLE public.sessions OWNER TO jubilant; + +-- +-- Name: submission_attachments; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.submission_attachments ( + "blobId" integer, + name text NOT NULL, + "submissionDefId" integer NOT NULL, + index integer, + "isClientAudit" boolean +); + + +ALTER TABLE public.submission_attachments OWNER TO jubilant; + +-- +-- Name: submission_defs; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.submission_defs ( + id integer NOT NULL, + "submissionId" integer NOT NULL, + xml text NOT NULL, + "formDefId" integer NOT NULL, + "submitterId" integer, + "createdAt" timestamp(3) with time zone, + "encDataAttachmentName" character varying(255), + "localKey" text, + signature text, + current boolean, + "instanceName" text, + "instanceId" character varying(64) NOT NULL, + "userAgent" character varying(255), + "deviceId" character varying(255), + root boolean +); + + +ALTER TABLE public.submission_defs OWNER TO jubilant; + +-- +-- Name: submission_defs_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.submission_defs_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.submission_defs_id_seq OWNER TO jubilant; + +-- +-- Name: submission_defs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.submission_defs_id_seq OWNED BY public.submission_defs.id; + + +-- +-- Name: submissions; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.submissions ( + id integer NOT NULL, + "formId" integer NOT NULL, + "instanceId" character varying(64) NOT NULL, + "createdAt" timestamp(3) with time zone, + "updatedAt" timestamp(3) with time zone, + "deletedAt" timestamp(3) with time zone, + "submitterId" integer, + "deviceId" character varying(255), + draft boolean NOT NULL, + "reviewState" text +); + + +ALTER TABLE public.submissions OWNER TO jubilant; + +-- +-- Name: submissions_id_seq; Type: SEQUENCE; Schema: public; Owner: jubilant +-- + +CREATE SEQUENCE public.submissions_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.submissions_id_seq OWNER TO jubilant; + +-- +-- Name: submissions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: jubilant +-- + +ALTER SEQUENCE public.submissions_id_seq OWNED BY public.submissions.id; + + +-- +-- Name: user_project_preferences; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.user_project_preferences ( + "userId" integer NOT NULL, + "projectId" integer NOT NULL, + "propertyName" text NOT NULL, + "propertyValue" jsonb NOT NULL, + CONSTRAINT "user_project_preferences_propertyName_check" CHECK ((length("propertyName") > 0)) +); + + +ALTER TABLE public.user_project_preferences OWNER TO jubilant; + +-- +-- Name: user_site_preferences; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.user_site_preferences ( + "userId" integer NOT NULL, + "propertyName" text NOT NULL, + "propertyValue" jsonb NOT NULL, + CONSTRAINT "user_site_preferences_propertyName_check" CHECK ((length("propertyName") > 0)) +); + + +ALTER TABLE public.user_site_preferences OWNER TO jubilant; + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: jubilant +-- + +CREATE TABLE public.users ( + "actorId" integer NOT NULL, + password character varying(64), + email public.citext NOT NULL +); + + +ALTER TABLE public.users OWNER TO jubilant; + +-- +-- Name: actors id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.actors ALTER COLUMN id SET DEFAULT nextval('public.actors_id_seq'::regclass); + + +-- +-- Name: audits id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.audits ALTER COLUMN id SET DEFAULT nextval('public.audits_id_seq'::regclass); + + +-- +-- Name: blobs id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.blobs ALTER COLUMN id SET DEFAULT nextval('public.blobs_id_seq'::regclass); + + +-- +-- Name: comments id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.comments ALTER COLUMN id SET DEFAULT nextval('public.comments_id_seq'::regclass); + + +-- +-- Name: datasets id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.datasets ALTER COLUMN id SET DEFAULT nextval('public.datasets_id_seq'::regclass); + + +-- +-- Name: ds_properties id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_properties ALTER COLUMN id SET DEFAULT nextval('public.ds_properties_id_seq'::regclass); + + +-- +-- Name: entities id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entities ALTER COLUMN id SET DEFAULT nextval('public.entities_id_seq'::regclass); + + +-- +-- Name: entity_def_sources id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_def_sources ALTER COLUMN id SET DEFAULT nextval('public.entity_def_sources_id_seq'::regclass); + + +-- +-- Name: entity_defs id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_defs ALTER COLUMN id SET DEFAULT nextval('public.entity_defs_id_seq'::regclass); + + +-- +-- Name: form_defs id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_defs ALTER COLUMN id SET DEFAULT nextval('public.form_defs_id_seq'::regclass); + + +-- +-- Name: form_schemas id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_schemas ALTER COLUMN id SET DEFAULT nextval('public.form_schemas_id_seq'::regclass); + + +-- +-- Name: forms id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.forms ALTER COLUMN id SET DEFAULT nextval('public.forms_id_seq'::regclass); + + +-- +-- Name: keys id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.keys ALTER COLUMN id SET DEFAULT nextval('public.keys_id_seq'::regclass); + + +-- +-- Name: knex_migrations id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.knex_migrations ALTER COLUMN id SET DEFAULT nextval('public.knex_migrations_id_seq'::regclass); + + +-- +-- Name: knex_migrations_lock index; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.knex_migrations_lock ALTER COLUMN index SET DEFAULT nextval('public.knex_migrations_lock_index_seq'::regclass); + + +-- +-- Name: projects id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.projects ALTER COLUMN id SET DEFAULT nextval('public.projects_id_seq'::regclass); + + +-- +-- Name: purged_entities auditId; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.purged_entities ALTER COLUMN "auditId" SET DEFAULT nextval('public."purged_entities_auditId_seq"'::regclass); + + +-- +-- Name: roles id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.roles ALTER COLUMN id SET DEFAULT nextval('public.roles_id_seq'::regclass); + + +-- +-- Name: submission_defs id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_defs ALTER COLUMN id SET DEFAULT nextval('public.submission_defs_id_seq'::regclass); + + +-- +-- Name: submissions id; Type: DEFAULT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submissions ALTER COLUMN id SET DEFAULT nextval('public.submissions_id_seq'::regclass); + + +-- +-- Name: actees actees_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.actees + ADD CONSTRAINT actees_pkey PRIMARY KEY (id); + + +-- +-- Name: actors actors_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.actors + ADD CONSTRAINT actors_pkey PRIMARY KEY (id); + + +-- +-- Name: assignments assignments_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.assignments + ADD CONSTRAINT assignments_pkey PRIMARY KEY ("actorId", "roleId", "acteeId"); + + +-- +-- Name: audits audits_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.audits + ADD CONSTRAINT audits_pkey PRIMARY KEY (id); + + +-- +-- Name: blobs blobs_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.blobs + ADD CONSTRAINT blobs_pkey PRIMARY KEY (id); + + +-- +-- Name: blobs blobs_sha_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.blobs + ADD CONSTRAINT blobs_sha_unique UNIQUE (sha); + + +-- +-- Name: comments comments_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.comments + ADD CONSTRAINT comments_pkey PRIMARY KEY (id); + + +-- +-- Name: config config_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.config + ADD CONSTRAINT config_pkey PRIMARY KEY (key); + + +-- +-- Name: dataset_form_defs dataset_form_defs_datasetid_formdefid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.dataset_form_defs + ADD CONSTRAINT dataset_form_defs_datasetid_formdefid_unique UNIQUE ("datasetId", "formDefId"); + + +-- +-- Name: datasets datasets_name_projectid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.datasets + ADD CONSTRAINT datasets_name_projectid_unique UNIQUE (name, "projectId"); + + +-- +-- Name: datasets datasets_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.datasets + ADD CONSTRAINT datasets_pkey PRIMARY KEY (id); + + +-- +-- Name: ds_properties ds_properties_name_datasetid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_properties + ADD CONSTRAINT ds_properties_name_datasetid_unique UNIQUE (name, "datasetId"); + + +-- +-- Name: ds_properties ds_properties_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_properties + ADD CONSTRAINT ds_properties_pkey PRIMARY KEY (id); + + +-- +-- Name: ds_property_fields ds_property_fields_dspropertyid_formdefid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_property_fields + ADD CONSTRAINT ds_property_fields_dspropertyid_formdefid_unique UNIQUE ("dsPropertyId", "formDefId"); + + +-- +-- Name: ds_property_fields ds_property_fields_dspropertyid_path_formdefid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_property_fields + ADD CONSTRAINT ds_property_fields_dspropertyid_path_formdefid_unique UNIQUE ("dsPropertyId", path, "formDefId"); + + +-- +-- Name: entities entities_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entities + ADD CONSTRAINT entities_pkey PRIMARY KEY (id); + + +-- +-- Name: entities entities_uuid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entities + ADD CONSTRAINT entities_uuid_unique UNIQUE (uuid); + + +-- +-- Name: entity_def_sources entity_def_sources_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_def_sources + ADD CONSTRAINT entity_def_sources_pkey PRIMARY KEY (id); + + +-- +-- Name: entity_defs entity_defs_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_defs + ADD CONSTRAINT entity_defs_pkey PRIMARY KEY (id); + + +-- +-- Name: entity_submission_backlog entity_submission_backlog_branchId_branchBaseVersion_key; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_submission_backlog + ADD CONSTRAINT "entity_submission_backlog_branchId_branchBaseVersion_key" UNIQUE ("branchId", "branchBaseVersion"); + + +-- +-- Name: field_keys field_keys_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.field_keys + ADD CONSTRAINT field_keys_pkey PRIMARY KEY ("actorId"); + + +-- +-- Name: form_attachments form_attachments_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_attachments + ADD CONSTRAINT form_attachments_pkey PRIMARY KEY ("formDefId", name); + + +-- +-- Name: form_defs form_defs_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_defs + ADD CONSTRAINT form_defs_pkey PRIMARY KEY (id); + + +-- +-- Name: form_fields form_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_fields + ADD CONSTRAINT form_fields_pkey PRIMARY KEY ("schemaId", path); + + +-- +-- Name: form_schemas form_schemas_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_schemas + ADD CONSTRAINT form_schemas_pkey PRIMARY KEY (id); + + +-- +-- Name: forms forms_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.forms + ADD CONSTRAINT forms_pkey PRIMARY KEY (id); + + +-- +-- Name: keys keys_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.keys + ADD CONSTRAINT keys_pkey PRIMARY KEY (id); + + +-- +-- Name: keys keys_public_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.keys + ADD CONSTRAINT keys_public_unique UNIQUE (public); + + +-- +-- Name: knex_migrations_lock knex_migrations_lock_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.knex_migrations_lock + ADD CONSTRAINT knex_migrations_lock_pkey PRIMARY KEY (index); + + +-- +-- Name: knex_migrations knex_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.knex_migrations + ADD CONSTRAINT knex_migrations_pkey PRIMARY KEY (id); + + +-- +-- Name: projects projects_acteeid_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT projects_acteeid_unique UNIQUE ("acteeId"); + + +-- +-- Name: projects projects_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT projects_pkey PRIMARY KEY (id); + + +-- +-- Name: public_links public_links_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.public_links + ADD CONSTRAINT public_links_pkey PRIMARY KEY ("actorId"); + + +-- +-- Name: purged_entities purged_entities_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.purged_entities + ADD CONSTRAINT purged_entities_pkey PRIMARY KEY ("entityUuid"); + + +-- +-- Name: roles roles_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.roles + ADD CONSTRAINT roles_pkey PRIMARY KEY (id); + + +-- +-- Name: submission_attachments submission_attachments_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_attachments + ADD CONSTRAINT submission_attachments_pkey PRIMARY KEY ("submissionDefId", name); + + +-- +-- Name: submission_defs submission_defs_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_defs + ADD CONSTRAINT submission_defs_pkey PRIMARY KEY (id); + + +-- +-- Name: submissions submissions_formid_instanceid_draft_unique; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submissions + ADD CONSTRAINT submissions_formid_instanceid_draft_unique UNIQUE ("formId", "instanceId", draft); + + +-- +-- Name: submissions submissions_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submissions + ADD CONSTRAINT submissions_pkey PRIMARY KEY (id); + + +-- +-- Name: user_project_preferences user_project_preferences_primary_key; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.user_project_preferences + ADD CONSTRAINT user_project_preferences_primary_key PRIMARY KEY ("userId", "projectId", "propertyName"); + + +-- +-- Name: user_site_preferences user_site_preferences_primary_key; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.user_site_preferences + ADD CONSTRAINT user_site_preferences_primary_key PRIMARY KEY ("userId", "propertyName"); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_pkey PRIMARY KEY ("actorId"); + + +-- +-- Name: actees_parent_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX actees_parent_index ON public.actees USING btree (parent); + + +-- +-- Name: actors_displayname_gist_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX actors_displayname_gist_index ON public.actors USING gist ("displayName" public.gist_trgm_ops); + + +-- +-- Name: actors_type_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX actors_type_index ON public.actors USING btree (type); + + +-- +-- Name: assignments_actorid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX assignments_actorid_index ON public.assignments USING btree ("actorId"); + + +-- +-- Name: audits_acteeid_loggedat_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_acteeid_loggedat_index ON public.audits USING btree ("acteeId", "loggedAt"); + + +-- +-- Name: audits_action_acteeid_loggedat_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_action_acteeid_loggedat_index ON public.audits USING btree (action, "acteeId", "loggedAt"); + + +-- +-- Name: audits_actorid_action_loggedat_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_actorid_action_loggedat_index ON public.audits USING btree ("actorId", action, "loggedAt"); + + +-- +-- Name: audits_actorid_loggedat_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_actorid_loggedat_index ON public.audits USING btree ("actorId", "loggedAt"); + + +-- +-- Name: audits_claimed_processed_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_claimed_processed_index ON public.audits USING btree (claimed, processed); + + +-- +-- Name: audits_details_entity_def_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_entity_def_index ON public.audits USING hash ((((details ->> 'entityDefId'::text))::integer)); + + +-- +-- Name: audits_details_entity_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_entity_index ON public.audits USING hash ((((details ->> 'entityId'::text))::integer)); + + +-- +-- Name: audits_details_entity_source_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_entity_source_index ON public.audits USING hash ((((details ->> 'sourceId'::text))::integer)); + + +-- +-- Name: audits_details_entity_uuid; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_entity_uuid ON public.audits USING hash ((((details -> 'entity'::text) ->> 'uuid'::text))) WHERE (action = ANY (ARRAY['entity.create'::text, 'entity.update'::text, 'entity.update.version'::text, 'entity.update.resolve'::text, 'entity.delete'::text, 'entity.restore'::text])); + + +-- +-- Name: audits_details_entity_uuid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_entity_uuid_index ON public.audits USING hash ((((details -> 'entity'::text) ->> 'uuid'::text))); + + +-- +-- Name: audits_details_entityuuids; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_entityuuids ON public.audits USING gin (((details -> 'entityUuids'::text)) jsonb_path_ops) WHERE (action = 'entity.purge'::text); + + +-- +-- Name: audits_details_submission_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX audits_details_submission_index ON public.audits USING hash ((((details -> 'submissionId'::text))::integer)); + + +-- +-- Name: blobs_sha_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX blobs_sha_index ON public.blobs USING btree (sha); + + +-- +-- Name: client_audits_start_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX client_audits_start_index ON public.client_audits USING btree (start); + + +-- +-- Name: comments_submissionid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX comments_submissionid_index ON public.comments USING btree ("submissionId"); + + +-- +-- Name: entities_datasetid_createdat_id_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX entities_datasetid_createdat_id_index ON public.entities USING btree ("datasetId", "createdAt", id); + + +-- +-- Name: entities_deletedat_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX entities_deletedat_index ON public.entities USING btree ("deletedAt"); + + +-- +-- Name: entity_defs_entityid_current_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX entity_defs_entityid_current_index ON public.entity_defs USING btree ("entityId", current); + + +-- +-- Name: entity_defs_sourceid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX entity_defs_sourceid_index ON public.entity_defs USING btree ("sourceId"); + + +-- +-- Name: field_keys_actorid_projectid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX field_keys_actorid_projectid_index ON public.field_keys USING btree ("actorId", "projectId"); + + +-- +-- Name: form_attachments_formid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_attachments_formid_index ON public.form_attachments USING btree ("formId"); + + +-- +-- Name: form_defs_formid_publishedat_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_defs_formid_publishedat_index ON public.form_defs USING btree ("formId", "publishedAt"); + + +-- +-- Name: form_field_values_formid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_field_values_formid_index ON public.form_field_values USING btree ("formId"); + + +-- +-- Name: form_field_values_formid_submissiondefid_path_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_field_values_formid_submissiondefid_path_index ON public.form_field_values USING btree ("formId", "submissionDefId", path); + + +-- +-- Name: form_field_values_submissiondefid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_field_values_submissiondefid_index ON public.form_field_values USING btree ("submissionDefId"); + + +-- +-- Name: form_fields_formid_path_type_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_fields_formid_path_type_index ON public.form_fields USING btree ("formId", path, type); + + +-- +-- Name: form_fields_schemaid_binary_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_fields_schemaid_binary_index ON public.form_fields USING btree ("schemaId", "binary"); + + +-- +-- Name: form_fields_schemaid_order_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX form_fields_schemaid_order_index ON public.form_fields USING btree ("schemaId", "order"); + + +-- +-- Name: forms_deletedat_state_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX forms_deletedat_state_index ON public.forms USING btree ("deletedAt", state); + + +-- +-- Name: forms_projectid_xmlformid_deletedat_unique; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE UNIQUE INDEX forms_projectid_xmlformid_deletedat_unique ON public.forms USING btree ("projectId", "xmlFormId") WHERE ("deletedAt" IS NULL); + + +-- +-- Name: forms_xmlformid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX forms_xmlformid_index ON public.forms USING btree ("xmlFormId"); + + +-- +-- Name: keys_public_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX keys_public_index ON public.keys USING btree (public); + + +-- +-- Name: purged_entities_actee_uuid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX purged_entities_actee_uuid_index ON public.purged_entities USING btree ("acteeId", "entityUuid"); + + +-- +-- Name: roles_verbs_gin_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX roles_verbs_gin_index ON public.roles USING gin (verbs jsonb_path_ops); + + +-- +-- Name: sessions_actorid_expires_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX sessions_actorid_expires_index ON public.sessions USING btree ("actorId", "expiresAt"); + + +-- +-- Name: sessions_token_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE UNIQUE INDEX sessions_token_index ON public.sessions USING btree (token); + + +-- +-- Name: submission_defs_createdat_id_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX submission_defs_createdat_id_index ON public.submission_defs USING btree ("createdAt", id); + + +-- +-- Name: submission_defs_submissionid_current_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX submission_defs_submissionid_current_index ON public.submission_defs USING btree ("submissionId", current); + + +-- +-- Name: submission_defs_submissionid_instanceid_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX submission_defs_submissionid_instanceid_index ON public.submission_defs USING btree ("submissionId", "instanceId"); + + +-- +-- Name: submissions_formid_createdat_id_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX submissions_formid_createdat_id_index ON public.submissions USING btree ("formId", "createdAt", id); + + +-- +-- Name: user_project_preferences_userId_idx; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX "user_project_preferences_userId_idx" ON public.user_project_preferences USING btree ("userId"); + + +-- +-- Name: user_site_preferences_userId_idx; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX "user_site_preferences_userId_idx" ON public.user_site_preferences USING btree ("userId"); + + +-- +-- Name: users_email_gist_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX users_email_gist_index ON public.users USING gist (email public.gist_trgm_ops); + + +-- +-- Name: users_email_index; Type: INDEX; Schema: public; Owner: jubilant +-- + +CREATE INDEX users_email_index ON public.users USING btree (email); + + +-- +-- Name: users check_email; Type: TRIGGER; Schema: public; Owner: jubilant +-- + +CREATE TRIGGER check_email BEFORE INSERT OR UPDATE ON public.users FOR EACH ROW EXECUTE FUNCTION public.check_email(); + + +-- +-- Name: forms check_form_state; Type: TRIGGER; Schema: public; Owner: jubilant +-- + +CREATE TRIGGER check_form_state BEFORE INSERT OR UPDATE ON public.forms FOR EACH ROW EXECUTE FUNCTION public.check_form_state(); + + +-- +-- Name: form_defs check_form_version; Type: TRIGGER; Schema: public; Owner: jubilant +-- + +CREATE TRIGGER check_form_version AFTER INSERT OR UPDATE ON public.form_defs FOR EACH ROW EXECUTE FUNCTION public.check_form_version(); + + +-- +-- Name: submission_defs check_instanceid_unique; Type: TRIGGER; Schema: public; Owner: jubilant +-- + +CREATE TRIGGER check_instanceid_unique AFTER INSERT ON public.submission_defs FOR EACH ROW EXECUTE FUNCTION public.check_instanceid_unique(); + + +-- +-- Name: form_defs check_managed_key; Type: TRIGGER; Schema: public; Owner: jubilant +-- + +CREATE TRIGGER check_managed_key AFTER INSERT OR UPDATE ON public.form_defs FOR EACH ROW EXECUTE FUNCTION public.check_managed_key(); + + +-- +-- Name: submissions check_review_state; Type: TRIGGER; Schema: public; Owner: jubilant +-- + +CREATE TRIGGER check_review_state BEFORE INSERT OR UPDATE ON public.submissions FOR EACH ROW EXECUTE FUNCTION public.check_review_state(); + + +-- +-- Name: actors actors_acteeid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.actors + ADD CONSTRAINT actors_acteeid_foreign FOREIGN KEY ("acteeId") REFERENCES public.actees(id); + + +-- +-- Name: assignments assignments_acteeid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.assignments + ADD CONSTRAINT assignments_acteeid_foreign FOREIGN KEY ("acteeId") REFERENCES public.actees(id); + + +-- +-- Name: assignments assignments_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.assignments + ADD CONSTRAINT assignments_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: assignments assignments_roleid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.assignments + ADD CONSTRAINT assignments_roleid_foreign FOREIGN KEY ("roleId") REFERENCES public.roles(id); + + +-- +-- Name: submission_attachments attachments_blobid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_attachments + ADD CONSTRAINT attachments_blobid_foreign FOREIGN KEY ("blobId") REFERENCES public.blobs(id); + + +-- +-- Name: audits audits_acteeid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.audits + ADD CONSTRAINT audits_acteeid_foreign FOREIGN KEY ("acteeId") REFERENCES public.actees(id); + + +-- +-- Name: audits audits_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.audits + ADD CONSTRAINT audits_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: client_audits client_audits_blobid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.client_audits + ADD CONSTRAINT client_audits_blobid_foreign FOREIGN KEY ("blobId") REFERENCES public.blobs(id); + + +-- +-- Name: comments comments_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.comments + ADD CONSTRAINT comments_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: comments comments_submissionid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.comments + ADD CONSTRAINT comments_submissionid_foreign FOREIGN KEY ("submissionId") REFERENCES public.submissions(id) ON DELETE CASCADE; + + +-- +-- Name: dataset_form_defs dataset_form_defs_datasetid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.dataset_form_defs + ADD CONSTRAINT dataset_form_defs_datasetid_foreign FOREIGN KEY ("datasetId") REFERENCES public.datasets(id); + + +-- +-- Name: dataset_form_defs dataset_form_defs_formdefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.dataset_form_defs + ADD CONSTRAINT dataset_form_defs_formdefid_foreign FOREIGN KEY ("formDefId") REFERENCES public.form_defs(id) ON DELETE CASCADE; + + +-- +-- Name: datasets datasets_projectid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.datasets + ADD CONSTRAINT datasets_projectid_foreign FOREIGN KEY ("projectId") REFERENCES public.projects(id); + + +-- +-- Name: ds_properties ds_properties_datasetid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_properties + ADD CONSTRAINT ds_properties_datasetid_foreign FOREIGN KEY ("datasetId") REFERENCES public.datasets(id); + + +-- +-- Name: ds_property_fields ds_property_fields_dspropertyid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.ds_property_fields + ADD CONSTRAINT ds_property_fields_dspropertyid_foreign FOREIGN KEY ("dsPropertyId") REFERENCES public.ds_properties(id); + + +-- +-- Name: entities entities_createdby_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entities + ADD CONSTRAINT entities_createdby_foreign FOREIGN KEY ("creatorId") REFERENCES public.actors(id); + + +-- +-- Name: entities entities_datasetid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entities + ADD CONSTRAINT entities_datasetid_foreign FOREIGN KEY ("datasetId") REFERENCES public.datasets(id); + + +-- +-- Name: entity_def_sources entity_def_sources_auditid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_def_sources + ADD CONSTRAINT entity_def_sources_auditid_foreign FOREIGN KEY ("auditId") REFERENCES public.audits(id) ON DELETE SET NULL; + + +-- +-- Name: entity_def_sources entity_def_sources_submissiondefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_def_sources + ADD CONSTRAINT entity_def_sources_submissiondefid_foreign FOREIGN KEY ("submissionDefId") REFERENCES public.submission_defs(id) ON DELETE SET NULL; + + +-- +-- Name: entity_defs entity_defs_entityid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_defs + ADD CONSTRAINT entity_defs_entityid_foreign FOREIGN KEY ("entityId") REFERENCES public.entities(id) ON DELETE CASCADE; + + +-- +-- Name: entity_defs entity_defs_sourceid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_defs + ADD CONSTRAINT entity_defs_sourceid_foreign FOREIGN KEY ("sourceId") REFERENCES public.entity_def_sources(id); + + +-- +-- Name: field_keys field_keys_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.field_keys + ADD CONSTRAINT field_keys_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: field_keys field_keys_createdby_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.field_keys + ADD CONSTRAINT field_keys_createdby_foreign FOREIGN KEY ("createdBy") REFERENCES public.actors(id); + + +-- +-- Name: field_keys field_keys_projectid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.field_keys + ADD CONSTRAINT field_keys_projectid_foreign FOREIGN KEY ("projectId") REFERENCES public.projects(id); + + +-- +-- Name: entity_submission_backlog fk_audit_id; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_submission_backlog + ADD CONSTRAINT fk_audit_id FOREIGN KEY ("auditId") REFERENCES public.audits(id) ON DELETE CASCADE; + + +-- +-- Name: entity_submission_backlog fk_submission_defs; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_submission_backlog + ADD CONSTRAINT fk_submission_defs FOREIGN KEY ("submissionDefId") REFERENCES public.submission_defs(id) ON DELETE CASCADE; + + +-- +-- Name: entity_submission_backlog fk_submissions; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.entity_submission_backlog + ADD CONSTRAINT fk_submissions FOREIGN KEY ("submissionId") REFERENCES public.submissions(id) ON DELETE CASCADE; + + +-- +-- Name: form_attachments form_attachments_blobid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_attachments + ADD CONSTRAINT form_attachments_blobid_foreign FOREIGN KEY ("blobId") REFERENCES public.blobs(id); + + +-- +-- Name: form_attachments form_attachments_datasetid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_attachments + ADD CONSTRAINT form_attachments_datasetid_foreign FOREIGN KEY ("datasetId") REFERENCES public.datasets(id); + + +-- +-- Name: form_attachments form_attachments_formdefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_attachments + ADD CONSTRAINT form_attachments_formdefid_foreign FOREIGN KEY ("formDefId") REFERENCES public.form_defs(id) ON DELETE CASCADE; + + +-- +-- Name: form_attachments form_attachments_formid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_attachments + ADD CONSTRAINT form_attachments_formid_foreign FOREIGN KEY ("formId") REFERENCES public.forms(id) ON DELETE CASCADE; + + +-- +-- Name: form_defs form_defs_formid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_defs + ADD CONSTRAINT form_defs_formid_foreign FOREIGN KEY ("formId") REFERENCES public.forms(id) ON DELETE CASCADE; + + +-- +-- Name: form_defs form_defs_keyid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_defs + ADD CONSTRAINT form_defs_keyid_foreign FOREIGN KEY ("keyId") REFERENCES public.keys(id); + + +-- +-- Name: form_defs form_defs_schemaid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_defs + ADD CONSTRAINT form_defs_schemaid_foreign FOREIGN KEY ("schemaId") REFERENCES public.form_schemas(id); + + +-- +-- Name: form_defs form_defs_xlsblobid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_defs + ADD CONSTRAINT form_defs_xlsblobid_foreign FOREIGN KEY ("xlsBlobId") REFERENCES public.blobs(id); + + +-- +-- Name: form_field_values form_field_values_formid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_field_values + ADD CONSTRAINT form_field_values_formid_foreign FOREIGN KEY ("formId") REFERENCES public.forms(id) ON DELETE CASCADE; + + +-- +-- Name: form_field_values form_field_values_submissiondefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_field_values + ADD CONSTRAINT form_field_values_submissiondefid_foreign FOREIGN KEY ("submissionDefId") REFERENCES public.submission_defs(id) ON DELETE CASCADE; + + +-- +-- Name: form_fields form_fields_formid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_fields + ADD CONSTRAINT form_fields_formid_foreign FOREIGN KEY ("formId") REFERENCES public.forms(id) ON DELETE CASCADE; + + +-- +-- Name: form_fields form_fields_schemaid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.form_fields + ADD CONSTRAINT form_fields_schemaid_foreign FOREIGN KEY ("schemaId") REFERENCES public.form_schemas(id) ON DELETE CASCADE; + + +-- +-- Name: forms forms_acteeid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.forms + ADD CONSTRAINT forms_acteeid_foreign FOREIGN KEY ("acteeId") REFERENCES public.actees(id); + + +-- +-- Name: forms forms_currentdefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.forms + ADD CONSTRAINT forms_currentdefid_foreign FOREIGN KEY ("currentDefId") REFERENCES public.form_defs(id); + + +-- +-- Name: forms forms_draftdefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.forms + ADD CONSTRAINT forms_draftdefid_foreign FOREIGN KEY ("draftDefId") REFERENCES public.form_defs(id); + + +-- +-- Name: forms forms_projectid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.forms + ADD CONSTRAINT forms_projectid_foreign FOREIGN KEY ("projectId") REFERENCES public.projects(id); + + +-- +-- Name: projects projects_keyid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT projects_keyid_foreign FOREIGN KEY ("keyId") REFERENCES public.keys(id); + + +-- +-- Name: public_links public_links_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.public_links + ADD CONSTRAINT public_links_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: public_links public_links_createdby_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.public_links + ADD CONSTRAINT public_links_createdby_foreign FOREIGN KEY ("createdBy") REFERENCES public.actors(id); + + +-- +-- Name: public_links public_links_formid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.public_links + ADD CONSTRAINT public_links_formid_foreign FOREIGN KEY ("formId") REFERENCES public.forms(id) ON DELETE CASCADE; + + +-- +-- Name: sessions sessions_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.sessions + ADD CONSTRAINT sessions_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: submission_attachments submission_attachments_submissiondefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_attachments + ADD CONSTRAINT submission_attachments_submissiondefid_foreign FOREIGN KEY ("submissionDefId") REFERENCES public.submission_defs(id) ON DELETE CASCADE; + + +-- +-- Name: submission_defs submission_defs_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_defs + ADD CONSTRAINT submission_defs_actorid_foreign FOREIGN KEY ("submitterId") REFERENCES public.actors(id); + + +-- +-- Name: submission_defs submission_defs_formdefid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_defs + ADD CONSTRAINT submission_defs_formdefid_foreign FOREIGN KEY ("formDefId") REFERENCES public.form_defs(id) ON DELETE CASCADE; + + +-- +-- Name: submission_defs submission_defs_submissionid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submission_defs + ADD CONSTRAINT submission_defs_submissionid_foreign FOREIGN KEY ("submissionId") REFERENCES public.submissions(id) ON DELETE CASCADE; + + +-- +-- Name: submissions submissions_formid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submissions + ADD CONSTRAINT submissions_formid_foreign FOREIGN KEY ("formId") REFERENCES public.forms(id) ON DELETE CASCADE; + + +-- +-- Name: submissions submissions_submitter_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.submissions + ADD CONSTRAINT submissions_submitter_foreign FOREIGN KEY ("submitterId") REFERENCES public.actors(id); + + +-- +-- Name: user_project_preferences user_project_preferences_projectId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.user_project_preferences + ADD CONSTRAINT "user_project_preferences_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES public.projects(id); + + +-- +-- Name: user_project_preferences user_project_preferences_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.user_project_preferences + ADD CONSTRAINT "user_project_preferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES public.users("actorId"); + + +-- +-- Name: user_site_preferences user_site_preferences_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.user_site_preferences + ADD CONSTRAINT "user_site_preferences_userId_fkey" FOREIGN KEY ("userId") REFERENCES public.users("actorId"); + + +-- +-- Name: users users_actorid_foreign; Type: FK CONSTRAINT; Schema: public; Owner: jubilant +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_actorid_foreign FOREIGN KEY ("actorId") REFERENCES public.actors(id); + + +-- +-- Name: SCHEMA public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE USAGE ON SCHEMA public FROM PUBLIC; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +-- +-- PostgreSQL database dump complete +-- From 7f3ca0fccffabd5049fcce342c6d3ec18b796865 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:00:30 +0000 Subject: [PATCH 120/133] add trailing newline? --- test/db-partial-migrations/expected-schema.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/test/db-partial-migrations/expected-schema.sql b/test/db-partial-migrations/expected-schema.sql index 16a66b3b1..cfd322750 100644 --- a/test/db-partial-migrations/expected-schema.sql +++ b/test/db-partial-migrations/expected-schema.sql @@ -2680,3 +2680,4 @@ GRANT ALL ON SCHEMA public TO PUBLIC; -- -- PostgreSQL database dump complete -- + From de3db3c10e578928df675028b324d22722cd1b19 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:02:11 +0000 Subject: [PATCH 121/133] select less cols --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 73de6cb0d..a12068840 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -112,7 +112,7 @@ log "Checking migrations table..." tableName="knex_migrations" if ! diff \ test/db-partial-migrations/expected-migrations-table-contents.sql \ - <(psql "$pgConnectionString" -c "SELECT * FROM $tableName"); then + <(psql "$pgConnectionString" -c "SELECT id, name FROM $tableName"); then log "!!!" log "!!! $tableName table content differences detected. See above for details." log "!!!" From c0dd6e645dbd008416c86ea31fa42b7c56be09c5 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:02:39 +0000 Subject: [PATCH 122/133] flushings --- test/db-partial-migrations/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index a12068840..f96fa9180 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -102,6 +102,7 @@ log "Checking final database schema..." if ! diff \ test/db-partial-migrations/expected-schema.sql \ <(pg_dump --schema-only "$pgConnectionString"); then + sleep 1 # wait for output to flush - seems slow in CI log "!!!" log "!!! Schema differences detected. See above for details." log "!!!" @@ -113,6 +114,7 @@ tableName="knex_migrations" if ! diff \ test/db-partial-migrations/expected-migrations-table-contents.sql \ <(psql "$pgConnectionString" -c "SELECT id, name FROM $tableName"); then + sleep 1 # wait for output to flush - seems slow in CI log "!!!" log "!!! $tableName table content differences detected. See above for details." log "!!!" From 083b6040d064ae0a1171b2579a323e0131367dd9 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:04:24 +0000 Subject: [PATCH 123/133] expected table contents --- .../expected-migrations-table-contents.sql | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/test/db-partial-migrations/expected-migrations-table-contents.sql b/test/db-partial-migrations/expected-migrations-table-contents.sql index e69de29bb..fdf4937f8 100644 --- a/test/db-partial-migrations/expected-migrations-table-contents.sql +++ b/test/db-partial-migrations/expected-migrations-table-contents.sql @@ -0,0 +1,193 @@ + id | name +-----+---------------------------------------------------------- + 1 | 20170920-01-initial.js + 2 | 20171010-01-auth.js + 3 | 20171023-01-authz-forms.js + 4 | 20171030-01-add-default-authz-records.js + 5 | 20171106-01-remove-user-update-timestamp.js + 6 | 20171121-01-add-submissions-constraint.js + 7 | 20171121-02-add-submitter.js + 8 | 20171213-01-unrequire-display-name.js + 9 | 20180108-01-expiring-actors.js + 10 | 20180108-02-enum-to-varchar.js + 11 | 20180112-01-audit-table.js + 12 | 20180112-02-add-field-keys.js + 13 | 20180118-01-rerequire-display-name.js + 14 | 20180125-01-add-form-detail-fields.js + 15 | 20180125-02-more-field-key-grants.js + 16 | 20180125-03-add-blob-tables.js + 17 | 20180301-01-configuration.js + 18 | 20180322-01-additional-form-options.js + 19 | 20180327-01-update-form-constraints.js + 20 | 20180501-01-add-configs-timestamp.js + 21 | 20180501-02-fix-date-columns.js + 22 | 20180515-01-enforce-nonnull-form-version.js + 23 | 20180727-01-rename-attachments-table.js + 24 | 20180727-02-add-md5-to-blobs.js + 25 | 20180727-03-add-form-attachments-table.js + 26 | 20181011-make-email-case-insensitive.js + 27 | 20181012-01-add-submissions-createdat-index.js + 28 | 20181206-01-add-projects.js + 29 | 20181207-01-grant-verbs-to-text.js + 30 | 20181207-02-rename-grant-verbs.js + 31 | 20181211-01-audit-verbs-to-text.js + 32 | 20181211-02-rename-audit-actions.js + 33 | 20181212-00-fix-user-type.js + 34 | 20181212-01-add-roles.js + 35 | 20181212-02-remove-groups.js + 36 | 20181212-03-add-single-use-roles.js + 37 | 20181219-01-add-submission-update-verb.js + 38 | 20181221-01-nullable-submission-blobs.js + 39 | 20181230-01-add-device-id-to-submission.js + 40 | 20190225-01-add-actor-trigram-indices.js + 41 | 20190225-02-add-role-grants.js + 42 | 20190226-01-convert-verbs-to-jsonb.js + 43 | 20190226-02-add-role-actee-species.js + 44 | 20190226-03-add-assignment-verbs.js + 45 | 20190226-04-add-assignment-actee-species.js + 46 | 20190227-01-add-project-manager-role.js + 47 | 20190405-01-add-project-archival-flag.js + 48 | 20190416-01-email-uniqueness.js + 49 | 20190416-02-add-user-delete-verb.js + 50 | 20190520-01-add-form-versioning.js + 51 | 20190523-01-add-form-state-constraint.js + 52 | 20190605-01-reformat-audits.js + 53 | 20190607-01-convert-audit-details-to-jsonb.js + 54 | 20190607-02-standardize-attachment-actees.js + 55 | 20190607-03-rename-sub-attachment-audits.js + 56 | 20190610-01-add-audits-verbs.js + 57 | 20190610-02-backfill-submission-audit-instanceids.js + 58 | 20190611-01-add-updatedat-to-form-attachments.js + 59 | 20190618-01-add-csrf-token.js + 60 | 20190618-01-add-encryption-tracking.js + 61 | 20190701-01-add-managed-encryption-key-check.js + 62 | 20190916-01-granularize-app-user-permissions.js + 63 | 20190917-01-cleanup-app-user-role.js + 64 | 20190923-01-add-project-viewer-role.js + 65 | 20190925-01-add-client-audits.js + 66 | 20191007-01-backfill-client-audits.js + 67 | 20191010-01-add-excel-blob-reference.js + 68 | 20191023-01-add-worker-columns-to-audits.js + 69 | 20191025-01-add-id-to-audits.js + 70 | 20191106-01-remove-deleted-actor-assignments.js + 71 | 20191231-01-remove-transformations.js + 72 | 20191231-02-add-schema-storage.js + 73 | 20200110-01-add-drafts.js + 74 | 20200112-01-check-field-collisions.js + 75 | 20200114-01-remove-formid-sha256-constraint.js + 76 | 20200117-01-draft-test-submissions.js + 77 | 20200121-01-add-draft-keys.js + 78 | 20200122-01-remove-draft-form-state.js + 79 | 20200129-01-cascade-submission-deletes.js + 80 | 20200220-01-repair-submission-parsing.js + 81 | 20200403-01-add-performance-indices.js + 82 | 20200407-01-allow-actorless-submission-defs.js + 83 | 20200423-01-fix-field-insert-performance.js + 84 | 20200428-01-allow-string-downcast.js + 85 | 20200519-01-add-enketo-id.js +log '!!!' +echo '[test/db-partial-migrations/prepare] !!!' +log '!!! knex_migrations table content differences detected. See above for details.' +echo '[test/db-partial-migrations/prepare] !!! knex_migrations table content differences detected. See above for details.' +log '!!!' +echo '[test/db-partial-migrations/prepare] !!!' +exit 1 + 86 | 20200519-02-add-form-viewer-role.js + 87 | 20200520-01-backfill-enketo.js + 88 | 20200715-01-add-data-collector-role.js + 89 | 20200721-01-add-public-links.js + 90 | 20200728-01-add-enketo-single-token-to-forms.js + 91 | 20200731-01-allow-project-managers-to-end-sessions.js + 92 | 20200810-01-reschedule-enketo-processing.js + 93 | 20200918-01-repair-publishedat-dates.js + 94 | 20200930-01-add-backup-run-verb.js + 95 | 20201117-01-remove-deleted-actor-assignments-again.js + 96 | 20201207-01-harmonize-submitter-id-columns.js + 97 | 20210118-01-add-current-flag-to-submission-defs.js + 98 | 20210120-01-instance-names.js + 99 | 20210203-01-add-hierarchy-to-actees.js + 100 | 20210210-01-add-instanceid-to-submission-defs.js + 101 | 20210218-01-add-submission-edit-verbs.js + 102 | 20210218-02-add-draft-to-submissions-unique.js + 103 | 20210219-01-add-review-state.js + 104 | 20210219-02-add-notes-and-index-to-audits.js + 105 | 20210324-01-add-submission-edit-verbs-to-managers.js + 106 | 20210325-01-remove-project.list-verb.js + 107 | 20210408-01-drop-public-link-createdat.js + 108 | 20210408-02-backfill-specialized-actor-audits.js + 109 | 20210409-01-add-comments.js + 110 | 20210409-02-update-review-states.js + 111 | 20210423-01-add-name-to-form-def.js + 112 | 20210423-02-drop-form-name.js + 113 | 20210716-01-config-value-jsonb.js + 114 | 20210721-01-add-config-set-verb.js + 115 | 20210817-01-disallow-structure-downcast-to-string.js + 116 | 20210825-01-add-analytics-read-verb.js + 117 | 20210903-01-backfill-encrypted-client-audits.js + 118 | 20210927-01-revert-disallow-structure-downcast.js + 119 | 20211008-01-track-select-many-options.js + 120 | 20211021-remove-hashes-from-audits.js + 121 | 20211109-01-add-user-agent-to-submissions.js + 122 | 20211114-01-flag-initial-submission-def.js + 123 | 20211117-01-add-form-restore-verb.js + 124 | 20211129-01-add-purged-details-to-actees.js + 125 | 20220121-01-form-cascade-delete.js + 126 | 20220121-02-purge-deleted-forms.js + 127 | 20220209-01-purge-unneeded-drafts.js + 128 | 20220309-01-add-project-description.js + 129 | 20220803-01-create-entities-schema.js + 130 | 20221003-01-add-dataset-verbs.js + 131 | 20221114-01-explict-dataset-publish.js + 132 | 20221117-01-check-datasetId-is-null-for-non-file-type.js + 133 | 20221118-01-make-entities-columns-not-null.js + 134 | 20221208-01-reduce-tz-precision.js + 135 | 20230106-01-remove-revision-number.js + 136 | 20230109-01-add-form-schema.js + 137 | 20230123-01-remove-google-backups.js + 138 | 20230126-01-add-entity-indices.js + 139 | 20230127-01-rename-entity-created-by.js + 140 | 20230324-01-edit-dataset-verbs.js + 141 | 20230406-01-add-entity-def-fields.js + 142 | 20230406-02-move-entity-label-add-deletedAt.js + 143 | 20230414-01-remove-user-mfa-secret.js + 144 | 20230419-01-optimize-indices-sub-defs.js + 145 | 20230509-01-dataset-approval-flag.js + 146 | 20230512-01-add-entity-root.js + 147 | 20230512-02-backfill-entity-id.js + 148 | 20230512-03-add-entity-source.js + 149 | 20230518-01-add-entity-index-to-audits.js + 150 | 20230802-01-delete-orphan-submissions.js + 151 | 20230818-01-remove-schemaId-from-dsPropertyFields.js + 152 | 20230824-01-add-entity-version.js + 153 | 20230830-01-remove-entity-label-from-audits.js + 154 | 20230907-01-opened-form-verb.js + 155 | 20231002-01-add-conflict-details.js + 156 | 20231013-01-change-entity-error-action.js + 157 | 20231208-01-dataset-form-def-actions.js + 158 | 20240215-01-entity-delete-verb.js + 159 | 20240215-02-dedupe-verbs.js + 160 | 20240312-01-add-dataset-create-verb.js + 161 | 20240322-01-add-entity-source-index-to-audits.js + 162 | 20240515-01-entity-tz-precision.js + 163 | 20240607-01-add-offline-entity-branch-trunk-info.js + 164 | 20240607-02-add-submission-backlog.js + 165 | 20240715-01-backlog-add-event-entityuuid.js + 166 | 20240913-01-add-blob-s3.js + 167 | 20240914-01-add-submission-delete-verb.js + 168 | 20240914-02-remove-orphaned-client-audits.js + 169 | 20241001-01-index-on-session-table.js + 170 | 20241008-01-add-user_preferences.js + 171 | 20241010-01-schedule-entity-form-upgrade.js + 172 | 20241029-01-schedule-entity-form-upgrade-create-forms.js + 173 | 20241030-01-add-force-entity-def-source.js + 174 | 20241224-01-entity-restore-verb.js + 175 | 20241224-02-cascade-entity-purge.js + 176 | 20241226-01-indices-for-purging-entities.js + 177 | 20241227-01-backfill-audit-entity-uuid.js + 178 | 20250113-01-add-webformsenabled-formtable-column.js + 179 | 20250113-01-disable-nullable-blob-content-types.js + 180 | 20250221-01-deletedAt-index-entity.js + 181 | 20250307-01-purged-entities-table.js + 182 | 20250415-01-client-audit-remainder.js + 183 | 20250428-01-audit-indices.js +(183 rows) From 6fd9531e41b887d6d1ee358c2049e67c33419a12 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:05:54 +0000 Subject: [PATCH 124/133] trailing newline --- .../db-partial-migrations/expected-migrations-table-contents.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/test/db-partial-migrations/expected-migrations-table-contents.sql b/test/db-partial-migrations/expected-migrations-table-contents.sql index fdf4937f8..fae070cc7 100644 --- a/test/db-partial-migrations/expected-migrations-table-contents.sql +++ b/test/db-partial-migrations/expected-migrations-table-contents.sql @@ -191,3 +191,4 @@ exit 1 182 | 20250415-01-client-audit-remainder.js 183 | 20250428-01-audit-indices.js (183 rows) + From 1a7d8a787054dff1ed7a19ccf4abcabe2136d4fe Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:07:43 +0000 Subject: [PATCH 125/133] remove x --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index f96fa9180..1facebba5 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -1,4 +1,4 @@ -#!/bin/bash -eux +#!/bin/bash -eu set -o pipefail shopt -s inherit_errexit From 30b71b5c7cd4e87b9b0724940496fa75a81a155f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:08:10 +0000 Subject: [PATCH 126/133] remove random output in the middle --- .../expected-migrations-table-contents.sql | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/db-partial-migrations/expected-migrations-table-contents.sql b/test/db-partial-migrations/expected-migrations-table-contents.sql index fae070cc7..bb8d3f97f 100644 --- a/test/db-partial-migrations/expected-migrations-table-contents.sql +++ b/test/db-partial-migrations/expected-migrations-table-contents.sql @@ -85,13 +85,6 @@ 83 | 20200423-01-fix-field-insert-performance.js 84 | 20200428-01-allow-string-downcast.js 85 | 20200519-01-add-enketo-id.js -log '!!!' -echo '[test/db-partial-migrations/prepare] !!!' -log '!!! knex_migrations table content differences detected. See above for details.' -echo '[test/db-partial-migrations/prepare] !!! knex_migrations table content differences detected. See above for details.' -log '!!!' -echo '[test/db-partial-migrations/prepare] !!!' -exit 1 86 | 20200519-02-add-form-viewer-role.js 87 | 20200520-01-backfill-enketo.js 88 | 20200715-01-add-data-collector-role.js From ff0a10d99033a4b7f5e6d5c0df0adcf9ab437746 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:10:47 +0000 Subject: [PATCH 127/133] disable knex debug --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 1facebba5..871d8d852 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -81,7 +81,7 @@ log "Initial migrations structure:" show_migrations log "Running legacy migrations..." -DEBUG="knex:*" make migrations-legacy +make migrations-legacy log "Re-instating unrun migrations..." git checkout -- lib/model/migrations From 0271b3a1900e621e31941d9396d40329c9728d1f Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:20:35 +0000 Subject: [PATCH 128/133] check half way --- test/db-partial-migrations/test.sh | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 871d8d852..705cab04a 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -83,6 +83,22 @@ show_migrations log "Running legacy migrations..." make migrations-legacy +pgConnectionString="$(node -e ' + const { host, database, user, password } = require("config").get("default.database"); + console.log(`postgres://${user}:${password}@${host}/${database}`); +')" +migrationsTable="knex_migrations" + +expectedMigrations="$(find lib/model/migrations -maxdepth 1 -type f)" +actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT name FROM $migrationsTable")" +if ! diff <(echo "$expectedMigrations") <(echo "$actualMigrations"); then + log "!!!" + log "!!! Migration count ($actualCount) different from expected ($expectedCount)." + log "!!! There may have been an error running migrations..." + log "!!!" + exit 1 +fi + log "Re-instating unrun migrations..." git checkout -- lib/model/migrations git clean -dfx -- lib/model/migrations @@ -93,11 +109,6 @@ show_migrations log "Running modern migrations..." make migrations -pgConnectionString="$(node -e ' - const { host, database, user, password } = require("config").get("default.database"); - console.log(`postgres://${user}:${password}@${host}/${database}`); -')" - log "Checking final database schema..." if ! diff \ test/db-partial-migrations/expected-schema.sql \ @@ -110,13 +121,12 @@ if ! diff \ fi log "Checking migrations table..." -tableName="knex_migrations" if ! diff \ test/db-partial-migrations/expected-migrations-table-contents.sql \ - <(psql "$pgConnectionString" -c "SELECT id, name FROM $tableName"); then + <(psql "$pgConnectionString" -c "SELECT id, name FROM $migrationsTable"); then sleep 1 # wait for output to flush - seems slow in CI log "!!!" - log "!!! $tableName table content differences detected. See above for details." + log "!!! $migrationsTable table content differences detected. See above for details." log "!!!" exit 1 fi From 0391aff1d482ae6fcdb8b6a3723c0ea0398e5db5 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:21:15 +0000 Subject: [PATCH 129/133] wip --- test/db-partial-migrations/test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 705cab04a..aa06590e9 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -93,8 +93,7 @@ expectedMigrations="$(find lib/model/migrations -maxdepth 1 -type f)" actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT name FROM $migrationsTable")" if ! diff <(echo "$expectedMigrations") <(echo "$actualMigrations"); then log "!!!" - log "!!! Migration count ($actualCount) different from expected ($expectedCount)." - log "!!! There may have been an error running migrations..." + log "!!! Migrations ran differed from expected. See above for details." log "!!!" exit 1 fi From 77d8d6278b9591c2bb97826639991219769e54b5 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:22:49 +0000 Subject: [PATCH 130/133] just print name --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index aa06590e9..fbf002aa0 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -89,7 +89,7 @@ pgConnectionString="$(node -e ' ')" migrationsTable="knex_migrations" -expectedMigrations="$(find lib/model/migrations -maxdepth 1 -type f)" +expectedMigrations="$(find lib/model/migrations -maxdepth 1 -type f -printf '%p\n')" actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT name FROM $migrationsTable")" if ! diff <(echo "$expectedMigrations") <(echo "$actualMigrations"); then log "!!!" From 8048910084923672badcecba37f9da3f4fe016f7 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:25:58 +0000 Subject: [PATCH 131/133] prefixes --- test/db-partial-migrations/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index fbf002aa0..41e320af4 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -89,8 +89,8 @@ pgConnectionString="$(node -e ' ')" migrationsTable="knex_migrations" -expectedMigrations="$(find lib/model/migrations -maxdepth 1 -type f -printf '%p\n')" -actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT name FROM $migrationsTable")" +expectedMigrations="$(cd lib/model/migrations && find -maxdepth 1 -type f -printf '%p\n')" +actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT './' || name FROM $migrationsTable")" if ! diff <(echo "$expectedMigrations") <(echo "$actualMigrations"); then log "!!!" log "!!! Migrations ran differed from expected. See above for details." From 9b95483e597b5999310ac406830faeb81547535e Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:28:42 +0000 Subject: [PATCH 132/133] js only --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index 41e320af4..fdf236f25 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -89,7 +89,7 @@ pgConnectionString="$(node -e ' ')" migrationsTable="knex_migrations" -expectedMigrations="$(cd lib/model/migrations && find -maxdepth 1 -type f -printf '%p\n')" +expectedMigrations="$(cd lib/model/migrations && find -maxdepth 1 -type f -name \*.js -printf '%p\n')" actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT './' || name FROM $migrationsTable")" if ! diff <(echo "$expectedMigrations") <(echo "$actualMigrations"); then log "!!!" From 6089fbf5d94585cd4d55eddd8004c930dd80f113 Mon Sep 17 00:00:00 2001 From: alxndrsn Date: Fri, 2 May 2025 15:30:54 +0000 Subject: [PATCH 133/133] sort --- test/db-partial-migrations/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/db-partial-migrations/test.sh b/test/db-partial-migrations/test.sh index fdf236f25..a65bfc6d5 100755 --- a/test/db-partial-migrations/test.sh +++ b/test/db-partial-migrations/test.sh @@ -89,7 +89,7 @@ pgConnectionString="$(node -e ' ')" migrationsTable="knex_migrations" -expectedMigrations="$(cd lib/model/migrations && find -maxdepth 1 -type f -name \*.js -printf '%p\n')" +expectedMigrations="$(cd lib/model/migrations && find -maxdepth 1 -type f -name \*.js -printf '%p\n' | sort)" actualMigrations="$(psql --quiet --tuples-only --no-align "$pgConnectionString" -c "SELECT './' || name FROM $migrationsTable")" if ! diff <(echo "$expectedMigrations") <(echo "$actualMigrations"); then log "!!!"