feat: drizzle json generation

This commit is contained in:
Elliot DeNolf
2023-08-09 17:07:51 -04:00
parent 2f8549f331
commit cd447f1a9d
3 changed files with 46 additions and 14 deletions

View File

@@ -1,8 +1,9 @@
import fs from 'fs';
import { sql, eq } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/node-postgres';
import type { Connect } from 'payload/dist/database/types';
import { Client, Pool } from 'pg';
import { pushSchema } from 'drizzle-kit/utils';
import { generateDrizzleJson, pushSchema } from 'drizzle-kit/utils';
import { configToJSONSchema } from 'payload/dist/utilities/configToJSONSchema';
import prompts from 'prompts';
@@ -23,30 +24,30 @@ export const connect: Connect = async function connect(
) {
let db: DrizzleDB;
const schema: Record<string, GenericEnum | GenericTable | GenericRelation> = {};
this.schema = {};
Object.entries(this.tables).forEach(([key, val]) => {
schema[`${key}`] = val;
this.schema[`${key}`] = val;
});
Object.entries(this.relations).forEach(([key, val]) => {
schema[`${key}`] = val;
this.schema[`${key}`] = val;
});
Object.entries(this.enums).forEach(([key, val]) => {
schema[`${key}`] = val;
this.schema[`${key}`] = val;
});
try {
if ('pool' in this && this.pool !== false) {
const pool = new Pool(this.pool);
db = drizzle(pool, { schema });
db = drizzle(pool, { schema: this.schema });
await pool.connect();
}
if ('client' in this && this.client !== false) {
const client = new Client(this.client);
db = drizzle(client, { schema });
db = drizzle(client, { schema: this.schema });
await client.connect();
}
@@ -66,12 +67,11 @@ export const connect: Connect = async function connect(
this.payload.logger.info('Connected to Postgres successfully');
this.db = db;
// Only push schema if not in production
if (process.env.NODE_ENV === 'production') return;
// This will prompt if clarifications are needed for Drizzle to push new schema
const { hasDataLoss, warnings, statementsToExecute, apply } = await pushSchema(schema, this.db);
const { hasDataLoss, warnings, statementsToExecute, apply } = await pushSchema(this.schema, this.db);
this.payload.logger.debug({
msg: 'Schema push results',
@@ -113,6 +113,20 @@ export const connect: Connect = async function connect(
}
}
this.migrationDir = '.migrations';
// Create drizzle snapshot if it doesn't exist
if (!fs.existsSync(`${this.migrationDir}/drizzle-snapshot.json`)) {
// Ensure migration dir exists
if (!fs.existsSync(this.migrationDir)) {
fs.mkdirSync(this.migrationDir);
}
const drizzleJSON = generateDrizzleJson(this.schema);
fs.writeFileSync(`${this.migrationDir}/drizzle-snapshot.json`, JSON.stringify(drizzleJSON, null, 2));
}
const jsonSchema = configToJSONSchema(this.payload.config);
await apply();

View File

@@ -2,11 +2,21 @@
import fs from 'fs';
import { CreateMigration } from 'payload/dist/database/types';
import { generateDrizzleJson, generateMigration } from 'drizzle-kit/utils';
import { eq } from 'drizzle-orm';
import { jsonb, numeric, pgEnum, pgTable, varchar } from 'drizzle-orm/pg-core';
import { SanitizedCollectionConfig } from 'payload/dist/collections/config/types';
import type { DatabaseAdapter, Init } from 'payload/dist/database/types';
import { configToJSONSchema } from 'payload/dist/utilities/configToJSONSchema';
import prompts from 'prompts';
import { buildTable } from './schema/build';
import type { GenericEnum, GenericRelation, GenericTable, PostgresAdapter } from './types';
const migrationTemplate = `
import payload, { Payload } from 'payload';
export async function up(payload: Payload): Promise<void> {
{{SQL}}
await payload.db.db.execute(\`{{SQL}}\`);
};
export async function down(payload: Payload): Promise<void> {
@@ -14,11 +24,13 @@ export async function down(payload: Payload): Promise<void> {
};
`;
export const createMigration: CreateMigration = async function createMigration({
export const createMigration: CreateMigration = async function createMigration(
this: PostgresAdapter,
payload,
migrationDir,
migrationName,
}) {
) {
payload.logger.info({ msg: 'Creating migration from postgres adapter...' });
const dir = migrationDir || '.migrations'; // TODO: Verify path after linking
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
@@ -33,8 +45,12 @@ export const createMigration: CreateMigration = async function createMigration({
const formattedName = migrationName.replace(/\W/g, '_');
const fileName = `${timestamp}_${formattedName}.ts`;
const filePath = `${dir}/${fileName}`;
fs.writeFileSync(filePath, migrationTemplate);
payload.logger.info({ msg: `Migration created at ${filePath}` });
const snapshotJSON = fs.readFileSync(`${dir}/drizzle-snapshot.json`, 'utf8');
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')));
// TODO:
// Get the most recent migration schema from the file system

View File

@@ -9,6 +9,7 @@ export type DrizzleDB = NodePgDatabase<Record<string, never>>
type BaseArgs = {
migrationDir?: string;
migrationName?: string;
}
type ClientArgs = {
@@ -49,6 +50,7 @@ export type PostgresAdapter = DatabaseAdapter & Args & {
enums: Record<string, GenericEnum>
relations: Record<string, GenericRelation>
tables: Record<string, GenericTable>
schema: Record<string, GenericEnum | GenericTable | GenericRelation>
}
export type PostgresAdapterResult = (args: { payload: Payload }) => PostgresAdapter