@digilogiclabs/platform-core 1.2.0 → 1.4.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/migrate.js CHANGED
@@ -62,10 +62,11 @@ function toPoolConfig(config) {
62
62
  }
63
63
  return poolConfig;
64
64
  }
65
- var PostgresDatabase, TransactionDatabase, PostgresQueryBuilder;
65
+ var import_crypto, PostgresDatabase, TransactionDatabase, PostgresQueryBuilder;
66
66
  var init_PostgresDatabase = __esm({
67
67
  "src/adapters/postgres/PostgresDatabase.ts"() {
68
68
  "use strict";
69
+ import_crypto = require("crypto");
69
70
  PostgresDatabase = class _PostgresDatabase {
70
71
  pool;
71
72
  config;
@@ -91,12 +92,17 @@ var init_PostgresDatabase = __esm({
91
92
  const config = {
92
93
  connectionString: process.env.DATABASE_URL,
93
94
  host: process.env.POSTGRES_HOST ?? process.env.PGHOST,
94
- port: parseInt(process.env.POSTGRES_PORT ?? process.env.PGPORT ?? "5432", 10),
95
+ port: parseInt(
96
+ process.env.POSTGRES_PORT ?? process.env.PGPORT ?? "5432",
97
+ 10
98
+ ),
95
99
  database: process.env.POSTGRES_DATABASE ?? process.env.PGDATABASE,
96
100
  user: process.env.POSTGRES_USER ?? process.env.PGUSER,
97
101
  password: process.env.POSTGRES_PASSWORD ?? process.env.PGPASSWORD,
98
102
  max: parseInt(process.env.POSTGRES_POOL_MAX ?? "10", 10),
99
- ssl: process.env.POSTGRES_SSL === "true" ? { rejectUnauthorized: process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== "false" } : void 0,
103
+ ssl: process.env.POSTGRES_SSL === "true" ? {
104
+ rejectUnauthorized: process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== "false"
105
+ } : void 0,
100
106
  applicationName: process.env.POSTGRES_APP_NAME ?? "platform-core"
101
107
  };
102
108
  return _PostgresDatabase.create(config);
@@ -181,7 +187,7 @@ var init_PostgresDatabase = __esm({
181
187
  }
182
188
  }
183
189
  async transaction(fn) {
184
- const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2)}`;
190
+ const savepointName = `sp_${Date.now()}_${(0, import_crypto.randomBytes)(4).toString("hex")}`;
185
191
  try {
186
192
  await this.client.query(`SAVEPOINT ${savepointName}`);
187
193
  const result = await fn(this);
@@ -292,12 +298,16 @@ var init_PostgresDatabase = __esm({
292
298
  let sql = `SELECT ${selectClause} FROM ${this.tableName}`;
293
299
  const whereClauses = [];
294
300
  for (const { column, operator, value } of this._where) {
295
- whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);
301
+ whereClauses.push(
302
+ `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`
303
+ );
296
304
  params.push(value);
297
305
  }
298
306
  for (const { column, values } of this._whereIn) {
299
307
  const placeholders = values.map(() => `$${paramIndex++}`).join(", ");
300
- whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);
308
+ whereClauses.push(
309
+ `${this.escapeIdentifier(column)} IN (${placeholders})`
310
+ );
301
311
  params.push(...values);
302
312
  }
303
313
  if (whereClauses.length > 0) {
@@ -362,12 +372,16 @@ var init_PostgresDatabase = __esm({
362
372
  let sql = `UPDATE ${this.tableName} SET ${setClauses.join(", ")}`;
363
373
  const whereClauses = [];
364
374
  for (const { column, operator, value } of this._where) {
365
- whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);
375
+ whereClauses.push(
376
+ `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`
377
+ );
366
378
  params.push(value);
367
379
  }
368
380
  for (const { column, values } of this._whereIn) {
369
381
  const placeholders = values.map(() => `$${paramIndex++}`).join(", ");
370
- whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);
382
+ whereClauses.push(
383
+ `${this.escapeIdentifier(column)} IN (${placeholders})`
384
+ );
371
385
  params.push(...values);
372
386
  }
373
387
  if (whereClauses.length > 0) {
@@ -386,12 +400,16 @@ var init_PostgresDatabase = __esm({
386
400
  let sql = `DELETE FROM ${this.tableName}`;
387
401
  const whereClauses = [];
388
402
  for (const { column, operator, value } of this._where) {
389
- whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);
403
+ whereClauses.push(
404
+ `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`
405
+ );
390
406
  params.push(value);
391
407
  }
392
408
  for (const { column, values } of this._whereIn) {
393
409
  const placeholders = values.map(() => `$${paramIndex++}`).join(", ");
394
- whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);
410
+ whereClauses.push(
411
+ `${this.escapeIdentifier(column)} IN (${placeholders})`
412
+ );
395
413
  params.push(...values);
396
414
  }
397
415
  if (whereClauses.length > 0) {
@@ -653,7 +671,9 @@ var Migrator = class {
653
671
  if (!dryRun) {
654
672
  const acquired = await this.lock();
655
673
  if (!acquired) {
656
- throw new Error("Could not acquire migration lock. Another migration may be in progress.");
674
+ throw new Error(
675
+ "Could not acquire migration lock. Another migration may be in progress."
676
+ );
657
677
  }
658
678
  }
659
679
  try {
@@ -662,7 +682,9 @@ var Migrator = class {
662
682
  if (to) {
663
683
  const targetIndex = pending.findIndex((m) => m.version === to);
664
684
  if (targetIndex === -1) {
665
- throw new Error(`Target version ${to} not found in pending migrations`);
685
+ throw new Error(
686
+ `Target version ${to} not found in pending migrations`
687
+ );
666
688
  }
667
689
  pending = pending.slice(0, targetIndex + 1);
668
690
  }
@@ -689,14 +711,18 @@ var Migrator = class {
689
711
  if (!dryRun) {
690
712
  const acquired = await this.lock();
691
713
  if (!acquired) {
692
- throw new Error("Could not acquire migration lock. Another migration may be in progress.");
714
+ throw new Error(
715
+ "Could not acquire migration lock. Another migration may be in progress."
716
+ );
693
717
  }
694
718
  }
695
719
  try {
696
720
  const status = await this.status();
697
721
  const toRollback = status.applied.slice(-steps).reverse();
698
722
  for (const record of toRollback) {
699
- const migration = this.migrations.find((m) => m.version === record.version);
723
+ const migration = this.migrations.find(
724
+ (m) => m.version === record.version
725
+ );
700
726
  if (!migration) {
701
727
  throw new Error(
702
728
  `Migration ${record.version} was applied but is not registered. Cannot rollback.`
@@ -744,10 +770,16 @@ var Migrator = class {
744
770
  if (isUp) {
745
771
  return this.up({ ...options, to: version });
746
772
  } else {
747
- const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);
748
- const targetIndex = status.applied.findIndex((m) => m.version === version);
773
+ const currentIndex = status.applied.findIndex(
774
+ (m) => m.version === currentVersion
775
+ );
776
+ const targetIndex = status.applied.findIndex(
777
+ (m) => m.version === version
778
+ );
749
779
  if (targetIndex === -1) {
750
- throw new Error(`Target version ${version} not found in applied migrations`);
780
+ throw new Error(
781
+ `Target version ${version} not found in applied migrations`
782
+ );
751
783
  }
752
784
  const steps = currentIndex - targetIndex;
753
785
  return this.down({ ...options, steps });
@@ -791,13 +823,17 @@ var Migrator = class {
791
823
  await this.db.raw(
792
824
  `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)
793
825
  VALUES ($1, $2, $3, $4)`,
794
- [migration.version, migration.name, executionTime, migration.checksum]
826
+ [
827
+ migration.version,
828
+ migration.name,
829
+ executionTime,
830
+ migration.checksum
831
+ ]
795
832
  );
796
833
  } else {
797
- await this.db.raw(
798
- `DELETE FROM ${this.tableName} WHERE version = $1`,
799
- [migration.version]
800
- );
834
+ await this.db.raw(`DELETE FROM ${this.tableName} WHERE version = $1`, [
835
+ migration.version
836
+ ]);
801
837
  }
802
838
  return {
803
839
  migration,
@@ -862,7 +898,9 @@ var Migrator = class {
862
898
  return { valid: true, errors };
863
899
  }
864
900
  for (const applied of status.applied) {
865
- const migration = this.migrations.find((m) => m.version === applied.version);
901
+ const migration = this.migrations.find(
902
+ (m) => m.version === applied.version
903
+ );
866
904
  if (!migration) {
867
905
  errors.push(
868
906
  `Migration ${applied.version} (${applied.name}) was applied but is not registered`
@@ -956,9 +994,13 @@ function formatResults(results) {
956
994
  const status = result.dryRun ? "[DRY RUN]" : "";
957
995
  const time = result.success ? `(${result.executionTime}ms)` : "";
958
996
  if (result.success) {
959
- console.log(` ${icon} ${result.migration.version} - ${result.migration.name} ${time} ${status}`);
997
+ console.log(
998
+ ` ${icon} ${result.migration.version} - ${result.migration.name} ${time} ${status}`
999
+ );
960
1000
  } else {
961
- console.error(` ${icon} ${result.migration.version} - ${result.migration.name}`);
1001
+ console.error(
1002
+ ` ${icon} ${result.migration.version} - ${result.migration.name}`
1003
+ );
962
1004
  console.error(` Error: ${result.error?.message}`);
963
1005
  }
964
1006
  }
@@ -989,7 +1031,9 @@ async function main() {
989
1031
  await migrator.loadMigrations(options.migrationsDir);
990
1032
  } catch (e) {
991
1033
  if (options.command !== "create") {
992
- console.warn(`Warning: Could not load migrations from ${options.migrationsDir}`);
1034
+ console.warn(
1035
+ `Warning: Could not load migrations from ${options.migrationsDir}`
1036
+ );
993
1037
  }
994
1038
  }
995
1039
  switch (options.command) {
@@ -1001,7 +1045,9 @@ async function main() {
1001
1045
  console.log(`
1002
1046
  Applied (${status.applied.length}):`);
1003
1047
  for (const m of status.applied) {
1004
- console.log(` \u2713 ${m.version} - ${m.name} (${m.appliedAt.toISOString()})`);
1048
+ console.log(
1049
+ ` \u2713 ${m.version} - ${m.name} (${m.appliedAt.toISOString()})`
1050
+ );
1005
1051
  }
1006
1052
  console.log(`
1007
1053
  Pending (${status.pending.length}):`);
@@ -1011,7 +1057,9 @@ Pending (${status.pending.length}):`);
1011
1057
  break;
1012
1058
  }
1013
1059
  case "up": {
1014
- console.log(options.dryRun ? "\n=== Dry Run: Migrate Up ===\n" : "\n=== Migrating Up ===\n");
1060
+ console.log(
1061
+ options.dryRun ? "\n=== Dry Run: Migrate Up ===\n" : "\n=== Migrating Up ===\n"
1062
+ );
1015
1063
  const results = await migrator.up({
1016
1064
  dryRun: options.dryRun,
1017
1065
  to: options.to
@@ -1023,7 +1071,9 @@ Pending (${status.pending.length}):`);
1023
1071
  break;
1024
1072
  }
1025
1073
  case "down": {
1026
- console.log(options.dryRun ? "\n=== Dry Run: Rollback ===\n" : "\n=== Rolling Back ===\n");
1074
+ console.log(
1075
+ options.dryRun ? "\n=== Dry Run: Rollback ===\n" : "\n=== Rolling Back ===\n"
1076
+ );
1027
1077
  const results = await migrator.down({
1028
1078
  dryRun: options.dryRun,
1029
1079
  steps: options.steps
@@ -1035,7 +1085,9 @@ Pending (${status.pending.length}):`);
1035
1085
  break;
1036
1086
  }
1037
1087
  case "reset": {
1038
- console.log(options.dryRun ? "\n=== Dry Run: Reset ===\n" : "\n=== Resetting Database ===\n");
1088
+ console.log(
1089
+ options.dryRun ? "\n=== Dry Run: Reset ===\n" : "\n=== Resetting Database ===\n"
1090
+ );
1039
1091
  const results = await migrator.reset({ dryRun: options.dryRun });
1040
1092
  formatResults(results);
1041
1093
  if (results.some((r) => !r.success)) {
@@ -1045,13 +1097,17 @@ Pending (${status.pending.length}):`);
1045
1097
  }
1046
1098
  case "goto": {
1047
1099
  if (!options.name) {
1048
- console.error("Error: Version required. Usage: platform-migrate goto <version>");
1100
+ console.error(
1101
+ "Error: Version required. Usage: platform-migrate goto <version>"
1102
+ );
1049
1103
  process.exit(1);
1050
1104
  }
1051
1105
  console.log(`
1052
1106
  === Migrating to Version ${options.name} ===
1053
1107
  `);
1054
- const results = await migrator.goto(options.name, { dryRun: options.dryRun });
1108
+ const results = await migrator.goto(options.name, {
1109
+ dryRun: options.dryRun
1110
+ });
1055
1111
  formatResults(results);
1056
1112
  if (results.some((r) => !r.success)) {
1057
1113
  process.exit(1);
@@ -1060,7 +1116,9 @@ Pending (${status.pending.length}):`);
1060
1116
  }
1061
1117
  case "create": {
1062
1118
  if (!options.name) {
1063
- console.error("Error: Migration name required. Usage: platform-migrate create <name>");
1119
+ console.error(
1120
+ "Error: Migration name required. Usage: platform-migrate create <name>"
1121
+ );
1064
1122
  process.exit(1);
1065
1123
  }
1066
1124
  const filePath = await migrator.create(options.name);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/postgres/PostgresDatabase.ts","../src/migrations/Migrator.ts","../src/migrations/cli.ts"],"sourcesContent":["/**\r\n * PostgreSQL Direct Database Adapter\r\n *\r\n * Production implementation using pg (node-postgres) for direct PostgreSQL connections.\r\n * Provides true ACID transaction support, connection pooling, and prepared statements.\r\n *\r\n * This adapter is vendor-agnostic - works with any PostgreSQL-compatible database:\r\n * - PostgreSQL (self-hosted or managed)\r\n * - Amazon RDS PostgreSQL\r\n * - Azure Database for PostgreSQL\r\n * - Google Cloud SQL for PostgreSQL\r\n * - CockroachDB (PostgreSQL wire protocol)\r\n * - YugabyteDB\r\n * - Neon, Supabase (direct connection, not REST)\r\n */\r\n\r\nimport type { Pool, PoolClient, PoolConfig, QueryResult as PgQueryResult } from 'pg';\r\nimport { IDatabase, IQueryBuilder, QueryResult } from '../../interfaces/IDatabase';\r\n\r\nexport interface PostgresConfig {\r\n /** Connection string (postgresql://user:pass@host:port/database) */\r\n connectionString?: string;\r\n\r\n /** Host name */\r\n host?: string;\r\n\r\n /** Port number */\r\n port?: number;\r\n\r\n /** Database name */\r\n database?: string;\r\n\r\n /** Username */\r\n user?: string;\r\n\r\n /** Password */\r\n password?: string;\r\n\r\n /** SSL configuration */\r\n ssl?: boolean | { rejectUnauthorized?: boolean; ca?: string };\r\n\r\n /** Maximum number of connections in pool */\r\n max?: number;\r\n\r\n /** Idle timeout in milliseconds */\r\n idleTimeoutMillis?: number;\r\n\r\n /** Connection timeout in milliseconds */\r\n connectionTimeoutMillis?: number;\r\n\r\n /** Statement timeout in milliseconds (0 = no limit) */\r\n statementTimeout?: number;\r\n\r\n /** Query timeout in milliseconds (0 = no limit) */\r\n queryTimeout?: number;\r\n\r\n /** Application name for connection identification */\r\n applicationName?: string;\r\n}\r\n\r\n/**\r\n * Convert our config to pg pool config\r\n */\r\nfunction toPoolConfig(config: PostgresConfig): PoolConfig {\r\n const poolConfig: PoolConfig = {};\r\n\r\n if (config.connectionString) {\r\n poolConfig.connectionString = config.connectionString;\r\n } else {\r\n poolConfig.host = config.host;\r\n poolConfig.port = config.port;\r\n poolConfig.database = config.database;\r\n poolConfig.user = config.user;\r\n poolConfig.password = config.password;\r\n }\r\n\r\n if (config.ssl !== undefined) {\r\n poolConfig.ssl = config.ssl;\r\n }\r\n\r\n poolConfig.max = config.max ?? 10;\r\n poolConfig.idleTimeoutMillis = config.idleTimeoutMillis ?? 30000;\r\n poolConfig.connectionTimeoutMillis = config.connectionTimeoutMillis ?? 10000;\r\n poolConfig.application_name = config.applicationName ?? 'platform-core';\r\n\r\n // Statement timeout\r\n if (config.statementTimeout) {\r\n poolConfig.statement_timeout = config.statementTimeout;\r\n }\r\n\r\n // Query timeout\r\n if (config.queryTimeout) {\r\n poolConfig.query_timeout = config.queryTimeout;\r\n }\r\n\r\n return poolConfig;\r\n}\r\n\r\nexport class PostgresDatabase implements IDatabase {\r\n private pool: Pool;\r\n private config: PostgresConfig;\r\n\r\n constructor(pool: Pool, config: PostgresConfig = {}) {\r\n this.pool = pool;\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create a PostgresDatabase from configuration\r\n */\r\n static async create(config: PostgresConfig): Promise<PostgresDatabase> {\r\n // Dynamic import to keep pg as optional peer dependency\r\n const { Pool } = await import('pg');\r\n const poolConfig = toPoolConfig(config);\r\n const pool = new Pool(poolConfig);\r\n\r\n // Test connection\r\n const client = await pool.connect();\r\n client.release();\r\n\r\n return new PostgresDatabase(pool, config);\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<PostgresDatabase> {\r\n const config: PostgresConfig = {\r\n connectionString: process.env.DATABASE_URL,\r\n host: process.env.POSTGRES_HOST ?? process.env.PGHOST,\r\n port: parseInt(process.env.POSTGRES_PORT ?? process.env.PGPORT ?? '5432', 10),\r\n database: process.env.POSTGRES_DATABASE ?? process.env.PGDATABASE,\r\n user: process.env.POSTGRES_USER ?? process.env.PGUSER,\r\n password: process.env.POSTGRES_PASSWORD ?? process.env.PGPASSWORD,\r\n max: parseInt(process.env.POSTGRES_POOL_MAX ?? '10', 10),\r\n ssl:\r\n process.env.POSTGRES_SSL === 'true'\r\n ? { rejectUnauthorized: process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== 'false' }\r\n : undefined,\r\n applicationName: process.env.POSTGRES_APP_NAME ?? 'platform-core',\r\n };\r\n\r\n return PostgresDatabase.create(config);\r\n }\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new PostgresQueryBuilder<T>(this.pool, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n try {\r\n const result: PgQueryResult = await this.pool.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Execute a function within a database transaction.\r\n * Provides true ACID guarantees - either all operations succeed or all are rolled back.\r\n */\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n const client = await this.pool.connect();\r\n\r\n try {\r\n await client.query('BEGIN');\r\n\r\n // Create a transaction-scoped database instance\r\n const txDatabase = new TransactionDatabase(client);\r\n\r\n const result = await fn(txDatabase);\r\n\r\n await client.query('COMMIT');\r\n return result;\r\n } catch (error) {\r\n await client.query('ROLLBACK');\r\n throw error;\r\n } finally {\r\n client.release();\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.pool.query('SELECT 1 as health');\r\n return result.rows.length > 0;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.pool.end();\r\n }\r\n\r\n /**\r\n * Get pool statistics for monitoring\r\n */\r\n getPoolStats(): {\r\n totalCount: number;\r\n idleCount: number;\r\n waitingCount: number;\r\n } {\r\n return {\r\n totalCount: this.pool.totalCount,\r\n idleCount: this.pool.idleCount,\r\n waitingCount: this.pool.waitingCount,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transaction-scoped database that uses a single client connection\r\n */\r\nclass TransactionDatabase implements IDatabase {\r\n constructor(private client: PoolClient) {}\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new PostgresQueryBuilder<T>(this.client, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n try {\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n // Nested transaction using savepoint\r\n const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2)}`;\r\n\r\n try {\r\n await this.client.query(`SAVEPOINT ${savepointName}`);\r\n const result = await fn(this);\r\n await this.client.query(`RELEASE SAVEPOINT ${savepointName}`);\r\n return result;\r\n } catch (error) {\r\n await this.client.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);\r\n throw error;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n await this.client.query('SELECT 1');\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Transaction database doesn't own the client, so don't close\r\n }\r\n}\r\n\r\n/**\r\n * PostgreSQL Query Builder\r\n */\r\nclass PostgresQueryBuilder<T = unknown> implements IQueryBuilder<T> {\r\n private client: Pool | PoolClient;\r\n private tableName: string;\r\n private _select: string[] = ['*'];\r\n private _where: Array<{ column: string; operator: string; value: unknown }> = [];\r\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\r\n private _orderBy: { column: string; direction: 'asc' | 'desc' } | null = null;\r\n private _limit: number | null = null;\r\n private _offset: number = 0;\r\n private _insertData: Partial<T>[] | null = null;\r\n private _updateData: Partial<T> | null = null;\r\n private _deleteFlag: boolean = false;\r\n private _returning: string[] = ['*'];\r\n\r\n constructor(client: Pool | PoolClient, tableName: string) {\r\n this.client = client;\r\n this.tableName = this.escapeIdentifier(tableName);\r\n }\r\n\r\n select(columns?: string | string[]): IQueryBuilder<T> {\r\n if (columns) {\r\n this._select = Array.isArray(columns) ? columns : [columns];\r\n }\r\n return this;\r\n }\r\n\r\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\r\n this._insertData = Array.isArray(data) ? data : [data];\r\n return this;\r\n }\r\n\r\n update(data: Partial<T>): IQueryBuilder<T> {\r\n this._updateData = data;\r\n return this;\r\n }\r\n\r\n delete(): IQueryBuilder<T> {\r\n this._deleteFlag = true;\r\n return this;\r\n }\r\n\r\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\r\n this._where.push({ column, operator, value });\r\n return this;\r\n }\r\n\r\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\r\n this._whereIn.push({ column, values });\r\n return this;\r\n }\r\n\r\n orderBy(column: string, direction: 'asc' | 'desc' = 'asc'): IQueryBuilder<T> {\r\n this._orderBy = { column, direction };\r\n return this;\r\n }\r\n\r\n limit(count: number): IQueryBuilder<T> {\r\n this._limit = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): IQueryBuilder<T> {\r\n this._offset = count;\r\n return this;\r\n }\r\n\r\n async single(): Promise<{ data: T | null; error?: Error }> {\r\n this._limit = 1;\r\n const result = await this.execute();\r\n\r\n if (result.error) {\r\n return { data: null, error: result.error };\r\n }\r\n\r\n return { data: result.data[0] ?? null };\r\n }\r\n\r\n async execute(): Promise<QueryResult<T>> {\r\n try {\r\n if (this._insertData) {\r\n return await this.executeInsert();\r\n }\r\n\r\n if (this._updateData) {\r\n return await this.executeUpdate();\r\n }\r\n\r\n if (this._deleteFlag) {\r\n return await this.executeDelete();\r\n }\r\n\r\n return await this.executeSelect();\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n private async executeSelect(): Promise<QueryResult<T>> {\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SELECT clause\r\n const selectClause = this._select.map((col) => this.escapeIdentifier(col)).join(', ');\r\n let sql = `SELECT ${selectClause} FROM ${this.tableName}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n // Build ORDER BY\r\n if (this._orderBy) {\r\n sql += ` ORDER BY ${this.escapeIdentifier(this._orderBy.column)} ${this._orderBy.direction.toUpperCase()}`;\r\n }\r\n\r\n // Build LIMIT and OFFSET\r\n if (this._limit !== null) {\r\n sql += ` LIMIT $${paramIndex++}`;\r\n params.push(this._limit);\r\n }\r\n\r\n if (this._offset > 0) {\r\n sql += ` OFFSET $${paramIndex++}`;\r\n params.push(this._offset);\r\n }\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeInsert(): Promise<QueryResult<T>> {\r\n if (!this._insertData || this._insertData.length === 0) {\r\n return { data: [] };\r\n }\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Get all unique columns from the data\r\n const columns = new Set<string>();\r\n for (const row of this._insertData) {\r\n Object.keys(row as object).forEach((key) => columns.add(key));\r\n }\r\n const columnList = Array.from(columns);\r\n\r\n // Build column list\r\n const columnClause = columnList.map((col) => this.escapeIdentifier(col)).join(', ');\r\n\r\n // Build values\r\n const valueRows: string[] = [];\r\n for (const row of this._insertData) {\r\n const rowValues: string[] = [];\r\n for (const col of columnList) {\r\n rowValues.push(`$${paramIndex++}`);\r\n params.push((row as Record<string, unknown>)[col] ?? null);\r\n }\r\n valueRows.push(`(${rowValues.join(', ')})`);\r\n }\r\n\r\n const sql = `INSERT INTO ${this.tableName} (${columnClause}) VALUES ${valueRows.join(', ')} RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeUpdate(): Promise<QueryResult<T>> {\r\n if (!this._updateData) {\r\n return { data: [] };\r\n }\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SET clause\r\n const setClauses: string[] = [];\r\n for (const [key, value] of Object.entries(this._updateData as object)) {\r\n setClauses.push(`${this.escapeIdentifier(key)} = $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n let sql = `UPDATE ${this.tableName} SET ${setClauses.join(', ')}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n sql += ` RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeDelete(): Promise<QueryResult<T>> {\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n let sql = `DELETE FROM ${this.tableName}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n sql += ` RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private escapeIdentifier(identifier: string): string {\r\n // Handle special cases\r\n if (identifier === '*') return '*';\r\n\r\n // Handle schema.table notation\r\n if (identifier.includes('.')) {\r\n return identifier\r\n .split('.')\r\n .map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`)\r\n .join('.');\r\n }\r\n\r\n // Escape identifier with double quotes\r\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n\r\n private mapOperator(operator: string): string {\r\n switch (operator.toLowerCase()) {\r\n case '=':\r\n case '==':\r\n return '=';\r\n case '!=':\r\n case '<>':\r\n return '<>';\r\n case '<':\r\n return '<';\r\n case '<=':\r\n return '<=';\r\n case '>':\r\n return '>';\r\n case '>=':\r\n return '>=';\r\n case 'like':\r\n return 'LIKE';\r\n case 'ilike':\r\n return 'ILIKE';\r\n case 'is':\r\n return 'IS';\r\n case 'is not':\r\n return 'IS NOT';\r\n default:\r\n return '=';\r\n }\r\n }\r\n}\r\n","/**\r\n * Database Migrator\r\n *\r\n * Enterprise-grade database migration system supporting:\r\n * - PostgreSQL (primary)\r\n * - Memory database (for testing)\r\n * - Transaction-safe migrations\r\n * - Concurrent execution locking\r\n * - Checksum validation\r\n * - Dry-run mode\r\n */\r\n\r\nimport type {\r\n IMigrator,\r\n Migration,\r\n MigrationRecord,\r\n MigrationResult,\r\n MigrationStatus,\r\n MigratorConfig,\r\n IMigrationDatabase,\r\n} from '../interfaces/IMigration';\r\n\r\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string } = {\r\n tableName: '_migrations',\r\n schema: 'public',\r\n lockTimeout: 60,\r\n validateChecksums: true,\r\n migrationsDir: undefined,\r\n};\r\n\r\n/**\r\n * Generate a checksum for migration content\r\n */\r\nfunction generateChecksum(content: string): string {\r\n // Simple hash for checksum - in production you might use crypto\r\n let hash = 0;\r\n for (let i = 0; i < content.length; i++) {\r\n const char = content.charCodeAt(i);\r\n hash = (hash << 5) - hash + char;\r\n hash = hash & hash; // Convert to 32-bit integer\r\n }\r\n return Math.abs(hash).toString(16).padStart(8, '0');\r\n}\r\n\r\n/**\r\n * Sort migrations by version\r\n */\r\nfunction sortMigrations(migrations: Migration[]): Migration[] {\r\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\r\n}\r\n\r\nexport class Migrator implements IMigrator {\r\n private db: IMigrationDatabase;\r\n private config: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string };\r\n private migrations: Migration[] = [];\r\n private initialized = false;\r\n private locked = false;\r\n\r\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\r\n this.db = db;\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Get the fully qualified migration table name\r\n */\r\n private get tableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\r\n }\r\n\r\n /**\r\n * Get the lock table name\r\n */\r\n private get lockTableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\r\n }\r\n\r\n /**\r\n * Initialize migration tracking tables\r\n */\r\n private async initialize(): Promise<void> {\r\n if (this.initialized) return;\r\n\r\n // Create schema if not exists\r\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\r\n\r\n // Create migrations tracking table\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\r\n version VARCHAR(255) PRIMARY KEY,\r\n name VARCHAR(255) NOT NULL,\r\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\r\n execution_time INTEGER NOT NULL,\r\n checksum VARCHAR(64)\r\n )\r\n `);\r\n\r\n // Create lock table for concurrent safety\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\r\n id INTEGER PRIMARY KEY DEFAULT 1,\r\n locked_at TIMESTAMP WITH TIME ZONE,\r\n locked_by VARCHAR(255),\r\n CONSTRAINT single_row CHECK (id = 1)\r\n )\r\n `);\r\n\r\n // Insert initial lock row if not exists\r\n await this.db.raw(`\r\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\r\n VALUES (1, NULL, NULL)\r\n ON CONFLICT (id) DO NOTHING\r\n `);\r\n\r\n this.initialized = true;\r\n }\r\n\r\n /**\r\n * Acquire migration lock\r\n */\r\n async lock(): Promise<boolean> {\r\n await this.initialize();\r\n\r\n const lockId = `${process.pid}-${Date.now()}`;\r\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\r\n\r\n // Try to acquire lock (only if not locked or lock expired)\r\n const result = await this.db.raw<{ locked_at: Date | null }>(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\r\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\r\n RETURNING locked_at\r\n `,\r\n [lockId, lockTimeout]\r\n );\r\n\r\n if (result.data.length > 0) {\r\n this.locked = true;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Release migration lock\r\n */\r\n async unlock(): Promise<void> {\r\n if (!this.locked) return;\r\n\r\n await this.db.raw(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = NULL, locked_by = NULL\r\n WHERE id = 1\r\n `\r\n );\r\n\r\n this.locked = false;\r\n }\r\n\r\n /**\r\n * Add migrations to the migrator\r\n */\r\n addMigrations(migrations: Migration[]): void {\r\n for (const migration of migrations) {\r\n // Generate checksum if not provided\r\n if (!migration.checksum) {\r\n const content =\r\n typeof migration.up === 'string' ? migration.up : migration.up.toString();\r\n migration.checksum = generateChecksum(content);\r\n }\r\n\r\n // Avoid duplicates\r\n if (!this.migrations.find((m) => m.version === migration.version)) {\r\n this.migrations.push(migration);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Load migrations from directory\r\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\r\n */\r\n async loadMigrations(dir: string): Promise<void> {\r\n // Dynamic import for Node.js file system\r\n const { readdir, readFile } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n const files = await readdir(dir);\r\n const migrationFiles = files.filter(\r\n (f) => f.match(/^\\d+_.*\\.(ts|js|sql)$/)\r\n );\r\n\r\n for (const file of migrationFiles) {\r\n const filePath = join(dir, file);\r\n const [version, ...nameParts] = file.replace(/\\.(ts|js|sql)$/, '').split('_');\r\n const name = nameParts.join('_');\r\n\r\n if (file.endsWith('.sql')) {\r\n // SQL file - parse UP and DOWN sections\r\n const content = await readFile(filePath, 'utf-8');\r\n const [up, down] = this.parseSqlMigration(content);\r\n\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up,\r\n down,\r\n },\r\n ]);\r\n } else {\r\n // TypeScript/JavaScript file - import the module\r\n const module = await import(filePath);\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up: module.up,\r\n down: module.down,\r\n transactional: module.transactional,\r\n },\r\n ]);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL migration file with -- UP and -- DOWN sections\r\n */\r\n private parseSqlMigration(content: string): [string, string] {\r\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\r\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\r\n\r\n const up = upMatch?.[1]?.trim() ?? content.trim();\r\n const down = downMatch?.[1]?.trim() ?? '';\r\n\r\n return [up, down];\r\n }\r\n\r\n /**\r\n * Get current migration status\r\n */\r\n async status(): Promise<MigrationStatus> {\r\n await this.initialize();\r\n\r\n // Get applied migrations\r\n const result = await this.db.raw<{\r\n version: string;\r\n name: string;\r\n applied_at: Date;\r\n execution_time: number;\r\n checksum: string | null;\r\n }>(\r\n `SELECT version, name, applied_at, execution_time, checksum\r\n FROM ${this.tableName}\r\n ORDER BY version ASC`\r\n );\r\n\r\n const applied: MigrationRecord[] = result.data.map((row) => ({\r\n version: row.version,\r\n name: row.name,\r\n appliedAt: new Date(row.applied_at),\r\n executionTime: row.execution_time,\r\n checksum: row.checksum ?? undefined,\r\n }));\r\n\r\n const appliedVersions = new Set(applied.map((m) => m.version));\r\n const sortedMigrations = sortMigrations(this.migrations);\r\n\r\n const pending = sortedMigrations.filter(\r\n (m) => !appliedVersions.has(m.version)\r\n );\r\n\r\n return {\r\n applied,\r\n pending,\r\n currentVersion: applied.length > 0 ? applied[applied.length - 1]!.version : null,\r\n latestVersion:\r\n sortedMigrations.length > 0\r\n ? sortedMigrations[sortedMigrations.length - 1]!.version\r\n : null,\r\n };\r\n }\r\n\r\n /**\r\n * Run all pending migrations (or up to a specific version)\r\n */\r\n async up(options: { dryRun?: boolean; to?: string } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, to } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n let pending = status.pending;\r\n\r\n // Filter to specific version if requested\r\n if (to) {\r\n const targetIndex = pending.findIndex((m) => m.version === to);\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${to} not found in pending migrations`);\r\n }\r\n pending = pending.slice(0, targetIndex + 1);\r\n }\r\n\r\n for (const migration of pending) {\r\n const result = await this.runMigration(migration, 'up', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break; // Stop on first failure\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback migrations\r\n */\r\n async down(options: { dryRun?: boolean; steps?: number } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, steps = 1 } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n\r\n // Get the last N applied migrations (in reverse order)\r\n const toRollback = status.applied.slice(-steps).reverse();\r\n\r\n for (const record of toRollback) {\r\n const migration = this.migrations.find((m) => m.version === record.version);\r\n if (!migration) {\r\n throw new Error(\r\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`\r\n );\r\n }\r\n\r\n const result = await this.runMigration(migration, 'down', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break;\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback all migrations and re-run them\r\n */\r\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const downResults = await this.down({\r\n dryRun: options.dryRun,\r\n steps: status.applied.length,\r\n });\r\n\r\n // Only proceed with up if all downs succeeded\r\n if (downResults.every((r) => r.success)) {\r\n const upResults = await this.up({ dryRun: options.dryRun });\r\n return [...downResults, ...upResults];\r\n }\r\n\r\n return downResults;\r\n }\r\n\r\n /**\r\n * Migrate to a specific version\r\n */\r\n async goto(version: string, options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const currentVersion = status.currentVersion;\r\n const results: MigrationResult[] = [];\r\n\r\n // If already at target, nothing to do\r\n if (currentVersion === version) {\r\n return results;\r\n }\r\n\r\n // Determine direction\r\n const isUp = !currentVersion || version > currentVersion;\r\n\r\n if (isUp) {\r\n return this.up({ ...options, to: version });\r\n } else {\r\n // Find how many steps down we need to go\r\n const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);\r\n const targetIndex = status.applied.findIndex((m) => m.version === version);\r\n\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${version} not found in applied migrations`);\r\n }\r\n\r\n const steps = currentIndex - targetIndex;\r\n return this.down({ ...options, steps });\r\n }\r\n }\r\n\r\n /**\r\n * Run a single migration\r\n */\r\n private async runMigration(\r\n migration: Migration,\r\n direction: 'up' | 'down',\r\n dryRun: boolean\r\n ): Promise<MigrationResult> {\r\n const startTime = Date.now();\r\n const action = direction === 'up' ? migration.up : migration.down;\r\n\r\n try {\r\n if (dryRun) {\r\n // Just simulate - don't actually run\r\n return {\r\n migration,\r\n success: true,\r\n executionTime: 0,\r\n dryRun: true,\r\n };\r\n }\r\n\r\n const transactional = migration.transactional !== false;\r\n const runAction = async (db: IMigrationDatabase) => {\r\n if (typeof action === 'string') {\r\n const result = await db.raw(action);\r\n if (result.error) {\r\n throw result.error;\r\n }\r\n } else {\r\n await action(db);\r\n }\r\n };\r\n\r\n if (transactional) {\r\n await this.db.transaction(async (tx) => {\r\n await runAction(tx);\r\n });\r\n } else {\r\n await runAction(this.db);\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n\r\n // Update tracking table\r\n if (direction === 'up') {\r\n await this.db.raw(\r\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\r\n VALUES ($1, $2, $3, $4)`,\r\n [migration.version, migration.name, executionTime, migration.checksum]\r\n );\r\n } else {\r\n await this.db.raw(\r\n `DELETE FROM ${this.tableName} WHERE version = $1`,\r\n [migration.version]\r\n );\r\n }\r\n\r\n return {\r\n migration,\r\n success: true,\r\n executionTime,\r\n dryRun: false,\r\n };\r\n } catch (error) {\r\n return {\r\n migration,\r\n success: false,\r\n executionTime: Date.now() - startTime,\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n dryRun: false,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Create a new migration file\r\n */\r\n async create(name: string): Promise<string> {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n if (!this.config.migrationsDir) {\r\n throw new Error('migrationsDir must be configured to create migrations');\r\n }\r\n\r\n // Ensure directory exists\r\n await mkdir(this.config.migrationsDir, { recursive: true });\r\n\r\n // Generate version timestamp\r\n const now = new Date();\r\n const version = [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n\r\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();\r\n const fileName = `${version}_${safeName}.sql`;\r\n const filePath = join(this.config.migrationsDir, fileName);\r\n\r\n const template = `-- Migration: ${name}\r\n-- Version: ${version}\r\n-- Created: ${now.toISOString()}\r\n\r\n-- UP\r\n-- Add your forward migration SQL here\r\n\r\n\r\n-- DOWN\r\n-- Add your rollback migration SQL here\r\n\r\n`;\r\n\r\n await writeFile(filePath, template, 'utf-8');\r\n\r\n return filePath;\r\n }\r\n\r\n /**\r\n * Validate migration integrity\r\n */\r\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\r\n const errors: string[] = [];\r\n const status = await this.status();\r\n\r\n if (!this.config.validateChecksums) {\r\n return { valid: true, errors };\r\n }\r\n\r\n for (const applied of status.applied) {\r\n const migration = this.migrations.find((m) => m.version === applied.version);\r\n\r\n if (!migration) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`\r\n );\r\n continue;\r\n }\r\n\r\n if (applied.checksum && migration.checksum !== applied.checksum) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n }\r\n}\r\n","#!/usr/bin/env node\r\n/**\r\n * Database Migration CLI\r\n *\r\n * Command-line interface for running database migrations.\r\n *\r\n * Usage:\r\n * npx platform-migrate status # Show migration status\r\n * npx platform-migrate up # Run all pending migrations\r\n * npx platform-migrate up --to V # Run migrations up to version V\r\n * npx platform-migrate up --dry-run # Preview without applying\r\n * npx platform-migrate down # Rollback last migration\r\n * npx platform-migrate down --steps N # Rollback last N migrations\r\n * npx platform-migrate reset # Rollback all and re-run\r\n * npx platform-migrate create NAME # Create new migration file\r\n * npx platform-migrate validate # Validate migration integrity\r\n *\r\n * Environment Variables:\r\n * DATABASE_URL - PostgreSQL connection string\r\n * MIGRATIONS_DIR - Directory containing migration files (default: ./migrations)\r\n * MIGRATIONS_TABLE - Table name for tracking (default: _migrations)\r\n */\r\n\r\nimport { Migrator } from './Migrator';\r\nimport type { MigrationResult } from '../interfaces/IMigration';\r\n\r\ninterface CliOptions {\r\n command: string;\r\n dryRun: boolean;\r\n steps: number;\r\n to?: string;\r\n name?: string;\r\n migrationsDir: string;\r\n help: boolean;\r\n}\r\n\r\nconst HELP_TEXT = `\r\nDatabase Migration CLI\r\n\r\nUSAGE:\r\n platform-migrate <command> [options]\r\n\r\nCOMMANDS:\r\n status Show current migration status\r\n up Run all pending migrations\r\n down Rollback the last migration\r\n reset Rollback all and re-run migrations\r\n goto <ver> Migrate to a specific version\r\n create <name> Create a new migration file\r\n validate Validate migration integrity\r\n\r\nOPTIONS:\r\n --dry-run Preview changes without applying\r\n --steps <n> Number of migrations to rollback (for down command)\r\n --to <ver> Target version (for up command)\r\n --dir <path> Migrations directory (default: ./migrations)\r\n --help, -h Show this help message\r\n\r\nENVIRONMENT:\r\n DATABASE_URL PostgreSQL connection string (required)\r\n MIGRATIONS_DIR Default migrations directory\r\n MIGRATIONS_TABLE Migration tracking table name\r\n\r\nEXAMPLES:\r\n platform-migrate status\r\n platform-migrate up\r\n platform-migrate up --dry-run\r\n platform-migrate down --steps 3\r\n platform-migrate create add_users_table\r\n platform-migrate goto 20240101000000\r\n`;\r\n\r\nfunction parseArgs(args: string[]): CliOptions {\r\n const options: CliOptions = {\r\n command: '',\r\n dryRun: false,\r\n steps: 1,\r\n migrationsDir: process.env.MIGRATIONS_DIR ?? './migrations',\r\n help: false,\r\n };\r\n\r\n for (let i = 0; i < args.length; i++) {\r\n const arg = args[i]!;\r\n\r\n if (arg === '--dry-run') {\r\n options.dryRun = true;\r\n } else if (arg === '--steps' && args[i + 1]) {\r\n options.steps = parseInt(args[++i]!, 10);\r\n } else if (arg === '--to' && args[i + 1]) {\r\n options.to = args[++i];\r\n } else if ((arg === '--dir' || arg === '-d') && args[i + 1]) {\r\n options.migrationsDir = args[++i]!;\r\n } else if (arg === '--help' || arg === '-h') {\r\n options.help = true;\r\n } else if (!arg.startsWith('-') && !options.command) {\r\n options.command = arg;\r\n } else if (!arg.startsWith('-') && options.command && !options.name) {\r\n options.name = arg;\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nfunction formatResults(results: MigrationResult[]): void {\r\n if (results.length === 0) {\r\n console.log('No migrations to run.');\r\n return;\r\n }\r\n\r\n for (const result of results) {\r\n const icon = result.success ? '✓' : '✗';\r\n const status = result.dryRun ? '[DRY RUN]' : '';\r\n const time = result.success ? `(${result.executionTime}ms)` : '';\r\n\r\n if (result.success) {\r\n console.log(` ${icon} ${result.migration.version} - ${result.migration.name} ${time} ${status}`);\r\n } else {\r\n console.error(` ${icon} ${result.migration.version} - ${result.migration.name}`);\r\n console.error(` Error: ${result.error?.message}`);\r\n }\r\n }\r\n\r\n const successful = results.filter((r) => r.success).length;\r\n const failed = results.filter((r) => !r.success).length;\r\n\r\n console.log(`\\n${successful} successful, ${failed} failed`);\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const args = process.argv.slice(2);\r\n const options = parseArgs(args);\r\n\r\n if (options.help || !options.command) {\r\n console.log(HELP_TEXT);\r\n process.exit(options.help ? 0 : 1);\r\n }\r\n\r\n // Check for DATABASE_URL\r\n if (!process.env.DATABASE_URL) {\r\n console.error('Error: DATABASE_URL environment variable is required');\r\n process.exit(1);\r\n }\r\n\r\n try {\r\n // Dynamic import PostgresDatabase to keep dependencies optional\r\n const { PostgresDatabase } = await import('../adapters/postgres/PostgresDatabase');\r\n const db = await PostgresDatabase.fromEnv();\r\n\r\n const migrator = new Migrator(db, {\r\n tableName: process.env.MIGRATIONS_TABLE ?? '_migrations',\r\n migrationsDir: options.migrationsDir,\r\n });\r\n\r\n // Load migrations from directory\r\n try {\r\n await migrator.loadMigrations(options.migrationsDir);\r\n } catch (e) {\r\n // Directory may not exist for some commands\r\n if (options.command !== 'create') {\r\n console.warn(`Warning: Could not load migrations from ${options.migrationsDir}`);\r\n }\r\n }\r\n\r\n switch (options.command) {\r\n case 'status': {\r\n const status = await migrator.status();\r\n console.log('\\n=== Migration Status ===\\n');\r\n console.log(`Current Version: ${status.currentVersion ?? 'None'}`);\r\n console.log(`Latest Version: ${status.latestVersion ?? 'None'}`);\r\n console.log(`\\nApplied (${status.applied.length}):`);\r\n for (const m of status.applied) {\r\n console.log(` ✓ ${m.version} - ${m.name} (${m.appliedAt.toISOString()})`);\r\n }\r\n console.log(`\\nPending (${status.pending.length}):`);\r\n for (const m of status.pending) {\r\n console.log(` ○ ${m.version} - ${m.name}`);\r\n }\r\n break;\r\n }\r\n\r\n case 'up': {\r\n console.log(options.dryRun ? '\\n=== Dry Run: Migrate Up ===\\n' : '\\n=== Migrating Up ===\\n');\r\n const results = await migrator.up({\r\n dryRun: options.dryRun,\r\n to: options.to,\r\n });\r\n formatResults(results);\r\n if (results.some((r) => !r.success)) {\r\n process.exit(1);\r\n }\r\n break;\r\n }\r\n\r\n case 'down': {\r\n console.log(options.dryRun ? '\\n=== Dry Run: Rollback ===\\n' : '\\n=== Rolling Back ===\\n');\r\n const results = await migrator.down({\r\n dryRun: options.dryRun,\r\n steps: options.steps,\r\n });\r\n formatResults(results);\r\n if (results.some((r) => !r.success)) {\r\n process.exit(1);\r\n }\r\n break;\r\n }\r\n\r\n case 'reset': {\r\n console.log(options.dryRun ? '\\n=== Dry Run: Reset ===\\n' : '\\n=== Resetting Database ===\\n');\r\n const results = await migrator.reset({ dryRun: options.dryRun });\r\n formatResults(results);\r\n if (results.some((r) => !r.success)) {\r\n process.exit(1);\r\n }\r\n break;\r\n }\r\n\r\n case 'goto': {\r\n if (!options.name) {\r\n console.error('Error: Version required. Usage: platform-migrate goto <version>');\r\n process.exit(1);\r\n }\r\n console.log(`\\n=== Migrating to Version ${options.name} ===\\n`);\r\n const results = await migrator.goto(options.name, { dryRun: options.dryRun });\r\n formatResults(results);\r\n if (results.some((r) => !r.success)) {\r\n process.exit(1);\r\n }\r\n break;\r\n }\r\n\r\n case 'create': {\r\n if (!options.name) {\r\n console.error('Error: Migration name required. Usage: platform-migrate create <name>');\r\n process.exit(1);\r\n }\r\n const filePath = await migrator.create(options.name);\r\n console.log(`\\nCreated migration: ${filePath}\\n`);\r\n break;\r\n }\r\n\r\n case 'validate': {\r\n console.log('\\n=== Validating Migrations ===\\n');\r\n const { valid, errors } = await migrator.validate();\r\n if (valid) {\r\n console.log('✓ All migrations are valid');\r\n } else {\r\n console.error('✗ Validation failed:');\r\n for (const error of errors) {\r\n console.error(` - ${error}`);\r\n }\r\n process.exit(1);\r\n }\r\n break;\r\n }\r\n\r\n default:\r\n console.error(`Unknown command: ${options.command}`);\r\n console.log(HELP_TEXT);\r\n process.exit(1);\r\n }\r\n\r\n await db.close();\r\n } catch (error) {\r\n console.error('Error:', error instanceof Error ? error.message : error);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n// Run if executed directly\r\nmain().catch((error) => {\r\n console.error('Fatal error:', error);\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":["module","PostgresDatabase"]}
1
+ {"version":3,"sources":["../src/adapters/postgres/PostgresDatabase.ts","../src/migrations/Migrator.ts","../src/migrations/cli.ts"],"sourcesContent":["/**\n * PostgreSQL Direct Database Adapter\n *\n * Production implementation using pg (node-postgres) for direct PostgreSQL connections.\n * Provides true ACID transaction support, connection pooling, and prepared statements.\n *\n * This adapter is vendor-agnostic - works with any PostgreSQL-compatible database:\n * - PostgreSQL (self-hosted or managed)\n * - Amazon RDS PostgreSQL\n * - Azure Database for PostgreSQL\n * - Google Cloud SQL for PostgreSQL\n * - CockroachDB (PostgreSQL wire protocol)\n * - YugabyteDB\n * - Neon, Supabase (direct connection, not REST)\n */\n\nimport type {\n Pool,\n PoolClient,\n PoolConfig,\n QueryResult as PgQueryResult,\n} from \"pg\";\nimport {\n IDatabase,\n IQueryBuilder,\n QueryResult,\n} from \"../../interfaces/IDatabase\";\nimport { randomBytes } from \"crypto\";\n\nexport interface PostgresConfig {\n /** Connection string (postgresql://user:pass@host:port/database) */\n connectionString?: string;\n\n /** Host name */\n host?: string;\n\n /** Port number */\n port?: number;\n\n /** Database name */\n database?: string;\n\n /** Username */\n user?: string;\n\n /** Password */\n password?: string;\n\n /** SSL configuration */\n ssl?: boolean | { rejectUnauthorized?: boolean; ca?: string };\n\n /** Maximum number of connections in pool */\n max?: number;\n\n /** Idle timeout in milliseconds */\n idleTimeoutMillis?: number;\n\n /** Connection timeout in milliseconds */\n connectionTimeoutMillis?: number;\n\n /** Statement timeout in milliseconds (0 = no limit) */\n statementTimeout?: number;\n\n /** Query timeout in milliseconds (0 = no limit) */\n queryTimeout?: number;\n\n /** Application name for connection identification */\n applicationName?: string;\n}\n\n/**\n * Convert our config to pg pool config\n */\nfunction toPoolConfig(config: PostgresConfig): PoolConfig {\n const poolConfig: PoolConfig = {};\n\n if (config.connectionString) {\n poolConfig.connectionString = config.connectionString;\n } else {\n poolConfig.host = config.host;\n poolConfig.port = config.port;\n poolConfig.database = config.database;\n poolConfig.user = config.user;\n poolConfig.password = config.password;\n }\n\n if (config.ssl !== undefined) {\n poolConfig.ssl = config.ssl;\n }\n\n poolConfig.max = config.max ?? 10;\n poolConfig.idleTimeoutMillis = config.idleTimeoutMillis ?? 30000;\n poolConfig.connectionTimeoutMillis = config.connectionTimeoutMillis ?? 10000;\n poolConfig.application_name = config.applicationName ?? \"platform-core\";\n\n // Statement timeout\n if (config.statementTimeout) {\n poolConfig.statement_timeout = config.statementTimeout;\n }\n\n // Query timeout\n if (config.queryTimeout) {\n poolConfig.query_timeout = config.queryTimeout;\n }\n\n return poolConfig;\n}\n\nexport class PostgresDatabase implements IDatabase {\n private pool: Pool;\n private config: PostgresConfig;\n\n constructor(pool: Pool, config: PostgresConfig = {}) {\n this.pool = pool;\n this.config = config;\n }\n\n /**\n * Create a PostgresDatabase from configuration\n */\n static async create(config: PostgresConfig): Promise<PostgresDatabase> {\n // Dynamic import to keep pg as optional peer dependency\n const { Pool } = await import(\"pg\");\n const poolConfig = toPoolConfig(config);\n const pool = new Pool(poolConfig);\n\n // Test connection\n const client = await pool.connect();\n client.release();\n\n return new PostgresDatabase(pool, config);\n }\n\n /**\n * Create from environment variables\n */\n static async fromEnv(): Promise<PostgresDatabase> {\n const config: PostgresConfig = {\n connectionString: process.env.DATABASE_URL,\n host: process.env.POSTGRES_HOST ?? process.env.PGHOST,\n port: parseInt(\n process.env.POSTGRES_PORT ?? process.env.PGPORT ?? \"5432\",\n 10,\n ),\n database: process.env.POSTGRES_DATABASE ?? process.env.PGDATABASE,\n user: process.env.POSTGRES_USER ?? process.env.PGUSER,\n password: process.env.POSTGRES_PASSWORD ?? process.env.PGPASSWORD,\n max: parseInt(process.env.POSTGRES_POOL_MAX ?? \"10\", 10),\n ssl:\n process.env.POSTGRES_SSL === \"true\"\n ? {\n rejectUnauthorized:\n process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== \"false\",\n }\n : undefined,\n applicationName: process.env.POSTGRES_APP_NAME ?? \"platform-core\",\n };\n\n return PostgresDatabase.create(config);\n }\n\n from<T = unknown>(table: string): IQueryBuilder<T> {\n return new PostgresQueryBuilder<T>(this.pool, table);\n }\n\n async raw<T = unknown>(\n sql: string,\n params?: unknown[],\n ): Promise<QueryResult<T>> {\n try {\n const result: PgQueryResult = await this.pool.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n } catch (error) {\n return {\n data: [],\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n /**\n * Execute a function within a database transaction.\n * Provides true ACID guarantees - either all operations succeed or all are rolled back.\n */\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\n const client = await this.pool.connect();\n\n try {\n await client.query(\"BEGIN\");\n\n // Create a transaction-scoped database instance\n const txDatabase = new TransactionDatabase(client);\n\n const result = await fn(txDatabase);\n\n await client.query(\"COMMIT\");\n return result;\n } catch (error) {\n await client.query(\"ROLLBACK\");\n throw error;\n } finally {\n client.release();\n }\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const result = await this.pool.query(\"SELECT 1 as health\");\n return result.rows.length > 0;\n } catch {\n return false;\n }\n }\n\n async close(): Promise<void> {\n await this.pool.end();\n }\n\n /**\n * Get pool statistics for monitoring\n */\n getPoolStats(): {\n totalCount: number;\n idleCount: number;\n waitingCount: number;\n } {\n return {\n totalCount: this.pool.totalCount,\n idleCount: this.pool.idleCount,\n waitingCount: this.pool.waitingCount,\n };\n }\n}\n\n/**\n * Transaction-scoped database that uses a single client connection\n */\nclass TransactionDatabase implements IDatabase {\n constructor(private client: PoolClient) {}\n\n from<T = unknown>(table: string): IQueryBuilder<T> {\n return new PostgresQueryBuilder<T>(this.client, table);\n }\n\n async raw<T = unknown>(\n sql: string,\n params?: unknown[],\n ): Promise<QueryResult<T>> {\n try {\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n } catch (error) {\n return {\n data: [],\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\n // Nested transaction using savepoint\n const savepointName = `sp_${Date.now()}_${randomBytes(4).toString(\"hex\")}`;\n\n try {\n await this.client.query(`SAVEPOINT ${savepointName}`);\n const result = await fn(this);\n await this.client.query(`RELEASE SAVEPOINT ${savepointName}`);\n return result;\n } catch (error) {\n await this.client.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);\n throw error;\n }\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n await this.client.query(\"SELECT 1\");\n return true;\n } catch {\n return false;\n }\n }\n\n async close(): Promise<void> {\n // Transaction database doesn't own the client, so don't close\n }\n}\n\n/**\n * PostgreSQL Query Builder\n */\nclass PostgresQueryBuilder<T = unknown> implements IQueryBuilder<T> {\n private client: Pool | PoolClient;\n private tableName: string;\n private _select: string[] = [\"*\"];\n private _where: Array<{ column: string; operator: string; value: unknown }> =\n [];\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\n private _orderBy: { column: string; direction: \"asc\" | \"desc\" } | null = null;\n private _limit: number | null = null;\n private _offset: number = 0;\n private _insertData: Partial<T>[] | null = null;\n private _updateData: Partial<T> | null = null;\n private _deleteFlag: boolean = false;\n private _returning: string[] = [\"*\"];\n\n constructor(client: Pool | PoolClient, tableName: string) {\n this.client = client;\n this.tableName = this.escapeIdentifier(tableName);\n }\n\n select(columns?: string | string[]): IQueryBuilder<T> {\n if (columns) {\n this._select = Array.isArray(columns) ? columns : [columns];\n }\n return this;\n }\n\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\n this._insertData = Array.isArray(data) ? data : [data];\n return this;\n }\n\n update(data: Partial<T>): IQueryBuilder<T> {\n this._updateData = data;\n return this;\n }\n\n delete(): IQueryBuilder<T> {\n this._deleteFlag = true;\n return this;\n }\n\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\n this._where.push({ column, operator, value });\n return this;\n }\n\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\n this._whereIn.push({ column, values });\n return this;\n }\n\n orderBy(column: string, direction: \"asc\" | \"desc\" = \"asc\"): IQueryBuilder<T> {\n this._orderBy = { column, direction };\n return this;\n }\n\n limit(count: number): IQueryBuilder<T> {\n this._limit = count;\n return this;\n }\n\n offset(count: number): IQueryBuilder<T> {\n this._offset = count;\n return this;\n }\n\n async single(): Promise<{ data: T | null; error?: Error }> {\n this._limit = 1;\n const result = await this.execute();\n\n if (result.error) {\n return { data: null, error: result.error };\n }\n\n return { data: result.data[0] ?? null };\n }\n\n async execute(): Promise<QueryResult<T>> {\n try {\n if (this._insertData) {\n return await this.executeInsert();\n }\n\n if (this._updateData) {\n return await this.executeUpdate();\n }\n\n if (this._deleteFlag) {\n return await this.executeDelete();\n }\n\n return await this.executeSelect();\n } catch (error) {\n return {\n data: [],\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n private async executeSelect(): Promise<QueryResult<T>> {\n const params: unknown[] = [];\n let paramIndex = 1;\n\n // Build SELECT clause\n const selectClause = this._select\n .map((col) => this.escapeIdentifier(col))\n .join(\", \");\n let sql = `SELECT ${selectClause} FROM ${this.tableName}`;\n\n // Build WHERE clause\n const whereClauses: string[] = [];\n\n for (const { column, operator, value } of this._where) {\n whereClauses.push(\n `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`,\n );\n params.push(value);\n }\n\n for (const { column, values } of this._whereIn) {\n const placeholders = values.map(() => `$${paramIndex++}`).join(\", \");\n whereClauses.push(\n `${this.escapeIdentifier(column)} IN (${placeholders})`,\n );\n params.push(...values);\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(\" AND \")}`;\n }\n\n // Build ORDER BY\n if (this._orderBy) {\n sql += ` ORDER BY ${this.escapeIdentifier(this._orderBy.column)} ${this._orderBy.direction.toUpperCase()}`;\n }\n\n // Build LIMIT and OFFSET\n if (this._limit !== null) {\n sql += ` LIMIT $${paramIndex++}`;\n params.push(this._limit);\n }\n\n if (this._offset > 0) {\n sql += ` OFFSET $${paramIndex++}`;\n params.push(this._offset);\n }\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private async executeInsert(): Promise<QueryResult<T>> {\n if (!this._insertData || this._insertData.length === 0) {\n return { data: [] };\n }\n\n const params: unknown[] = [];\n let paramIndex = 1;\n\n // Get all unique columns from the data\n const columns = new Set<string>();\n for (const row of this._insertData) {\n Object.keys(row as object).forEach((key) => columns.add(key));\n }\n const columnList = Array.from(columns);\n\n // Build column list\n const columnClause = columnList\n .map((col) => this.escapeIdentifier(col))\n .join(\", \");\n\n // Build values\n const valueRows: string[] = [];\n for (const row of this._insertData) {\n const rowValues: string[] = [];\n for (const col of columnList) {\n rowValues.push(`$${paramIndex++}`);\n params.push((row as Record<string, unknown>)[col] ?? null);\n }\n valueRows.push(`(${rowValues.join(\", \")})`);\n }\n\n const sql = `INSERT INTO ${this.tableName} (${columnClause}) VALUES ${valueRows.join(\", \")} RETURNING ${this._returning.join(\", \")}`;\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private async executeUpdate(): Promise<QueryResult<T>> {\n if (!this._updateData) {\n return { data: [] };\n }\n\n const params: unknown[] = [];\n let paramIndex = 1;\n\n // Build SET clause\n const setClauses: string[] = [];\n for (const [key, value] of Object.entries(this._updateData as object)) {\n setClauses.push(`${this.escapeIdentifier(key)} = $${paramIndex++}`);\n params.push(value);\n }\n\n let sql = `UPDATE ${this.tableName} SET ${setClauses.join(\", \")}`;\n\n // Build WHERE clause\n const whereClauses: string[] = [];\n\n for (const { column, operator, value } of this._where) {\n whereClauses.push(\n `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`,\n );\n params.push(value);\n }\n\n for (const { column, values } of this._whereIn) {\n const placeholders = values.map(() => `$${paramIndex++}`).join(\", \");\n whereClauses.push(\n `${this.escapeIdentifier(column)} IN (${placeholders})`,\n );\n params.push(...values);\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(\" AND \")}`;\n }\n\n sql += ` RETURNING ${this._returning.join(\", \")}`;\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private async executeDelete(): Promise<QueryResult<T>> {\n const params: unknown[] = [];\n let paramIndex = 1;\n\n let sql = `DELETE FROM ${this.tableName}`;\n\n // Build WHERE clause\n const whereClauses: string[] = [];\n\n for (const { column, operator, value } of this._where) {\n whereClauses.push(\n `${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`,\n );\n params.push(value);\n }\n\n for (const { column, values } of this._whereIn) {\n const placeholders = values.map(() => `$${paramIndex++}`).join(\", \");\n whereClauses.push(\n `${this.escapeIdentifier(column)} IN (${placeholders})`,\n );\n params.push(...values);\n }\n\n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(\" AND \")}`;\n }\n\n sql += ` RETURNING ${this._returning.join(\", \")}`;\n\n const result = await this.client.query(sql, params);\n return {\n data: result.rows as T[],\n count: result.rowCount ?? undefined,\n };\n }\n\n private escapeIdentifier(identifier: string): string {\n // Handle special cases\n if (identifier === \"*\") return \"*\";\n\n // Handle schema.table notation\n if (identifier.includes(\".\")) {\n return identifier\n .split(\".\")\n .map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`)\n .join(\".\");\n }\n\n // Escape identifier with double quotes\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n }\n\n private mapOperator(operator: string): string {\n switch (operator.toLowerCase()) {\n case \"=\":\n case \"==\":\n return \"=\";\n case \"!=\":\n case \"<>\":\n return \"<>\";\n case \"<\":\n return \"<\";\n case \"<=\":\n return \"<=\";\n case \">\":\n return \">\";\n case \">=\":\n return \">=\";\n case \"like\":\n return \"LIKE\";\n case \"ilike\":\n return \"ILIKE\";\n case \"is\":\n return \"IS\";\n case \"is not\":\n return \"IS NOT\";\n default:\n return \"=\";\n }\n }\n}\n","/**\n * Database Migrator\n *\n * Enterprise-grade database migration system supporting:\n * - PostgreSQL (primary)\n * - Memory database (for testing)\n * - Transaction-safe migrations\n * - Concurrent execution locking\n * - Checksum validation\n * - Dry-run mode\n */\n\nimport type {\n IMigrator,\n Migration,\n MigrationRecord,\n MigrationResult,\n MigrationStatus,\n MigratorConfig,\n IMigrationDatabase,\n} from \"../interfaces/IMigration\";\n\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, \"migrationsDir\">> & {\n migrationsDir?: string;\n} = {\n tableName: \"_migrations\",\n schema: \"public\",\n lockTimeout: 60,\n validateChecksums: true,\n migrationsDir: undefined,\n};\n\n/**\n * Generate a checksum for migration content\n */\nfunction generateChecksum(content: string): string {\n // Simple hash for checksum - in production you might use crypto\n let hash = 0;\n for (let i = 0; i < content.length; i++) {\n const char = content.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n return Math.abs(hash).toString(16).padStart(8, \"0\");\n}\n\n/**\n * Sort migrations by version\n */\nfunction sortMigrations(migrations: Migration[]): Migration[] {\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\n}\n\nexport class Migrator implements IMigrator {\n private db: IMigrationDatabase;\n private config: Required<Omit<MigratorConfig, \"migrationsDir\">> & {\n migrationsDir?: string;\n };\n private migrations: Migration[] = [];\n private initialized = false;\n private locked = false;\n\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\n this.db = db;\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n /**\n * Get the fully qualified migration table name\n */\n private get tableName(): string {\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\n }\n\n /**\n * Get the lock table name\n */\n private get lockTableName(): string {\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\n }\n\n /**\n * Initialize migration tracking tables\n */\n private async initialize(): Promise<void> {\n if (this.initialized) return;\n\n // Create schema if not exists\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\n\n // Create migrations tracking table\n await this.db.raw(`\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n version VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\n execution_time INTEGER NOT NULL,\n checksum VARCHAR(64)\n )\n `);\n\n // Create lock table for concurrent safety\n await this.db.raw(`\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\n id INTEGER PRIMARY KEY DEFAULT 1,\n locked_at TIMESTAMP WITH TIME ZONE,\n locked_by VARCHAR(255),\n CONSTRAINT single_row CHECK (id = 1)\n )\n `);\n\n // Insert initial lock row if not exists\n await this.db.raw(`\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\n VALUES (1, NULL, NULL)\n ON CONFLICT (id) DO NOTHING\n `);\n\n this.initialized = true;\n }\n\n /**\n * Acquire migration lock\n */\n async lock(): Promise<boolean> {\n await this.initialize();\n\n const lockId = `${process.pid}-${Date.now()}`;\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\n\n // Try to acquire lock (only if not locked or lock expired)\n const result = await this.db.raw<{ locked_at: Date | null }>(\n `\n UPDATE ${this.lockTableName}\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\n RETURNING locked_at\n `,\n [lockId, lockTimeout],\n );\n\n if (result.data.length > 0) {\n this.locked = true;\n return true;\n }\n\n return false;\n }\n\n /**\n * Release migration lock\n */\n async unlock(): Promise<void> {\n if (!this.locked) return;\n\n await this.db.raw(\n `\n UPDATE ${this.lockTableName}\n SET locked_at = NULL, locked_by = NULL\n WHERE id = 1\n `,\n );\n\n this.locked = false;\n }\n\n /**\n * Add migrations to the migrator\n */\n addMigrations(migrations: Migration[]): void {\n for (const migration of migrations) {\n // Generate checksum if not provided\n if (!migration.checksum) {\n const content =\n typeof migration.up === \"string\"\n ? migration.up\n : migration.up.toString();\n migration.checksum = generateChecksum(content);\n }\n\n // Avoid duplicates\n if (!this.migrations.find((m) => m.version === migration.version)) {\n this.migrations.push(migration);\n }\n }\n }\n\n /**\n * Load migrations from directory\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\n */\n async loadMigrations(dir: string): Promise<void> {\n // Dynamic import for Node.js file system\n const { readdir, readFile } = await import(\"fs/promises\");\n const { join } = await import(\"path\");\n\n const files = await readdir(dir);\n const migrationFiles = files.filter((f) =>\n f.match(/^\\d+_.*\\.(ts|js|sql)$/),\n );\n\n for (const file of migrationFiles) {\n const filePath = join(dir, file);\n const [version, ...nameParts] = file\n .replace(/\\.(ts|js|sql)$/, \"\")\n .split(\"_\");\n const name = nameParts.join(\"_\");\n\n if (file.endsWith(\".sql\")) {\n // SQL file - parse UP and DOWN sections\n const content = await readFile(filePath, \"utf-8\");\n const [up, down] = this.parseSqlMigration(content);\n\n this.addMigrations([\n {\n version: version!,\n name,\n up,\n down,\n },\n ]);\n } else {\n // TypeScript/JavaScript file - import the module\n const module = await import(filePath);\n this.addMigrations([\n {\n version: version!,\n name,\n up: module.up,\n down: module.down,\n transactional: module.transactional,\n },\n ]);\n }\n }\n }\n\n /**\n * Parse SQL migration file with -- UP and -- DOWN sections\n */\n private parseSqlMigration(content: string): [string, string] {\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\n\n const up = upMatch?.[1]?.trim() ?? content.trim();\n const down = downMatch?.[1]?.trim() ?? \"\";\n\n return [up, down];\n }\n\n /**\n * Get current migration status\n */\n async status(): Promise<MigrationStatus> {\n await this.initialize();\n\n // Get applied migrations\n const result = await this.db.raw<{\n version: string;\n name: string;\n applied_at: Date;\n execution_time: number;\n checksum: string | null;\n }>(\n `SELECT version, name, applied_at, execution_time, checksum\n FROM ${this.tableName}\n ORDER BY version ASC`,\n );\n\n const applied: MigrationRecord[] = result.data.map((row) => ({\n version: row.version,\n name: row.name,\n appliedAt: new Date(row.applied_at),\n executionTime: row.execution_time,\n checksum: row.checksum ?? undefined,\n }));\n\n const appliedVersions = new Set(applied.map((m) => m.version));\n const sortedMigrations = sortMigrations(this.migrations);\n\n const pending = sortedMigrations.filter(\n (m) => !appliedVersions.has(m.version),\n );\n\n return {\n applied,\n pending,\n currentVersion:\n applied.length > 0 ? applied[applied.length - 1]!.version : null,\n latestVersion:\n sortedMigrations.length > 0\n ? sortedMigrations[sortedMigrations.length - 1]!.version\n : null,\n };\n }\n\n /**\n * Run all pending migrations (or up to a specific version)\n */\n async up(\n options: { dryRun?: boolean; to?: string } = {},\n ): Promise<MigrationResult[]> {\n const { dryRun = false, to } = options;\n const results: MigrationResult[] = [];\n\n if (!dryRun) {\n const acquired = await this.lock();\n if (!acquired) {\n throw new Error(\n \"Could not acquire migration lock. Another migration may be in progress.\",\n );\n }\n }\n\n try {\n const status = await this.status();\n let pending = status.pending;\n\n // Filter to specific version if requested\n if (to) {\n const targetIndex = pending.findIndex((m) => m.version === to);\n if (targetIndex === -1) {\n throw new Error(\n `Target version ${to} not found in pending migrations`,\n );\n }\n pending = pending.slice(0, targetIndex + 1);\n }\n\n for (const migration of pending) {\n const result = await this.runMigration(migration, \"up\", dryRun);\n results.push(result);\n\n if (!result.success) {\n break; // Stop on first failure\n }\n }\n } finally {\n if (!dryRun) {\n await this.unlock();\n }\n }\n\n return results;\n }\n\n /**\n * Rollback migrations\n */\n async down(\n options: { dryRun?: boolean; steps?: number } = {},\n ): Promise<MigrationResult[]> {\n const { dryRun = false, steps = 1 } = options;\n const results: MigrationResult[] = [];\n\n if (!dryRun) {\n const acquired = await this.lock();\n if (!acquired) {\n throw new Error(\n \"Could not acquire migration lock. Another migration may be in progress.\",\n );\n }\n }\n\n try {\n const status = await this.status();\n\n // Get the last N applied migrations (in reverse order)\n const toRollback = status.applied.slice(-steps).reverse();\n\n for (const record of toRollback) {\n const migration = this.migrations.find(\n (m) => m.version === record.version,\n );\n if (!migration) {\n throw new Error(\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`,\n );\n }\n\n const result = await this.runMigration(migration, \"down\", dryRun);\n results.push(result);\n\n if (!result.success) {\n break;\n }\n }\n } finally {\n if (!dryRun) {\n await this.unlock();\n }\n }\n\n return results;\n }\n\n /**\n * Rollback all migrations and re-run them\n */\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\n const status = await this.status();\n const downResults = await this.down({\n dryRun: options.dryRun,\n steps: status.applied.length,\n });\n\n // Only proceed with up if all downs succeeded\n if (downResults.every((r) => r.success)) {\n const upResults = await this.up({ dryRun: options.dryRun });\n return [...downResults, ...upResults];\n }\n\n return downResults;\n }\n\n /**\n * Migrate to a specific version\n */\n async goto(\n version: string,\n options: { dryRun?: boolean } = {},\n ): Promise<MigrationResult[]> {\n const status = await this.status();\n const currentVersion = status.currentVersion;\n const results: MigrationResult[] = [];\n\n // If already at target, nothing to do\n if (currentVersion === version) {\n return results;\n }\n\n // Determine direction\n const isUp = !currentVersion || version > currentVersion;\n\n if (isUp) {\n return this.up({ ...options, to: version });\n } else {\n // Find how many steps down we need to go\n const currentIndex = status.applied.findIndex(\n (m) => m.version === currentVersion,\n );\n const targetIndex = status.applied.findIndex(\n (m) => m.version === version,\n );\n\n if (targetIndex === -1) {\n throw new Error(\n `Target version ${version} not found in applied migrations`,\n );\n }\n\n const steps = currentIndex - targetIndex;\n return this.down({ ...options, steps });\n }\n }\n\n /**\n * Run a single migration\n */\n private async runMigration(\n migration: Migration,\n direction: \"up\" | \"down\",\n dryRun: boolean,\n ): Promise<MigrationResult> {\n const startTime = Date.now();\n const action = direction === \"up\" ? migration.up : migration.down;\n\n try {\n if (dryRun) {\n // Just simulate - don't actually run\n return {\n migration,\n success: true,\n executionTime: 0,\n dryRun: true,\n };\n }\n\n const transactional = migration.transactional !== false;\n const runAction = async (db: IMigrationDatabase) => {\n if (typeof action === \"string\") {\n const result = await db.raw(action);\n if (result.error) {\n throw result.error;\n }\n } else {\n await action(db);\n }\n };\n\n if (transactional) {\n await this.db.transaction(async (tx) => {\n await runAction(tx);\n });\n } else {\n await runAction(this.db);\n }\n\n const executionTime = Date.now() - startTime;\n\n // Update tracking table\n if (direction === \"up\") {\n await this.db.raw(\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\n VALUES ($1, $2, $3, $4)`,\n [\n migration.version,\n migration.name,\n executionTime,\n migration.checksum,\n ],\n );\n } else {\n await this.db.raw(`DELETE FROM ${this.tableName} WHERE version = $1`, [\n migration.version,\n ]);\n }\n\n return {\n migration,\n success: true,\n executionTime,\n dryRun: false,\n };\n } catch (error) {\n return {\n migration,\n success: false,\n executionTime: Date.now() - startTime,\n error: error instanceof Error ? error : new Error(String(error)),\n dryRun: false,\n };\n }\n }\n\n /**\n * Create a new migration file\n */\n async create(name: string): Promise<string> {\n const { writeFile, mkdir } = await import(\"fs/promises\");\n const { join } = await import(\"path\");\n\n if (!this.config.migrationsDir) {\n throw new Error(\"migrationsDir must be configured to create migrations\");\n }\n\n // Ensure directory exists\n await mkdir(this.config.migrationsDir, { recursive: true });\n\n // Generate version timestamp\n const now = new Date();\n const version = [\n now.getFullYear(),\n String(now.getMonth() + 1).padStart(2, \"0\"),\n String(now.getDate()).padStart(2, \"0\"),\n String(now.getHours()).padStart(2, \"0\"),\n String(now.getMinutes()).padStart(2, \"0\"),\n String(now.getSeconds()).padStart(2, \"0\"),\n ].join(\"\");\n\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, \"_\").toLowerCase();\n const fileName = `${version}_${safeName}.sql`;\n const filePath = join(this.config.migrationsDir, fileName);\n\n const template = `-- Migration: ${name}\n-- Version: ${version}\n-- Created: ${now.toISOString()}\n\n-- UP\n-- Add your forward migration SQL here\n\n\n-- DOWN\n-- Add your rollback migration SQL here\n\n`;\n\n await writeFile(filePath, template, \"utf-8\");\n\n return filePath;\n }\n\n /**\n * Validate migration integrity\n */\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\n const errors: string[] = [];\n const status = await this.status();\n\n if (!this.config.validateChecksums) {\n return { valid: true, errors };\n }\n\n for (const applied of status.applied) {\n const migration = this.migrations.find(\n (m) => m.version === applied.version,\n );\n\n if (!migration) {\n errors.push(\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`,\n );\n continue;\n }\n\n if (applied.checksum && migration.checksum !== applied.checksum) {\n errors.push(\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`,\n );\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n }\n}\n","#!/usr/bin/env node\n/**\n * Database Migration CLI\n *\n * Command-line interface for running database migrations.\n *\n * Usage:\n * npx platform-migrate status # Show migration status\n * npx platform-migrate up # Run all pending migrations\n * npx platform-migrate up --to V # Run migrations up to version V\n * npx platform-migrate up --dry-run # Preview without applying\n * npx platform-migrate down # Rollback last migration\n * npx platform-migrate down --steps N # Rollback last N migrations\n * npx platform-migrate reset # Rollback all and re-run\n * npx platform-migrate create NAME # Create new migration file\n * npx platform-migrate validate # Validate migration integrity\n *\n * Environment Variables:\n * DATABASE_URL - PostgreSQL connection string\n * MIGRATIONS_DIR - Directory containing migration files (default: ./migrations)\n * MIGRATIONS_TABLE - Table name for tracking (default: _migrations)\n */\n\nimport { Migrator } from \"./Migrator\";\nimport type { MigrationResult } from \"../interfaces/IMigration\";\n\ninterface CliOptions {\n command: string;\n dryRun: boolean;\n steps: number;\n to?: string;\n name?: string;\n migrationsDir: string;\n help: boolean;\n}\n\nconst HELP_TEXT = `\nDatabase Migration CLI\n\nUSAGE:\n platform-migrate <command> [options]\n\nCOMMANDS:\n status Show current migration status\n up Run all pending migrations\n down Rollback the last migration\n reset Rollback all and re-run migrations\n goto <ver> Migrate to a specific version\n create <name> Create a new migration file\n validate Validate migration integrity\n\nOPTIONS:\n --dry-run Preview changes without applying\n --steps <n> Number of migrations to rollback (for down command)\n --to <ver> Target version (for up command)\n --dir <path> Migrations directory (default: ./migrations)\n --help, -h Show this help message\n\nENVIRONMENT:\n DATABASE_URL PostgreSQL connection string (required)\n MIGRATIONS_DIR Default migrations directory\n MIGRATIONS_TABLE Migration tracking table name\n\nEXAMPLES:\n platform-migrate status\n platform-migrate up\n platform-migrate up --dry-run\n platform-migrate down --steps 3\n platform-migrate create add_users_table\n platform-migrate goto 20240101000000\n`;\n\nfunction parseArgs(args: string[]): CliOptions {\n const options: CliOptions = {\n command: \"\",\n dryRun: false,\n steps: 1,\n migrationsDir: process.env.MIGRATIONS_DIR ?? \"./migrations\",\n help: false,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i]!;\n\n if (arg === \"--dry-run\") {\n options.dryRun = true;\n } else if (arg === \"--steps\" && args[i + 1]) {\n options.steps = parseInt(args[++i]!, 10);\n } else if (arg === \"--to\" && args[i + 1]) {\n options.to = args[++i];\n } else if ((arg === \"--dir\" || arg === \"-d\") && args[i + 1]) {\n options.migrationsDir = args[++i]!;\n } else if (arg === \"--help\" || arg === \"-h\") {\n options.help = true;\n } else if (!arg.startsWith(\"-\") && !options.command) {\n options.command = arg;\n } else if (!arg.startsWith(\"-\") && options.command && !options.name) {\n options.name = arg;\n }\n }\n\n return options;\n}\n\nfunction formatResults(results: MigrationResult[]): void {\n if (results.length === 0) {\n console.log(\"No migrations to run.\");\n return;\n }\n\n for (const result of results) {\n const icon = result.success ? \"✓\" : \"✗\";\n const status = result.dryRun ? \"[DRY RUN]\" : \"\";\n const time = result.success ? `(${result.executionTime}ms)` : \"\";\n\n if (result.success) {\n console.log(\n ` ${icon} ${result.migration.version} - ${result.migration.name} ${time} ${status}`,\n );\n } else {\n console.error(\n ` ${icon} ${result.migration.version} - ${result.migration.name}`,\n );\n console.error(` Error: ${result.error?.message}`);\n }\n }\n\n const successful = results.filter((r) => r.success).length;\n const failed = results.filter((r) => !r.success).length;\n\n console.log(`\\n${successful} successful, ${failed} failed`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n const options = parseArgs(args);\n\n if (options.help || !options.command) {\n console.log(HELP_TEXT);\n process.exit(options.help ? 0 : 1);\n }\n\n // Check for DATABASE_URL\n if (!process.env.DATABASE_URL) {\n console.error(\"Error: DATABASE_URL environment variable is required\");\n process.exit(1);\n }\n\n try {\n // Dynamic import PostgresDatabase to keep dependencies optional\n const { PostgresDatabase } =\n await import(\"../adapters/postgres/PostgresDatabase\");\n const db = await PostgresDatabase.fromEnv();\n\n const migrator = new Migrator(db, {\n tableName: process.env.MIGRATIONS_TABLE ?? \"_migrations\",\n migrationsDir: options.migrationsDir,\n });\n\n // Load migrations from directory\n try {\n await migrator.loadMigrations(options.migrationsDir);\n } catch (e) {\n // Directory may not exist for some commands\n if (options.command !== \"create\") {\n console.warn(\n `Warning: Could not load migrations from ${options.migrationsDir}`,\n );\n }\n }\n\n switch (options.command) {\n case \"status\": {\n const status = await migrator.status();\n console.log(\"\\n=== Migration Status ===\\n\");\n console.log(`Current Version: ${status.currentVersion ?? \"None\"}`);\n console.log(`Latest Version: ${status.latestVersion ?? \"None\"}`);\n console.log(`\\nApplied (${status.applied.length}):`);\n for (const m of status.applied) {\n console.log(\n ` ✓ ${m.version} - ${m.name} (${m.appliedAt.toISOString()})`,\n );\n }\n console.log(`\\nPending (${status.pending.length}):`);\n for (const m of status.pending) {\n console.log(` ○ ${m.version} - ${m.name}`);\n }\n break;\n }\n\n case \"up\": {\n console.log(\n options.dryRun\n ? \"\\n=== Dry Run: Migrate Up ===\\n\"\n : \"\\n=== Migrating Up ===\\n\",\n );\n const results = await migrator.up({\n dryRun: options.dryRun,\n to: options.to,\n });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"down\": {\n console.log(\n options.dryRun\n ? \"\\n=== Dry Run: Rollback ===\\n\"\n : \"\\n=== Rolling Back ===\\n\",\n );\n const results = await migrator.down({\n dryRun: options.dryRun,\n steps: options.steps,\n });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"reset\": {\n console.log(\n options.dryRun\n ? \"\\n=== Dry Run: Reset ===\\n\"\n : \"\\n=== Resetting Database ===\\n\",\n );\n const results = await migrator.reset({ dryRun: options.dryRun });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"goto\": {\n if (!options.name) {\n console.error(\n \"Error: Version required. Usage: platform-migrate goto <version>\",\n );\n process.exit(1);\n }\n console.log(`\\n=== Migrating to Version ${options.name} ===\\n`);\n const results = await migrator.goto(options.name, {\n dryRun: options.dryRun,\n });\n formatResults(results);\n if (results.some((r) => !r.success)) {\n process.exit(1);\n }\n break;\n }\n\n case \"create\": {\n if (!options.name) {\n console.error(\n \"Error: Migration name required. Usage: platform-migrate create <name>\",\n );\n process.exit(1);\n }\n const filePath = await migrator.create(options.name);\n console.log(`\\nCreated migration: ${filePath}\\n`);\n break;\n }\n\n case \"validate\": {\n console.log(\"\\n=== Validating Migrations ===\\n\");\n const { valid, errors } = await migrator.validate();\n if (valid) {\n console.log(\"✓ All migrations are valid\");\n } else {\n console.error(\"✗ Validation failed:\");\n for (const error of errors) {\n console.error(` - ${error}`);\n }\n process.exit(1);\n }\n break;\n }\n\n default:\n console.error(`Unknown command: ${options.command}`);\n console.log(HELP_TEXT);\n process.exit(1);\n }\n\n await db.close();\n } catch (error) {\n console.error(\"Error:\", error instanceof Error ? error.message : error);\n process.exit(1);\n }\n}\n\n// Run if executed directly\nmain().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n});\n"],"mappings":"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","names":["module","PostgresDatabase"]}