1
0
Fork 0
mirror of synced 2024-06-27 18:40:42 +12:00
budibase/packages/backend-core/src/migrations/index.js
2022-01-24 10:48:59 +00:00

104 lines
3 KiB
JavaScript

const { DEFAULT_TENANT_ID } = require("../constants")
const { DocumentTypes } = require("../db/constants")
const { getAllApps } = require("../db/utils")
const environment = require("../environment")
const { doInTenant, getTenantIds, getGlobalDBName } = require("../tenancy")
exports.MIGRATION_TYPES = {
GLOBAL: "global", // run once, recorded in global db, global db is provided as an argument
APP: "app", // run per app, recorded in each app db, app db is provided as an argument
}
exports.getMigrationsDoc = async db => {
// get the migrations doc
try {
return await db.get(DocumentTypes.MIGRATIONS)
} catch (err) {
if (err.status && err.status === 404) {
return { _id: DocumentTypes.MIGRATIONS }
}
}
}
const runMigration = async (tenantId, CouchDB, migration, options = {}) => {
const migrationType = migration.type
const migrationName = migration.name
// get the db to store the migration in
let dbNames
if (migrationType === exports.MIGRATION_TYPES.GLOBAL) {
dbNames = [getGlobalDBName(tenantId)]
} else if (migrationType === exports.MIGRATION_TYPES.APP) {
dbNames = await getAllApps(CouchDB, { all: true })
} else {
throw new Error(
`[Tenant: ${tenantId}] Unrecognised migration type [${migrationType}]`
)
}
// run the migration against each db
for (const dbName of dbNames) {
const db = new CouchDB(dbName)
try {
const doc = await exports.getMigrationsDoc(db)
// exit if the migration has been performed already
if (doc[migrationName]) {
if (
options.force &&
options.force[migrationType] &&
options.force[migrationType].includes(migrationName)
) {
console.log(
`[Tenant: ${tenantId}] Forcing migration [${migrationName}]`
)
} else {
// the migration has already been performed
return
}
}
console.log(
`[Tenant: ${tenantId}] Performing migration: ${migrationName}`
)
// run the migration with tenant context
await doInTenant(tenantId, () => migration.fn(db))
console.log(`[Tenant: ${tenantId}] Migration complete: ${migrationName}`)
// mark as complete
doc[migrationName] = Date.now()
await db.put(doc)
} catch (err) {
console.error(
`[Tenant: ${tenantId}] Error performing migration: ${migrationName} on db: ${db.name}: `,
err
)
throw err
}
}
}
exports.runMigrations = async (CouchDB, migrations, options = {}) => {
console.log("Running migrations")
let tenantIds
if (environment.MULTI_TENANCY) {
if (!options.tenantIds || !options.tenantIds.length) {
// run for all tenants
tenantIds = await getTenantIds()
}
} else {
// single tenancy
tenantIds = [DEFAULT_TENANT_ID]
}
// for all tenants
for (const tenantId of tenantIds) {
// for all migrations
for (const migration of migrations) {
// run the migration
await runMigration(tenantId, CouchDB, migration, options)
}
}
console.log("Migrations complete")
}