@noego/proper 0.0.8 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.mjs CHANGED
@@ -429,9 +429,10 @@ var init_MigrationDirectoryReader = __esm({
429
429
  /**
430
430
  * Resolves the appropriate file for a migration based on dialect.
431
431
  * Priority: dialect-specific file > generic file
432
+ * File extensions: `.mysql.up.sql`, `.sqlite.up.sql`, `.pg.up.sql`.
432
433
  */
433
434
  resolveFile(baseName, direction) {
434
- const dialectExt = this.dialect === "sql" ? "mysql" : "sqlite";
435
+ const dialectExt = this.dialect === "sql" ? "mysql" : this.dialect;
435
436
  const dialectFile = path.join(this.directory, `${baseName}.${dialectExt}.${direction}.sql`);
436
437
  if (fs.existsSync(dialectFile)) return dialectFile;
437
438
  const genericFile = path.join(this.directory, `${baseName}.${direction}.sql`);
@@ -442,14 +443,14 @@ var init_MigrationDirectoryReader = __esm({
442
443
  * Checks if a file path is dialect-specific (contains .mysql. or .sqlite. in the name)
443
444
  */
444
445
  isDialectSpecific(filePath) {
445
- return /\.(mysql|sqlite)\.(up|down)\.sql$/i.test(filePath);
446
+ return /\.(mysql|sqlite|pg)\.(up|down)\.sql$/i.test(filePath);
446
447
  }
447
448
  loadMigrations(table, connection) {
448
449
  fs.existsSync(this.directory) || fs.mkdirSync(this.directory);
449
450
  const dir_content = fs.readdirSync(this.directory, { withFileTypes: true }).filter((file) => file.isFile()).map((file) => file.name);
450
451
  const uniqueKeys = /* @__PURE__ */ new Set();
451
452
  dir_content.forEach((file) => {
452
- const key = file.replace(/(?:\.(mysql|sqlite))?\.(up|down)\.(sql|js)/i, "").toLowerCase();
453
+ const key = file.replace(/(?:\.(mysql|sqlite|pg))?\.(up|down)\.(sql|js)/i, "").toLowerCase();
453
454
  uniqueKeys.add(key);
454
455
  });
455
456
  const migration_sorter = {};
@@ -526,6 +527,12 @@ var init_MigrationSetup = __esm({
526
527
  up TEXT,
527
528
  down TEXT,
528
529
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
530
+ )` : this.config.database === "pg" ? `CREATE TABLE IF NOT EXISTS ${tableName} (
531
+ id SERIAL PRIMARY KEY,
532
+ migration_key TEXT,
533
+ up TEXT,
534
+ down TEXT,
535
+ created_at TIMESTAMPTZ DEFAULT now()
529
536
  )` : `CREATE TABLE IF NOT EXISTS ${tableName} (
530
537
  id INT AUTO_INCREMENT PRIMARY KEY,
531
538
  migration_key VARCHAR(255),
@@ -572,33 +579,38 @@ function MySqlDialectParser(sql) {
572
579
  }
573
580
  return result;
574
581
  }
575
- function SqliteDialectParser(sql) {
576
- const lines = sql.split("\n");
577
- let result = "";
578
- let isInSqliteBlock = true;
579
- const startSqliteRegex = /^\s*--\s*\[\s*sqlite\s*\]\s*$/i;
582
+ function markerDialectParser(names) {
583
+ const startRegex = new RegExp(`^\\s*--\\s*\\[\\s*(${names.join("|")})\\s*\\]\\s*$`, "i");
580
584
  const anyDialectRegex = /^\s*--\s*\[\s*\w+\s*\]\s*$/i;
581
- for (const line of lines) {
582
- const trimmed = line.trim();
583
- if (startSqliteRegex.test(trimmed)) {
584
- isInSqliteBlock = true;
585
- result += line + "\n";
586
- continue;
587
- } else if (anyDialectRegex.test(trimmed) && !startSqliteRegex.test(trimmed)) {
588
- isInSqliteBlock = false;
589
- continue;
590
- }
591
- if (!isInSqliteBlock && line.toLowerCase().includes("create index")) {
592
- isInSqliteBlock = true;
593
- }
594
- if (isInSqliteBlock) {
595
- result += line + "\n";
585
+ return function(sql) {
586
+ const lines = sql.split("\n");
587
+ let result = "";
588
+ let capturing = true;
589
+ for (const line of lines) {
590
+ const trimmed = line.trim();
591
+ if (startRegex.test(trimmed)) {
592
+ capturing = true;
593
+ result += line + "\n";
594
+ continue;
595
+ } else if (anyDialectRegex.test(trimmed)) {
596
+ capturing = false;
597
+ continue;
598
+ }
599
+ if (!capturing && line.toLowerCase().includes("create index")) {
600
+ capturing = true;
601
+ }
602
+ if (capturing) {
603
+ result += line + "\n";
604
+ }
596
605
  }
597
- }
598
- return result;
606
+ return result;
607
+ };
599
608
  }
609
+ var SqliteDialectParser, PgDialectParser;
600
610
  var init_MigrationDialectParser = __esm({
601
611
  "framework/MigrationDialectParser.ts"() {
612
+ SqliteDialectParser = markerDialectParser(["sqlite"]);
613
+ PgDialectParser = markerDialectParser(["pg", "postgres", "postgresql"]);
602
614
  }
603
615
  });
604
616
 
@@ -606,7 +618,7 @@ var init_MigrationDialectParser = __esm({
606
618
  function isPromiseLike(value) {
607
619
  return !!value && typeof value.then === "function";
608
620
  }
609
- var BaseSQLRunner, SQLRunner, SQLiteRunner;
621
+ var BaseSQLRunner, SQLRunner, SQLiteRunner, PgRunner;
610
622
  var init_SQLRunner = __esm({
611
623
  "framework/SQLRunner.ts"() {
612
624
  BaseSQLRunner = class {
@@ -819,18 +831,125 @@ ${sql}
819
831
  });
820
832
  }
821
833
  };
834
+ PgRunner = class _PgRunner extends BaseSQLRunner {
835
+ constructor(connection) {
836
+ super();
837
+ this.connection = connection;
838
+ }
839
+ /** `?` -> `$1`, `$2`, ... outside of string literals / comments. */
840
+ static toPositional(sql) {
841
+ let out = "";
842
+ let n = 0;
843
+ let inSingle = false;
844
+ let inDouble = false;
845
+ let inLineComment = false;
846
+ let inBlockComment = false;
847
+ for (let i = 0; i < sql.length; i++) {
848
+ const ch = sql[i];
849
+ const next = sql[i + 1];
850
+ if (inLineComment) {
851
+ out += ch;
852
+ if (ch === "\n") inLineComment = false;
853
+ continue;
854
+ }
855
+ if (inBlockComment) {
856
+ out += ch;
857
+ if (ch === "*" && next === "/") {
858
+ out += next;
859
+ i++;
860
+ inBlockComment = false;
861
+ }
862
+ continue;
863
+ }
864
+ if (inSingle) {
865
+ out += ch;
866
+ if (ch === "'") inSingle = false;
867
+ continue;
868
+ }
869
+ if (inDouble) {
870
+ out += ch;
871
+ if (ch === '"') inDouble = false;
872
+ continue;
873
+ }
874
+ if (ch === "-" && next === "-") {
875
+ out += ch;
876
+ inLineComment = true;
877
+ continue;
878
+ }
879
+ if (ch === "/" && next === "*") {
880
+ out += ch + next;
881
+ i++;
882
+ inBlockComment = true;
883
+ continue;
884
+ }
885
+ if (ch === "'") {
886
+ out += ch;
887
+ inSingle = true;
888
+ continue;
889
+ }
890
+ if (ch === '"') {
891
+ out += ch;
892
+ inDouble = true;
893
+ continue;
894
+ }
895
+ if (ch === "?") {
896
+ out += `$${++n}`;
897
+ continue;
898
+ }
899
+ out += ch;
900
+ }
901
+ return out;
902
+ }
903
+ run(sql, params) {
904
+ return __async(this, null, function* () {
905
+ if (params.length > 0) {
906
+ return yield this.connection.query(_PgRunner.toPositional(sql), params);
907
+ }
908
+ return yield this.connection.query(sql);
909
+ });
910
+ }
911
+ _query(_0) {
912
+ return __async(this, arguments, function* (sql, params = []) {
913
+ const result = yield this.run(sql, params);
914
+ return [result.rows, result];
915
+ });
916
+ }
917
+ _execute(_0) {
918
+ return __async(this, arguments, function* (sql, params = []) {
919
+ var _a;
920
+ const result = yield this.run(sql, params);
921
+ return [{ changes: (_a = result.rowCount) != null ? _a : 0, lastID: void 0 }, result];
922
+ });
923
+ }
924
+ _end() {
925
+ return __async(this, null, function* () {
926
+ if (this.connection && typeof this.connection.end === "function") {
927
+ yield this.connection.end();
928
+ }
929
+ });
930
+ }
931
+ };
822
932
  }
823
933
  });
824
934
 
825
935
  // framework/MigrationRunner.ts
826
936
  import fs3 from "fs";
827
- import mysql from "mysql2/promise";
828
- import * as sqlite from "sqlite";
829
- import * as sqlite3 from "sqlite3";
830
937
  function toError(error) {
831
938
  if (error instanceof Error) return error;
832
939
  return new Error(String(error));
833
940
  }
941
+ function makeRunner(database, conn) {
942
+ switch (database) {
943
+ case "sql":
944
+ return new SQLRunner(conn);
945
+ case "sqlite":
946
+ return new SQLiteRunner(conn);
947
+ case "pg":
948
+ return new PgRunner(conn);
949
+ default:
950
+ throw ConfigurationError.unknownDatabaseType(database);
951
+ }
952
+ }
834
953
  var MigrationRunnerFactory, MySQLMigrationRunner, FileMigrationConfigReader, MigrationCreator;
835
954
  var init_MigrationRunner = __esm({
836
955
  "framework/MigrationRunner.ts"() {
@@ -856,6 +975,7 @@ var init_MigrationRunner = __esm({
856
975
  }
857
976
  static createConnection(config) {
858
977
  return __async(this, null, function* () {
978
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
859
979
  let conn = null;
860
980
  switch (config.database) {
861
981
  case "sql":
@@ -866,7 +986,8 @@ var init_MigrationRunner = __esm({
866
986
  password: process.env.SQL_PASSWORD
867
987
  }, config.sql);
868
988
  try {
869
- conn = yield mysql.createConnection(settings);
989
+ const mysql = yield import("mysql2/promise");
990
+ conn = yield ((_b = (_a = mysql.default) == null ? void 0 : _a.createConnection) != null ? _b : mysql.createConnection)(settings);
870
991
  return conn;
871
992
  } catch (error) {
872
993
  throw DatabaseConnectionError.connectionFailed("sql", toError(error).message);
@@ -876,14 +997,32 @@ var init_MigrationRunner = __esm({
876
997
  throw ConfigurationError.missingDatabaseConfiguration("sqlite");
877
998
  }
878
999
  try {
879
- conn = yield sqlite.open({
1000
+ const sqlite = yield import("sqlite");
1001
+ const sqlite3 = yield import("sqlite3");
1002
+ conn = yield ((_d = (_c = sqlite.default) == null ? void 0 : _c.open) != null ? _d : sqlite.open)({
880
1003
  filename: config.sqlite.database,
881
- driver: sqlite3.Database
1004
+ driver: (_f = (_e = sqlite3.default) == null ? void 0 : _e.Database) != null ? _f : sqlite3.Database
882
1005
  });
883
1006
  return conn;
884
1007
  } catch (error) {
885
1008
  throw DatabaseConnectionError.connectionFailed("sqlite", toError(error).message);
886
1009
  }
1010
+ case "pg":
1011
+ if (!config.pg && !process.env.DATABASE_URL) {
1012
+ throw ConfigurationError.missingDatabaseConfiguration("pg");
1013
+ }
1014
+ try {
1015
+ const pgcfg = (_g = config.pg) != null ? _g : {};
1016
+ const connectionString = (_h = pgcfg.connectionString) != null ? _h : process.env.DATABASE_URL;
1017
+ const settings2 = connectionString ? { connectionString, ssl: pgcfg.ssl } : __spreadProps(__spreadValues({}, pgcfg), { password: (_i = pgcfg.password) != null ? _i : process.env.PG_PASSWORD });
1018
+ const pg = yield import("pg");
1019
+ const Client = (_k = (_j = pg.default) == null ? void 0 : _j.Client) != null ? _k : pg.Client;
1020
+ conn = new Client(settings2);
1021
+ yield conn.connect();
1022
+ return conn;
1023
+ } catch (error) {
1024
+ throw DatabaseConnectionError.connectionFailed("pg", toError(error).message);
1025
+ }
887
1026
  default:
888
1027
  throw ConfigurationError.unknownDatabaseType(config.database);
889
1028
  }
@@ -904,16 +1043,7 @@ var init_MigrationRunner = __esm({
904
1043
  sqlrunner = conn;
905
1044
  driverConnection = null;
906
1045
  } else {
907
- switch (config.database) {
908
- case "sql":
909
- sqlrunner = new SQLRunner(conn);
910
- break;
911
- case "sqlite":
912
- sqlrunner = new SQLiteRunner(conn);
913
- break;
914
- default:
915
- throw ConfigurationError.unknownDatabaseType(config.database);
916
- }
1046
+ sqlrunner = makeRunner(config.database, conn);
917
1047
  }
918
1048
  const setup = new MigrationSetup(sqlrunner, config);
919
1049
  const read_strategy = this.getReadStategy(config);
@@ -925,17 +1055,7 @@ var init_MigrationRunner = __esm({
925
1055
  createEmpty(config) {
926
1056
  return __async(this, null, function* () {
927
1057
  const conn = null;
928
- let sqlrunner;
929
- switch (config.database) {
930
- case "sql":
931
- sqlrunner = new SQLRunner(conn);
932
- break;
933
- case "sqlite":
934
- sqlrunner = new SQLiteRunner(conn);
935
- break;
936
- default:
937
- throw ConfigurationError.unknownDatabaseType(config.database);
938
- }
1058
+ const sqlrunner = makeRunner(config.database, conn);
939
1059
  const setup = new MigrationSetup(sqlrunner, config);
940
1060
  const read_strategy = this.getReadStategy(config);
941
1061
  const migration_files = new MigrationDirectoryReader(config.migration_folder, read_strategy, sqlrunner, config.database);
@@ -948,6 +1068,8 @@ var init_MigrationRunner = __esm({
948
1068
  return MySqlDialectParser;
949
1069
  case "sqlite":
950
1070
  return SqliteDialectParser;
1071
+ case "pg":
1072
+ return PgDialectParser;
951
1073
  default:
952
1074
  throw ConfigurationError.unknownDatabaseType(config.database);
953
1075
  }
@@ -1134,6 +1256,8 @@ var init_MigrationRunner = __esm({
1134
1256
  config.database = "sql";
1135
1257
  } else if (config.sqlite) {
1136
1258
  config.database = "sqlite";
1259
+ } else if (config.pg) {
1260
+ config.database = "pg";
1137
1261
  } else {
1138
1262
  throw ConfigurationError.missingRequiredProperty("database");
1139
1263
  }
@@ -1189,8 +1313,10 @@ var init_MigrationRunner = __esm({
1189
1313
  // framework/SeedRunner.ts
1190
1314
  import fs4 from "fs";
1191
1315
  import path2 from "path";
1316
+ import { pathToFileURL } from "url";
1192
1317
  import Ajv from "ajv";
1193
1318
  import addFormats from "ajv-formats";
1319
+ import { tsImport } from "tsx/esm/api";
1194
1320
  function resolveAlias(name, aliasMap) {
1195
1321
  var _a;
1196
1322
  if (!aliasMap) return name;
@@ -1327,6 +1453,10 @@ function runSqlSeed(runner, resolved, direction) {
1327
1453
  function loadSeedModule(modulePath) {
1328
1454
  return __async(this, null, function* () {
1329
1455
  const resolved = path2.resolve(modulePath);
1456
+ if (resolved.endsWith(".ts")) {
1457
+ const fileUrl = pathToFileURL(resolved).href;
1458
+ return tsImport(fileUrl, fileUrl);
1459
+ }
1330
1460
  return import(resolved);
1331
1461
  });
1332
1462
  }
@@ -1426,6 +1556,10 @@ var require_cli = __commonJS({
1426
1556
  init_errors();
1427
1557
  init_SeedRunner();
1428
1558
  var args = MigrationCLIFactory.setup(process.argv);
1559
+ if (args.flags.help) {
1560
+ printUsage();
1561
+ process.exit(0);
1562
+ }
1429
1563
  if (!args.commands || args.commands.length === 0) {
1430
1564
  console.error("Error: No command specified");
1431
1565
  printUsage();