From 791ed3be5045b514d5362f6467883ea5be6c4e67 Mon Sep 17 00:00:00 2001 From: Elliot DeNolf Date: Thu, 10 Aug 2023 13:54:04 -0400 Subject: [PATCH] feat: conditionally use transactions --- .vscode/launch.json | 61 +++++++------------ packages/db-postgres/src/createMigration.ts | 6 +- src/database/createAdapter.ts | 15 ++++- src/database/migrations/getMigrations.ts | 2 +- src/database/migrations/migrate.ts | 9 ++- src/database/migrations/readMigrationFiles.ts | 1 + test/migrations-cli/config.ts | 53 +--------------- 7 files changed, 47 insertions(+), 100 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 5660bf2361..7d7a32aabb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -33,54 +33,39 @@ "cwd": "${workspaceFolder}" }, { - "type": "node", - "request": "launch", - "name": "Migrate CLI - create", - "runtimeArgs": [ - "-r", - "ts-node/register" - ], - "args": [ - "src/bin/migrate.ts", - "migrate:create", - "second" - ], - "env": { - "PAYLOAD_CONFIG_PATH": "test/migrations-cli/config.ts" - }, - "outputCapture": "std", - }, - { - "type": "node", + "type": "node-terminal", + "command": "ts-node src/bin/migrate.ts migrate", "request": "launch", "name": "Migrate CLI - migrate", - "runtimeArgs": [ - "-r", - "ts-node/register" - ], - "args": [ - "src/bin/migrate.ts", - "migrate", - ], "env": { - "PAYLOAD_CONFIG_PATH": "test/migrations-cli/config.ts" + "PAYLOAD_CONFIG_PATH": "test/migrations-cli/config.ts", + "PAYLOAD_DATABASE": "postgres", + "PAYLOAD_DROP_DATABASE": "true", }, "outputCapture": "std", }, { - "type": "node", + "type": "node-terminal", + "command": "ts-node src/bin/migrate.ts migrate:status", "request": "launch", "name": "Migrate CLI - status", - "runtimeArgs": [ - "-r", - "ts-node/register" - ], - "args": [ - "src/bin/migrate.ts", - "migrate:status", - ], "env": { - "PAYLOAD_CONFIG_PATH": "test/migrations-cli/config.ts" + "PAYLOAD_CONFIG_PATH": "test/migrations-cli/config.ts", + "PAYLOAD_DATABASE": "postgres", + "PAYLOAD_DROP_DATABASE": "true", + }, + "outputCapture": "std", + }, + { + "type": "node-terminal", + "command": "ts-node src/bin/migrate.ts migrate:create yass", + "request": "launch", + "name": "Migrate CLI - create", + "env": { + // "PAYLOAD_CONFIG_PATH": "test/migrations-cli/config.ts", + "PAYLOAD_CONFIG_PATH": "test/postgres/config.ts", + "PAYLOAD_DATABASE": "postgres", + // "PAYLOAD_DROP_DATABASE": "true", }, "outputCapture": "std", }, diff --git a/packages/db-postgres/src/createMigration.ts b/packages/db-postgres/src/createMigration.ts index bf2c96df2d..65b3b23f04 100644 --- a/packages/db-postgres/src/createMigration.ts +++ b/packages/db-postgres/src/createMigration.ts @@ -12,11 +12,11 @@ import prompts from 'prompts'; import { buildTable } from './schema/build'; import type { GenericEnum, GenericRelation, GenericTable, PostgresAdapter } from './types'; -const migrationTemplate = ` +const migrationTemplate = (upSQL?: string) => ` import payload, { Payload } from 'payload'; export async function up(payload: Payload): Promise { - await payload.db.db.execute(\`{{SQL}}\`); + ${upSQL ? `await payload.db.db.execute(\`${upSQL}\`);` : '// Migration code'} }; export async function down(payload: Payload): Promise { @@ -50,7 +50,7 @@ export const createMigration: CreateMigration = async function createMigration( const drizzleJsonBefore = generateDrizzleJson(JSON.parse(snapshotJSON)); const drizzleJsonAfter = generateDrizzleJson(this.schema, drizzleJsonBefore.id); const sqlStatements = await generateMigration(drizzleJsonBefore, drizzleJsonAfter); - fs.writeFileSync(filePath, migrationTemplate.replace('{{SQL}}', sqlStatements.join('\n'))); + fs.writeFileSync(filePath, migrationTemplate(sqlStatements.length ? sqlStatements?.join('\n') : undefined)); // TODO: // Get the most recent migration schema from the file system diff --git a/src/database/createAdapter.ts b/src/database/createAdapter.ts index 6052c0318e..a2e03213cd 100644 --- a/src/database/createAdapter.ts +++ b/src/database/createAdapter.ts @@ -7,9 +7,13 @@ import { migrateStatus } from './migrations/migrateStatus'; import { migrateDown } from './migrations/migrateDown'; import { migrateRefresh } from './migrations/migrateRefresh'; import { migrateReset } from './migrations/migrateReset'; -import { DatabaseAdapter } from './types'; +import { BeginTransaction, CommitTransaction, DatabaseAdapter, RollbackTransaction } from './types'; import { createMigration } from './migrations/createMigration'; +const beginTransaction: BeginTransaction = async () => null; +const rollbackTransaction: RollbackTransaction = async () => null; +const commitTransaction: CommitTransaction = async () => null; + export function createDatabaseAdapter(args: MarkOptional(args: MarkOptio | 'migrateRefresh' | 'migrateReset' | 'migrateFresh' - | 'migrationDir'>): T { + | 'migrationDir' +>): T { // Need to implement DB Webpack config extensions here if (args.webpack) { const existingWebpackConfig = args.payload.config.admin.webpack ? args.payload.config.admin.webpack : (webpackConfig) => webpackConfig; @@ -39,6 +44,12 @@ export function createDatabaseAdapter(args: MarkOptio migrateRefresh, migrateReset, migrateFresh: async () => null, + + // Default 'null' transaction functions + beginTransaction, + commitTransaction, + rollbackTransaction, + ...args, } as T; } diff --git a/src/database/migrations/getMigrations.ts b/src/database/migrations/getMigrations.ts index ccb628c639..91f2ec6e27 100644 --- a/src/database/migrations/getMigrations.ts +++ b/src/database/migrations/getMigrations.ts @@ -19,7 +19,7 @@ export async function getMigrations({ const existingMigrations = migrationQuery.docs as unknown as MigrationData[]; // Get the highest batch number from existing migrations - const latestBatch = existingMigrations?.[0]?.batch || 0; + const latestBatch = Number(existingMigrations?.[0]?.batch) || 0; return { existingMigrations, diff --git a/src/database/migrations/migrate.ts b/src/database/migrations/migrate.ts index e4333960c5..85e29e0376 100644 --- a/src/database/migrations/migrate.ts +++ b/src/database/migrations/migrate.ts @@ -21,10 +21,11 @@ export async function migrate(this: DatabaseAdapter): Promise { } const start = Date.now(); - let transactionID; + let transactionID: string | number | undefined; + + payload.logger.info({ msg: `Migrating: ${migration.name}` }); try { - payload.logger.info({ msg: `Migrating: ${migration.name}` }); transactionID = await this.beginTransaction(); await migration.up({ payload }); payload.logger.info({ msg: `Migrated: ${migration.name} (${Date.now() - start}ms)` }); @@ -34,9 +35,7 @@ export async function migrate(this: DatabaseAdapter): Promise { name: migration.name, batch: newBatch, }, - req: { - transactionID, - } as PayloadRequest, + ...(transactionID && { req: { transactionID } as PayloadRequest }), }); await this.commitTransaction(transactionID); } catch (err: unknown) { diff --git a/src/database/migrations/readMigrationFiles.ts b/src/database/migrations/readMigrationFiles.ts index 48f2c4b45c..c83b80fd84 100644 --- a/src/database/migrations/readMigrationFiles.ts +++ b/src/database/migrations/readMigrationFiles.ts @@ -16,6 +16,7 @@ export const readMigrationFiles = async ({ const files = fs .readdirSync(payload.db.migrationDir) .sort() + .filter((f) => f.endsWith('.ts')) .map((file) => { return path.resolve(payload.db.migrationDir, file); }); diff --git a/test/migrations-cli/config.ts b/test/migrations-cli/config.ts index 90d82be741..f997362ce1 100644 --- a/test/migrations-cli/config.ts +++ b/test/migrations-cli/config.ts @@ -1,52 +1,3 @@ -/* eslint-disable no-console */ +import { buildConfigWithDefaults } from '../buildConfigWithDefaults'; -import path from 'path'; -import { buildConfig } from '../buildConfig'; -import { CollectionConfig } from '../../types'; -import { mongooseAdapter } from '../../src/mongoose'; -import payload from '../../src'; - -const Users: CollectionConfig = { - slug: 'users', - auth: true, - fields: [ - { - name: 'custom', - type: 'text', - }, - { - name: 'checkbox', - type: 'checkbox', - }, - ], -}; - -// // @ts-expect-error partial -// const mockAdapter: DatabaseAdapter = { -// // payload: undefined, -// migrationDir: path.resolve(__dirname, '.migrations'), -// migrateStatus: async () => console.log('TODO: migrateStatus not implemented.'), -// createMigration: async (): Promise => -// console.log('TODO: createMigration not implemented.'), -// migrate: async (): Promise => console.log('TODO: migrate not implemented.'), -// migrateDown: async (): Promise => -// console.log('TODO: migrateDown not implemented.'), -// migrateRefresh: async (): Promise => -// console.log('TODO: migrateRefresh not implemented.'), -// migrateReset: async (): Promise => -// console.log('TODO: migrateReset not implemented.'), -// migrateFresh: async (): Promise => -// console.log('TODO: migrateFresh not implemented.'), -// }; - -export default buildConfig({ - serverURL: 'http://localhost:3000', - admin: { - user: Users.slug, - }, - collections: [Users], - typescript: { - outputFile: path.resolve(__dirname, 'payload-types.ts'), - }, - db: mongooseAdapter({ payload, url: 'mongodb://127.0.0.1:27017/migrations-cli-test' }), -}); +export default buildConfigWithDefaults({});