feat: conditionally use transactions

This commit is contained in:
Elliot DeNolf
2023-08-10 13:54:04 -04:00
parent 7345fa8fcd
commit 791ed3be50
7 changed files with 47 additions and 100 deletions

61
.vscode/launch.json vendored
View File

@@ -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",
},

View File

@@ -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<void> {
await payload.db.db.execute(\`{{SQL}}\`);
${upSQL ? `await payload.db.db.execute(\`${upSQL}\`);` : '// Migration code'}
};
export async function down(payload: Payload): Promise<void> {
@@ -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

View File

@@ -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<T extends DatabaseAdapter>(args: MarkOptional<T,
| 'transaction'
| 'migrate'
@@ -19,7 +23,8 @@ export function createDatabaseAdapter<T extends DatabaseAdapter>(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<T extends DatabaseAdapter>(args: MarkOptio
migrateRefresh,
migrateReset,
migrateFresh: async () => null,
// Default 'null' transaction functions
beginTransaction,
commitTransaction,
rollbackTransaction,
...args,
} as T;
}

View File

@@ -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,

View File

@@ -21,10 +21,11 @@ export async function migrate(this: DatabaseAdapter): Promise<void> {
}
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<void> {
name: migration.name,
batch: newBatch,
},
req: {
transactionID,
} as PayloadRequest,
...(transactionID && { req: { transactionID } as PayloadRequest }),
});
await this.commitTransaction(transactionID);
} catch (err: unknown) {

View File

@@ -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);
});

View File

@@ -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<void> =>
// console.log('TODO: createMigration not implemented.'),
// migrate: async (): Promise<void> => console.log('TODO: migrate not implemented.'),
// migrateDown: async (): Promise<void> =>
// console.log('TODO: migrateDown not implemented.'),
// migrateRefresh: async (): Promise<void> =>
// console.log('TODO: migrateRefresh not implemented.'),
// migrateReset: async (): Promise<void> =>
// console.log('TODO: migrateReset not implemented.'),
// migrateFresh: async (): Promise<void> =>
// 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({});