@bobbykim/manguito-cms-db 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +61 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +770 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +727 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapters/postgres.ts","../src/codegen/index.ts","../src/seeder/index.ts","../src/migrations/index.ts","../src/migrations/scanner.ts"],"sourcesContent":["// @bobbykim/manguito-cms-db\n// Drizzle ORM adapters, migrations, and schema codegen.\n\nexport { sql } from 'drizzle-orm'\n\nexport { createPostgresAdapter } from './adapters/postgres'\nexport type { PostgresAdapterOptions } from './adapters/postgres'\nexport type { DrizzlePostgresInstance } from './types'\n\nexport { generateSchemaFile } from './codegen/index'\n\nexport { seedSystemTables } from './seeder/index'\nexport type { SeedResult, SeederOptions } from './types'\n\nexport {\n runDevMigration,\n generateMigration,\n applyMigrations,\n getMigrationStatus,\n} from './migrations/index'\n\nexport { scanMigrationFiles } from './migrations/scanner'\nexport type { ScanResult, DestructiveOperation } from './migrations/scanner'\n","import { drizzle as drizzleNode } from 'drizzle-orm/node-postgres'\nimport { drizzle as drizzleNeon } from 'drizzle-orm/neon-http'\nimport { neon } from '@neondatabase/serverless'\nimport { Pool } from 'pg'\nimport { sql } from 'drizzle-orm'\nimport type { PostgresAdapter, DrizzlePostgresInstance } from '../types'\n\nexport type PostgresAdapterOptions = {\n url?: string\n serverless?: boolean\n pool?: {\n max?: number\n idle_timeout?: number\n connect_timeout?: number\n }\n}\n\nexport function createPostgresAdapter(\n options: PostgresAdapterOptions = {}\n): PostgresAdapter {\n const url = options.url ?? process.env['DB_URL']\n\n if (!url) {\n throw new Error(\n 'DB_URL_MISSING: No database URL provided. ' +\n 'Set the DB_URL environment variable or pass a url option.'\n )\n }\n\n if (!/^postgres(?:ql)?:\\/\\//i.test(url)) {\n throw new Error(\n 'DB_URL_INVALID: Database URL must begin with postgres:// or postgresql://'\n )\n }\n\n const isNeon = options.serverless ?? url.includes('neon.tech')\n const poolConfig = {\n max: options.pool?.max ?? 10,\n idle_timeout: options.pool?.idle_timeout ?? 30,\n connect_timeout: options.pool?.connect_timeout ?? 10,\n }\n\n let db: DrizzlePostgresInstance | null = null\n let pool: Pool | null = null\n let connected = false\n\n return {\n type: 'postgres',\n\n async connect(): Promise<void> {\n if (isNeon) {\n const sqlClient = neon(url)\n db = drizzleNeon(sqlClient)\n } else {\n pool = new Pool({\n connectionString: url,\n max: poolConfig.max,\n idleTimeoutMillis: poolConfig.idle_timeout * 1000,\n connectionTimeoutMillis: poolConfig.connect_timeout * 1000,\n })\n const client = await pool.connect()\n client.release()\n db = drizzleNode(pool)\n }\n connected = true\n },\n\n async disconnect(): Promise<void> {\n // Close the pool so idle connections are released — otherwise the process\n // hangs on exit and the backend connections linger (which breaks, e.g.,\n // DROP DATABASE on the connected database). Neon's HTTP client is\n // stateless and needs no teardown.\n if (pool) {\n await pool.end()\n pool = null\n }\n db = null\n connected = false\n },\n\n isConnected(): boolean {\n return connected\n },\n\n getDb(): DrizzlePostgresInstance {\n if (!db) {\n throw new Error(\n 'DB not connected — call connect() before accessing the database.'\n )\n }\n return db\n },\n\n async getTableNames(): Promise<string[]> {\n if (!db) throw new Error('DB not connected')\n const result = await db.execute(\n sql`SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = 'public'\n ORDER BY table_name`\n )\n return result.rows.map((r) => (r as { table_name: string }).table_name)\n },\n\n async tableExists(name: string): Promise<boolean> {\n if (!db) throw new Error('DB not connected')\n const result = await db.execute(\n sql`SELECT 1\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_name = ${name}\n LIMIT 1`\n )\n return result.rows.length > 0\n },\n }\n}\n","import type {\n DbColumnType,\n ParsedField,\n ParsedParagraphType,\n SchemaRegistry,\n SystemField,\n} from '@bobbykim/manguito-cms-core'\n\n// ─── File Header ──────────────────────────────────────────────────────────────\n\nfunction generateFileHeader(): string {\n return (\n \"import * as s from 'drizzle-orm/pg-core'\\n\" +\n \"import { sql } from 'drizzle-orm'\"\n )\n}\n\n// ─── System Tables ────────────────────────────────────────────────────────────\n\nconst SYSTEM_TABLES_SECTION = `// ─── System Tables ──────────────────────────────────────────────────────────\nexport const media = s.pgTable('media', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n type: s.varchar('type', { length: 50 }).notNull(),\n url: s.varchar('url', { length: 2048 }).notNull(),\n mime_type: s.varchar('mime_type', { length: 255 }).notNull(),\n alt: s.varchar('alt', { length: 255 }),\n file_size: s.integer('file_size').notNull(),\n width: s.integer('width'),\n height: s.integer('height'),\n duration: s.integer('duration'),\n reference_count: s.integer('reference_count').notNull().default(0),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})\n\nexport const base_paths = s.pgTable('base_paths', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n name: s.varchar('name', { length: 255 }).notNull().unique(),\n path: s.varchar('path', { length: 1024 }).notNull().unique(),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})\n\nexport const roles = s.pgTable('roles', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n name: s.varchar('name', { length: 255 }).notNull().unique(),\n label: s.varchar('label', { length: 255 }).notNull(),\n is_system: s.boolean('is_system').notNull().default(false),\n hierarchy_level: s.integer('hierarchy_level').notNull().unique(),\n permissions: s.text('permissions').array().notNull(),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})\n\nexport const users = s.pgTable('users', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n email: s.varchar('email', { length: 255 }).notNull().unique(),\n password_hash: s.varchar('password_hash', { length: 255 }).notNull(),\n role_id: s.uuid('role_id')\n .notNull()\n .references(() => roles.id, { onDelete: 'restrict' }),\n token_version: s.integer('token_version').notNull().default(0),\n must_change_password: s.boolean('must_change_password').notNull().default(false),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})`\n\n// ─── Column Generators ────────────────────────────────────────────────────────\n\nexport function generateSystemFieldColumn(field: SystemField): string {\n const { name, db_type, primary_key, default: defaultVal, nullable } = field\n const col = buildSystemBase(name, db_type, primary_key, defaultVal)\n return primary_key || nullable ? col : col + '.notNull()'\n}\n\nfunction buildSystemBase(\n name: string,\n db_type: SystemField['db_type'],\n primary_key: boolean | undefined,\n defaultVal: string | undefined,\n): string {\n switch (db_type) {\n case 'uuid':\n return primary_key\n ? `s.uuid('${name}').primaryKey().defaultRandom()`\n : `s.uuid('${name}')`\n case 'varchar':\n return `s.varchar('${name}')`\n case 'boolean': {\n const suffix =\n defaultVal === 'false'\n ? '.default(false)'\n : defaultVal === 'true'\n ? '.default(true)'\n : ''\n return `s.boolean('${name}')${suffix}`\n }\n case 'timestamp':\n return defaultVal === 'now()'\n ? `s.timestamp('${name}').defaultNow()`\n : `s.timestamp('${name}')`\n case 'integer':\n return defaultVal !== undefined\n ? `s.integer('${name}').default(${Number(defaultVal)})`\n : `s.integer('${name}')`\n }\n}\n\nfunction mapOnDelete(\n on_delete: 'CASCADE' | 'SET NULL' | 'RESTRICT',\n): string {\n if (on_delete === 'CASCADE') return 'cascade'\n if (on_delete === 'SET NULL') return 'set null'\n return 'restrict'\n}\n\nexport function generateFieldColumn(field: ParsedField): string | null {\n if (field.field_type === 'paragraph' || field.db_column === null) return null\n\n const col = field.db_column\n if (col.junction) return null\n\n const n = col.column_name\n const isEnum =\n col.check_constraint !== undefined && col.check_constraint.length > 0\n\n let expr = buildFieldBase(n, col.column_type, isEnum, field.validation.limit)\n\n if (!col.nullable) expr += '.notNull()'\n\n if (col.foreign_key) {\n const onDelete = mapOnDelete(col.foreign_key.on_delete)\n expr += `.references(() => ${col.foreign_key.table}.${col.foreign_key.column}, { onDelete: '${onDelete}' })`\n }\n\n return expr\n}\n\nfunction buildFieldBase(\n name: string,\n column_type: DbColumnType,\n isEnum: boolean,\n limit: number | undefined,\n): string {\n switch (column_type) {\n case 'varchar':\n return isEnum\n ? `s.varchar('${name}')`\n : `s.varchar('${name}', { length: ${limit ?? 255} })`\n case 'text':\n return `s.text('${name}')`\n case 'integer':\n return `s.integer('${name}')`\n case 'decimal':\n return `s.decimal('${name}', { precision: 10, scale: 4 })`\n case 'boolean':\n return `s.boolean('${name}')`\n case 'timestamp':\n return `s.timestamp('${name}')`\n case 'uuid':\n return `s.uuid('${name}')`\n }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction tableNameToVarName(tableName: string): string {\n return tableName.replace(/-/g, '_')\n}\n\nfunction generateTableDef(\n tableName: string,\n varName: string,\n systemFields: SystemField[],\n fields: ParsedField[],\n): string {\n const colLines: string[] = []\n\n for (const f of systemFields) {\n colLines.push(`${f.name}: ${generateSystemFieldColumn(f)},`)\n }\n\n for (const f of fields) {\n const colExpr = generateFieldColumn(f)\n if (colExpr === null) continue\n colLines.push(`${f.db_column!.column_name}: ${colExpr},`)\n }\n\n const enumFields = fields.filter(\n (f) => (f.db_column?.check_constraint?.length ?? 0) > 0,\n )\n\n if (enumFields.length === 0) {\n const colBlock = colLines.map((l) => ` ${l}`).join('\\n')\n return `export const ${varName} = s.pgTable('${tableName}', {\\n${colBlock}\\n})`\n }\n\n const colBlock = colLines.map((l) => ` ${l}`).join('\\n')\n const constraints = enumFields\n .map((f) => {\n const col = f.db_column!\n const values = col.check_constraint!.map((v) => `'${v}'`).join(', ')\n const cname = `${col.column_name}_check`\n return [\n ` ${cname}: s.check(`,\n ` '${cname}',`,\n ` sql\\`\\${table.${col.column_name}} IN (${values})\\``,\n ` ),`,\n ].join('\\n')\n })\n .join('\\n')\n\n return [\n `export const ${varName} = s.pgTable(`,\n ` '${tableName}',`,\n ` {`,\n colBlock,\n ` },`,\n ` (table) => ({`,\n constraints,\n ` })`,\n `)`,\n ].join('\\n')\n}\n\n// ─── Paragraph Topological Sort ───────────────────────────────────────────────\n\nexport function orderParagraphTypes(\n paragraphs: Record<string, ParsedParagraphType>,\n): ParsedParagraphType[] {\n const sorted: ParsedParagraphType[] = []\n const visited = new Set<string>()\n\n function visit(name: string) {\n if (visited.has(name)) return\n visited.add(name)\n const paragraph = paragraphs[name]\n if (!paragraph) return\n for (const field of paragraph.fields) {\n if (field.field_type === 'paragraph') {\n const ref = (field.ui_component as { ref: string }).ref\n visit(ref)\n }\n }\n sorted.push(paragraph)\n }\n\n for (const name of Object.keys(paragraphs)) visit(name)\n return sorted\n}\n\n// ─── Junction Table Generation ────────────────────────────────────────────────\n\nfunction generateJunctionTables(registry: SchemaRegistry): string {\n const tables: string[] = []\n\n for (const ct of Object.values(registry.content_types)) {\n const leftVar = tableNameToVarName(ct.db.table_name)\n\n for (const jt of ct.db.junction_tables) {\n const varName = tableNameToVarName(jt.table_name)\n const rightVar = tableNameToVarName(jt.right_table)\n\n const orderLine = jt.order_column\n ? ` order: s.integer('order').notNull().default(0),`\n : null\n\n const def = [\n `export const ${varName} = s.pgTable(`,\n ` '${jt.table_name}',`,\n ` {`,\n ` ${jt.left_column}: s.uuid('${jt.left_column}')`,\n ` .notNull()`,\n ` .references(() => ${leftVar}.id, { onDelete: 'cascade' }),`,\n ` ${jt.right_column}: s.uuid('${jt.right_column}')`,\n ` .notNull()`,\n ` .references(() => ${rightVar}.id, { onDelete: 'cascade' }),`,\n ...(orderLine ? [orderLine] : []),\n ` }`,\n `)`,\n ].join('\\n')\n\n tables.push(def)\n }\n }\n\n if (tables.length === 0) return ''\n\n return (\n '// ─── Junction Tables ─────────────────────────────────────────────────────────\\n' +\n tables.join('\\n\\n')\n )\n}\n\n// ─── generateSchemaFile ───────────────────────────────────────────────────────\n\nexport function generateSchemaFile(registry: SchemaRegistry): string {\n const sections: string[] = [generateFileHeader(), SYSTEM_TABLES_SECTION]\n\n const taxonomyTypes = Object.values(registry.taxonomy_types)\n if (taxonomyTypes.length > 0) {\n const header =\n '// ─── Taxonomy Types ──────────────────────────────────────────────────────────'\n const defs = taxonomyTypes.map((t) =>\n generateTableDef(\n t.db.table_name,\n tableNameToVarName(t.db.table_name),\n t.system_fields,\n t.fields,\n ),\n )\n sections.push(header + '\\n' + defs.join('\\n\\n'))\n }\n\n const paragraphTypes = orderParagraphTypes(registry.paragraph_types)\n if (paragraphTypes.length > 0) {\n const header =\n '// ─── Paragraph Types ─────────────────────────────────────────────────────────'\n const defs = paragraphTypes.map((p) =>\n generateTableDef(\n p.db.table_name,\n tableNameToVarName(p.db.table_name),\n p.system_fields,\n p.fields,\n ),\n )\n sections.push(header + '\\n' + defs.join('\\n\\n'))\n }\n\n const contentTypes = Object.values(registry.content_types)\n if (contentTypes.length > 0) {\n const header =\n '// ─── Content Types ───────────────────────────────────────────────────────────'\n const defs = contentTypes.map((c) =>\n generateTableDef(\n c.db.table_name,\n tableNameToVarName(c.db.table_name),\n c.system_fields,\n c.fields,\n ),\n )\n sections.push(header + '\\n' + defs.join('\\n\\n'))\n }\n\n const junctionSection = generateJunctionTables(registry)\n if (junctionSection) sections.push(junctionSection)\n\n return sections.join('\\n\\n')\n}\n","import { and, eq, inArray, sql } from 'drizzle-orm'\nimport * as s from 'drizzle-orm/pg-core'\nimport type {\n ParsedRoles,\n ParsedRoutes,\n SchemaRegistry,\n} from '@bobbykim/manguito-cms-core'\nimport type { DrizzlePostgresInstance, SeederOptions, SeedResult } from '../types'\n\n// ─── System Table Schema Objects ──────────────────────────────────────────────\n\nconst base_paths = s.pgTable('base_paths', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n name: s.varchar('name', { length: 255 }).notNull().unique(),\n path: s.varchar('path', { length: 1024 }).notNull().unique(),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})\n\nconst roles = s.pgTable('roles', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n name: s.varchar('name', { length: 255 }).notNull().unique(),\n label: s.varchar('label', { length: 255 }).notNull(),\n is_system: s.boolean('is_system').notNull().default(false),\n hierarchy_level: s.integer('hierarchy_level').notNull().unique(),\n permissions: s.text('permissions').array().notNull(),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})\n\nconst users = s.pgTable('users', {\n id: s.uuid('id').primaryKey().defaultRandom(),\n email: s.varchar('email', { length: 255 }).notNull().unique(),\n password_hash: s.varchar('password_hash', { length: 255 }).notNull(),\n role_id: s.uuid('role_id')\n .notNull()\n .references(() => roles.id, { onDelete: 'restrict' }),\n token_version: s.integer('token_version').notNull().default(0),\n created_at: s.timestamp('created_at').defaultNow().notNull(),\n updated_at: s.timestamp('updated_at').defaultNow().notNull(),\n})\n\n// ─── checkBasePathsInUse ──────────────────────────────────────────────────────\n\nasync function checkBasePathsInUse(\n db: DrizzlePostgresInstance,\n basePathNames: string[],\n): Promise<string[]> {\n const rows = await db\n .select({ id: base_paths.id, name: base_paths.name })\n .from(base_paths)\n .where(inArray(base_paths.name, basePathNames))\n\n if (rows.length === 0) return []\n\n const ids = rows.map((r) => `'${r.id}'`).join(', ')\n\n const tablesResult = await db.execute(\n sql`SELECT table_name\n FROM information_schema.columns\n WHERE table_schema = 'public'\n AND column_name = 'base_path_id'`,\n )\n\n const inUse: string[] = []\n\n for (const row of tablesResult.rows) {\n const tableName = (row as { table_name: string }).table_name\n const countResult = await db.execute(\n sql.raw(\n `SELECT COUNT(*) as count FROM \"${tableName}\"\n WHERE base_path_id IN (${ids})`,\n ),\n )\n const count = parseInt(\n ((countResult.rows[0] as { count: string }).count),\n 10,\n )\n if (count > 0) inUse.push(tableName)\n }\n\n return inUse\n}\n\n// ─── seedRoles ────────────────────────────────────────────────────────────────\n\nasync function seedRoles(\n db: DrizzlePostgresInstance,\n parsedRoles: ParsedRoles,\n dryRun: boolean,\n): Promise<SeedResult['roles']> {\n const existing = await db.select({ name: roles.name }).from(roles)\n const existingNames = new Set(existing.map((r) => r.name))\n const incomingNames = new Set(parsedRoles.roles.map((r) => r.name))\n\n const toDelete = [...existingNames].filter((n) => !incomingNames.has(n))\n\n if (toDelete.length > 0) {\n // Protect built-in roles: a role stored with is_system must not be removed\n // by dropping it from roles.json — that would delete, e.g., `admin` and lock\n // everyone out. To remove one deliberately, re-seed it with is_system: false\n // first, then remove it from roles.json.\n const systemRoles = await db\n .select({ name: roles.name })\n .from(roles)\n .where(and(inArray(roles.name, toDelete), eq(roles.is_system, true)))\n\n if (systemRoles.length > 0) {\n throw new Error(\n `SEEDER_SYSTEM_ROLE: Cannot remove system role(s) [${systemRoles.map((r) => r.name).join(', ')}] ` +\n `from roles.json — they are marked is_system and are protected from deletion. ` +\n `Re-seed the role with is_system: false first if you intend to remove it.`,\n )\n }\n\n const affected = await db\n .select({ id: users.id, email: users.email })\n .from(users)\n .innerJoin(roles, eq(users.role_id, roles.id))\n .where(inArray(roles.name, toDelete))\n\n if (affected.length > 0) {\n throw new Error(\n `SEEDER_ROLE_IN_USE: Cannot remove role(s) [${toDelete.join(', ')}] ` +\n `from roles.json — ${affected.length} user(s) are still assigned to them: ` +\n `${affected.map((u) => u.email).join(', ')}. ` +\n `Reassign those users to another role before removing it from roles.json.`,\n )\n }\n\n if (!dryRun) {\n await db.delete(roles).where(inArray(roles.name, toDelete))\n }\n }\n\n const inserted: string[] = []\n const updated: string[] = []\n\n for (const role of parsedRoles.roles) {\n if (!existingNames.has(role.name)) inserted.push(role.name)\n else updated.push(role.name)\n }\n\n if (!dryRun) {\n await db\n .insert(roles)\n .values(\n parsedRoles.roles.map((r) => ({\n name: r.name,\n label: r.label,\n is_system: r.is_system ?? false,\n hierarchy_level: r.hierarchy_level,\n permissions: r.permissions,\n })),\n )\n .onConflictDoUpdate({\n target: roles.name,\n set: {\n label: sql`excluded.label`,\n is_system: sql`excluded.is_system`,\n hierarchy_level: sql`excluded.hierarchy_level`,\n permissions: sql`excluded.permissions`,\n updated_at: sql`now()`,\n },\n })\n }\n\n return {\n inserted: inserted.length,\n updated: updated.length,\n deleted: toDelete.length,\n }\n}\n\n// ─── seedBasePaths ────────────────────────────────────────────────────────────\n\nasync function seedBasePaths(\n db: DrizzlePostgresInstance,\n parsedRoutes: ParsedRoutes,\n dryRun: boolean,\n): Promise<SeedResult['base_paths']> {\n const existing = await db.select({ name: base_paths.name }).from(base_paths)\n const existingNames = new Set(existing.map((r) => r.name))\n const incomingNames = new Set(parsedRoutes.base_paths.map((r) => r.name))\n\n const toDelete = [...existingNames].filter((n) => !incomingNames.has(n))\n\n if (toDelete.length > 0) {\n const inUse = await checkBasePathsInUse(db, toDelete)\n\n if (inUse.length > 0) {\n throw new Error(\n `SEEDER_BASE_PATH_IN_USE: Cannot remove base path(s) [${toDelete.join(', ')}] ` +\n `from routes.json — content items are still referencing them ` +\n `(${inUse.join(', ')}). ` +\n `Update or delete that content before removing the base path.`,\n )\n }\n\n if (!dryRun) {\n await db.delete(base_paths).where(inArray(base_paths.name, toDelete))\n }\n }\n\n const inserted: string[] = []\n const updated: string[] = []\n\n for (const bp of parsedRoutes.base_paths) {\n if (!existingNames.has(bp.name)) inserted.push(bp.name)\n else updated.push(bp.name)\n }\n\n if (!dryRun) {\n await db\n .insert(base_paths)\n .values(parsedRoutes.base_paths)\n .onConflictDoUpdate({\n target: base_paths.name,\n set: {\n path: sql`excluded.path`,\n updated_at: sql`now()`,\n },\n })\n }\n\n return {\n inserted: inserted.length,\n updated: updated.length,\n deleted: toDelete.length,\n }\n}\n\n// ─── seedSystemTables ─────────────────────────────────────────────────────────\n\nexport async function seedSystemTables(\n db: DrizzlePostgresInstance,\n registry: SchemaRegistry,\n options: SeederOptions = {},\n): Promise<SeedResult> {\n const dryRun = options.dryRun ?? false\n\n const rolesResult = await seedRoles(db, registry.roles, dryRun)\n const basePathsResult = await seedBasePaths(db, registry.routes, dryRun)\n\n return {\n roles: rolesResult,\n base_paths: basePathsResult,\n }\n}\n","import { execSync, spawnSync } from 'node:child_process'\nimport crypto from 'node:crypto'\nimport path from 'node:path'\nimport fs from 'node:fs/promises'\nimport { sql } from 'drizzle-orm'\nimport type { MigrationResult, MigrationStatus } from '@bobbykim/manguito-cms-core'\nimport type { DrizzlePostgresInstance, MigrationRunnerOptions } from '../types'\n\n// drizzle-kit is invoked as a bare command resolved via PATH, but these calls\n// run with `cwd` set to the generated config's directory — which has no\n// node_modules of its own. Package managers put `node_modules/.bin` on PATH as\n// a *relative* entry (`./node_modules/.bin`), which stops resolving once the\n// child process's cwd changes. Resolve any relative PATH entries against the\n// original working directory (and prepend the project-local bin) so the bare\n// `drizzle-kit` command is found regardless of the child's cwd.\nfunction resolvedPathEnv(): NodeJS.ProcessEnv {\n const root = process.cwd()\n const localBin = path.join(root, 'node_modules', '.bin')\n const existing = (process.env.PATH ?? '')\n .split(path.delimiter)\n .filter(Boolean)\n .map((entry) => (path.isAbsolute(entry) ? entry : path.resolve(root, entry)))\n return { ...process.env, PATH: [localBin, ...existing].join(path.delimiter) }\n}\n\nexport async function runDevMigration(configPath: string): Promise<void> {\n execSync(`drizzle-kit push --config=${configPath}`, {\n stdio: 'inherit',\n cwd: path.dirname(configPath),\n env: resolvedPathEnv(),\n })\n}\n\nexport async function generateMigration(\n configPath: string,\n migrationsFolder: string,\n): Promise<string[]> {\n let beforeFiles: string[] = []\n try {\n const entries = await fs.readdir(migrationsFolder)\n beforeFiles = entries.filter((f) => f.endsWith('.sql'))\n } catch {\n // folder doesn't exist yet — no prior migrations\n }\n\n execSync(`drizzle-kit generate --config=${configPath}`, {\n stdio: 'inherit',\n cwd: path.dirname(configPath),\n env: resolvedPathEnv(),\n })\n\n let afterFiles: string[] = []\n try {\n const entries = await fs.readdir(migrationsFolder)\n afterFiles = entries.filter((f) => f.endsWith('.sql'))\n } catch {\n // folder still doesn't exist after generate — nothing created\n }\n\n const beforeSet = new Set(beforeFiles)\n return afterFiles.filter((f) => !beforeSet.has(f))\n}\n\nexport async function applyMigrations(\n configPath: string,\n db: DrizzlePostgresInstance,\n options: MigrationRunnerOptions,\n): Promise<MigrationResult> {\n const { migrationsTable, migrationsFolder } = options\n\n // Pre-create the tracking table with a plain nullable `id` (not SERIAL) so\n // drizzle-kit finds it already exists and skips its own CREATE TABLE. A\n // SERIAL column would add a sequence that drizzle-kit push tries to drop\n // (non-fatally, but noisily) since the table is excluded via tablesFilter.\n // The `id` column itself can't be dropped, though — drizzle-orm's migrator\n // runs `select id, hash, created_at from ...` regardless of which tool\n // created the table, so it must exist.\n await db.execute(\n sql.raw(\n `CREATE TABLE IF NOT EXISTS \"${migrationsTable}\" (id integer, hash text NOT NULL, created_at bigint)`,\n ),\n )\n // Backfill `id` on tables created by older versions of this function\n // (before the `id` column was added to the CREATE statement above).\n await db.execute(\n sql.raw(`ALTER TABLE \"${migrationsTable}\" ADD COLUMN IF NOT EXISTS id integer`),\n )\n\n // Reconcile migrations that are pending in the tracking table but already\n // applied in the DB — the typical result of running `manguito dev` (which\n // uses drizzle-kit push and never writes to the tracking table) before\n // `manguito migrate`. For each pending migration, check whether the first\n // table it creates already exists in Postgres. If it does, seed the\n // tracking record so drizzle-kit migrate treats it as applied.\n const statusBefore = await getMigrationStatus(db, options)\n if (statusBefore.pending.length > 0) {\n type JournalEntry = { when: number; tag: string }\n let journalEntries: JournalEntry[] = []\n try {\n const journalPath = path.join(migrationsFolder, 'meta', '_journal.json')\n const raw = await fs.readFile(journalPath, 'utf-8')\n journalEntries = (JSON.parse(raw) as { entries: JournalEntry[] }).entries\n } catch { /* no journal — skip reconciliation */ }\n\n for (const pendingFile of statusBefore.pending) {\n const sqlPath = path.join(migrationsFolder, pendingFile)\n let sqlContent: string\n try {\n sqlContent = await fs.readFile(sqlPath, 'utf-8')\n } catch { continue }\n\n // Extract the first table name from the migration SQL.\n const tableMatch = sqlContent.match(/CREATE TABLE (?:IF NOT EXISTS )?\"([^\"]+)\"/)\n if (!tableMatch) continue\n const tableName = tableMatch[1]\n\n const checkResult = await db.execute(\n sql.raw(`SELECT to_regclass('\"${tableName}\"') AS t`),\n )\n const tableExists = (checkResult.rows[0] as { t: string | null } | undefined)?.t !== null\n\n if (!tableExists) continue\n\n // Table already exists — seed the tracking record.\n const entry = journalEntries.find((e) => `${e.tag}.sql` === pendingFile)\n if (!entry) continue\n const hash = crypto.createHash('sha256').update(sqlContent).digest('hex')\n await db.execute(\n sql.raw(\n `INSERT INTO \"${migrationsTable}\" (hash, created_at) ` +\n `SELECT '${hash}', ${entry.when} ` +\n `WHERE NOT EXISTS (SELECT 1 FROM \"${migrationsTable}\" WHERE created_at = ${entry.when})`,\n ),\n )\n }\n }\n\n // After reconciliation, re-check status. If all pending migrations are now\n // marked applied (by the reconciliation above), skip drizzle-kit migrate —\n // there is nothing for it to do and it would fail on \"relation already exists\".\n const statusAfter = await getMigrationStatus(db, options)\n if (statusAfter.pending.length === 0) {\n return { applied: statusAfter.applied.length, skipped: 0 }\n }\n\n const result = spawnSync(\n 'drizzle-kit',\n ['migrate', `--config=${configPath}`],\n {\n cwd: path.dirname(configPath),\n // inherit lets drizzle-kit write its spinner and errors directly to the\n // terminal in real time — capturing stdout/stderr swallows ANSI overwrites\n // and hides the actual error message.\n stdio: 'inherit',\n env: { ...resolvedPathEnv(), NODE_NO_WARNINGS: '1' },\n },\n )\n if (result.error) {\n throw new Error(`Failed to spawn drizzle-kit: ${result.error.message}`)\n }\n if (result.status !== 0) {\n throw new Error(\n `drizzle-kit migrate exited with status ${String(result.status ?? 1)} — see output above for details`\n )\n }\n\n const status = await getMigrationStatus(db, options)\n return {\n applied: status.applied.length,\n skipped: 0,\n }\n}\n\nexport async function getMigrationStatus(\n db: DrizzlePostgresInstance,\n options: MigrationRunnerOptions,\n): Promise<MigrationStatus> {\n const { migrationsTable, migrationsFolder } = options\n\n // drizzle-kit tracks migrations by content hash and a bigint timestamp.\n // The journal maps filenames (via tag + .sql) to the `when` timestamp value\n // that drizzle-kit inserts into the tracking table's `created_at` column.\n type JournalEntry = { when: number; tag: string }\n let journalEntries: JournalEntry[]\n try {\n const journalPath = path.join(migrationsFolder, 'meta', '_journal.json')\n const raw = await fs.readFile(journalPath, 'utf-8')\n const journal = JSON.parse(raw) as { entries: JournalEntry[] }\n journalEntries = journal.entries\n } catch {\n return { applied: [], pending: [] }\n }\n\n const appliedWhenSet = new Set<number>()\n try {\n const result = await db.execute(\n sql.raw(`SELECT created_at FROM \"${migrationsTable}\"`),\n )\n for (const row of result.rows) {\n appliedWhenSet.add(Number((row as { created_at: string | number }).created_at))\n }\n } catch {\n // table doesn't exist yet — no migrations applied\n }\n\n const applied: string[] = []\n const pending: string[] = []\n for (const entry of journalEntries) {\n const filename = `${entry.tag}.sql`\n if (appliedWhenSet.has(entry.when)) {\n applied.push(filename)\n } else {\n pending.push(filename)\n }\n }\n\n return { applied, pending }\n}\n","import { readFileSync } from 'node:fs'\nimport path from 'node:path'\n\nexport type DestructiveOperation = {\n file: string\n operation: string\n pattern: 'DROP_COLUMN' | 'DROP_TABLE' | 'ALTER_COLUMN_TYPE'\n}\n\nexport type ScanResult = {\n hasDestructiveOperations: boolean\n operations: DestructiveOperation[]\n}\n\nfunction formatDropColumn(line: string): string {\n const upper = line.toUpperCase()\n const tableStart = upper.indexOf('ALTER TABLE') + 'ALTER TABLE'.length\n const dropIdx = upper.indexOf('DROP COLUMN')\n const colStart = dropIdx + 'DROP COLUMN'.length\n\n if (tableStart < 0 || dropIdx < 0) return line.trim()\n\n const tableName = line.slice(tableStart, dropIdx).trim().replace(/\"/g, '').replace(/;/g, '')\n const colName = (line.slice(colStart).trim().replace(/\"/g, '').split(/\\s+/)[0] ?? '').replace(/;/g, '')\n\n if (!tableName || !colName) return line.trim()\n\n return `DROP COLUMN ${tableName}.${colName}`\n}\n\nfunction formatDropTable(line: string): string {\n const upper = line.toUpperCase()\n const tableStart = upper.indexOf('DROP TABLE') + 'DROP TABLE'.length\n\n if (tableStart < 'DROP TABLE'.length) return line.trim()\n\n const tableName = (line.slice(tableStart).trim().replace(/\"/g, '').split(/\\s+/)[0] ?? '').replace(/;/g, '')\n\n if (!tableName) return line.trim()\n\n return `DROP TABLE ${tableName}`\n}\n\nfunction formatAlterColumnType(line: string): string {\n const upper = line.toUpperCase()\n const tableStart = upper.indexOf('ALTER TABLE') + 'ALTER TABLE'.length\n const alterColIdx = upper.indexOf('ALTER COLUMN')\n const colStart = alterColIdx + 'ALTER COLUMN'.length\n const typeIdx = upper.indexOf(' TYPE ', colStart)\n\n if (tableStart < 0 || alterColIdx < 0 || typeIdx < 0) return line.trim()\n\n const tableName = line.slice(tableStart, alterColIdx).trim().replace(/\"/g, '')\n const colName = line.slice(colStart, typeIdx).trim().replace(/\"/g, '')\n const newType = (line.slice(typeIdx + ' TYPE '.length).trim().split(/\\s+/)[0] ?? '').replace(/;/g, '')\n\n if (!tableName || !colName || !newType) return line.trim()\n\n return `ALTER COLUMN ${tableName}.${colName} TYPE ${newType}`\n}\n\nexport function scanMigrationFiles(filePaths: string[]): ScanResult {\n const operations: DestructiveOperation[] = []\n\n for (const filePath of filePaths) {\n const content = readFileSync(filePath, 'utf-8')\n const lines = content.split('\\n')\n const filename = path.basename(filePath)\n\n for (const line of lines) {\n const upper = line.trim().toUpperCase()\n\n if (upper.includes('DROP COLUMN')) {\n operations.push({\n file: filename,\n operation: formatDropColumn(line),\n pattern: 'DROP_COLUMN',\n })\n } else if (upper.includes('DROP TABLE')) {\n operations.push({\n file: filename,\n operation: formatDropTable(line),\n pattern: 'DROP_TABLE',\n })\n } else if (upper.includes('ALTER COLUMN') && upper.includes(' TYPE ')) {\n operations.push({\n file: filename,\n operation: formatAlterColumnType(line),\n pattern: 'ALTER_COLUMN_TYPE',\n })\n }\n }\n }\n\n return {\n hasDestructiveOperations: operations.length > 0,\n operations,\n }\n}\n"],"mappings":"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","names":["sql","colBlock","sql","sql","path"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bobbykim/manguito-cms-db",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=22.0.0"
|
|
6
|
+
},
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"module": "./dist/index.mjs",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@neondatabase/serverless": "^1.1.0",
|
|
22
|
+
"drizzle-kit": "^0.31.10",
|
|
23
|
+
"drizzle-orm": "^0.45.2",
|
|
24
|
+
"pg": "^8.22.0",
|
|
25
|
+
"@bobbykim/manguito-cms-core": "0.1.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25.9.5",
|
|
29
|
+
"@types/pg": "^8.20.0",
|
|
30
|
+
"dotenv-cli": "latest",
|
|
31
|
+
"tsup": "^8.5.1",
|
|
32
|
+
"typescript": "^6.0.3",
|
|
33
|
+
"vitest": "^4.1.10",
|
|
34
|
+
"@bobbykim/manguito-cms-test-utils": "0.0.1"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"dev": "tsup --watch",
|
|
39
|
+
"test": "dotenv -e .env.test -- vitest run",
|
|
40
|
+
"lint": "eslint src"
|
|
41
|
+
}
|
|
42
|
+
}
|