orchid-orm 1.76.5 → 1.77.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"bun.js","names":[],"sources":["../../src/migrations/adapters/bun.ts"],"sourcesContent":["import { patchRakeDb } from 'orchid-orm/migrations';\nexport * from '../patch-rake-db-types';\nexport * from 'rake-db/bun';\n\npatchRakeDb();\n"],"mappings":"mDAIa"}
1
+ {"version":3,"file":"bun.js","names":["patchRakeDb"],"sources":["../../src/migrations/adapters/bun.ts"],"sourcesContent":["import { patchRakeDb } from 'orchid-orm/migrations';\nexport * from '../patch-rake-db-types';\nexport * from 'rake-db/bun';\n\npatchRakeDb();\n"],"mappings":"CAIAA,kCAAAA,CAAAA,CAAAA,YAAAA,CAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"bun.mjs","names":[],"sources":["../../src/migrations/adapters/bun.ts"],"sourcesContent":["import { patchRakeDb } from 'orchid-orm/migrations';\nexport * from '../patch-rake-db-types';\nexport * from 'rake-db/bun';\n\npatchRakeDb();\n"],"mappings":";;AAIA,aAAa"}
1
+ {"version":3,"file":"bun.mjs","names":[],"sources":["../../src/migrations/adapters/bun.ts"],"sourcesContent":["import { patchRakeDb } from 'orchid-orm/migrations';\nexport * from '../patch-rake-db-types';\nexport * from 'rake-db/bun';\n\npatchRakeDb();\n"],"mappings":";;AAIA,YAAY"}
@@ -1,5 +1,6 @@
1
1
  import { ColumnSchemaConfig } from "pqb/internal";
2
2
  export * from "rake-db";
3
+ declare const patchRakeDb$1: () => void;
3
4
  declare module 'rake-db' {
4
5
  interface RakeDbConfig {
5
6
  dbPath?: string;
@@ -12,5 +13,5 @@ declare module 'rake-db' {
12
13
  generateTableTo?(tableName: string): string;
13
14
  }
14
15
  }
15
- declare const patchRakeDb: () => void;
16
+ declare const patchRakeDb: typeof patchRakeDb$1;
16
17
  export { patchRakeDb };
@@ -15,7 +15,7 @@ var __copyProps = (to, from, except, desc) => {
15
15
  }
16
16
  return to;
17
17
  };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
19
19
  value: mod,
20
20
  enumerable: true
21
21
  }) : target, mod));
@@ -26,8 +26,6 @@ node_path = __toESM(node_path);
26
26
  let node_url = require("node:url");
27
27
  let node_fs_promises = require("node:fs/promises");
28
28
  node_fs_promises = __toESM(node_fs_promises);
29
- let typescript = require("typescript");
30
- typescript = __toESM(typescript);
31
29
  const viewDataToSql = (viewData, viewName) => {
32
30
  return (0, pqb_internal.sqlToRawSql)(viewDataToQuerySql(viewData, viewName));
33
31
  };
@@ -351,8 +349,9 @@ const compareColumns = async (adapter, domainsMap, ast, currentSchema, compareSq
351
349
  if (!typeCasts.get(dbBaseType)?.has(codeBaseType)) {
352
350
  if (!(dbColumn instanceof pqb_internal.EnumColumn) || !(codeColumn instanceof pqb_internal.EnumColumn) || !(0, pqb_internal.deepCompare)(dbColumn.options, codeColumn.options)) {
353
351
  if (verifying) throw new AbortSignal();
352
+ const tableName = (0, rake_db.concatSchemaAndName)(changeTableData.changeTableAst);
354
353
  if (await (0, rake_db.promptSelect)({
355
- message: `Cannot cast type of ${(0, rake_db.concatSchemaAndName)(changeTableData.changeTableAst)}'s column ${key} from ${dbType} to ${codeType}`,
354
+ message: `Cannot cast type of ${tableName}'s column ${key} from ${dbType} to ${codeType}`,
356
355
  options: [`${pqb_internal.colors.yellowBold(`-/+`)} recreate the column, existing data will be ${pqb_internal.colors.red("lost")}`, `write migration manually`]
357
356
  })) throw new AbortSignal();
358
357
  dbColumn.data.name = codeColumn.data.name;
@@ -432,7 +431,7 @@ JOIN pg_type AS t ON t.oid = casttarget`);
432
431
  for (const [source, target] of rows) {
433
432
  const set = directTypeCasts.get(source);
434
433
  if (set) set.add(target);
435
- else directTypeCasts.set(source, new Set([target]));
434
+ else directTypeCasts.set(source, /* @__PURE__ */ new Set([target]));
436
435
  }
437
436
  typeCasts = /* @__PURE__ */ new Map();
438
437
  for (const [type, directSet] of directTypeCasts.entries()) {
@@ -563,7 +562,8 @@ const makeComparableDomain = (currentSchema, schemaName, name, column) => {
563
562
  inner = inner.data.item;
564
563
  arrayDims++;
565
564
  }
566
- const [typeSchema = "pg_catalog", type] = (0, rake_db.getSchemaAndTableFromName)(currentSchema, getColumnDbType(inner, currentSchema));
565
+ const fullType = getColumnDbType(inner, currentSchema);
566
+ const [typeSchema = "pg_catalog", type] = (0, rake_db.getSchemaAndTableFromName)(currentSchema, fullType);
567
567
  return {
568
568
  schemaName,
569
569
  name,
@@ -802,7 +802,7 @@ const processPrimaryKey = (config, changeTableData) => {
802
802
  };
803
803
  const changePrimaryKey = (config, columnsPrimaryKey, { codeTable, dbTableData: { primaryKey: dbPrimaryKey }, changeTableAst: { shape, add, drop }, changingColumns }) => {
804
804
  const tablePrimaryKey = codeTable.internal.tableData.primaryKey;
805
- const primaryKey = [...new Set([...columnsPrimaryKey, ...(config.snakeCase ? tablePrimaryKey?.columns.map((key) => ({
805
+ const primaryKey = [.../* @__PURE__ */ new Set([...columnsPrimaryKey, ...(config.snakeCase ? tablePrimaryKey?.columns.map((key) => ({
806
806
  key,
807
807
  name: (0, pqb_internal.toSnakeCase)(key)
808
808
  })) : tablePrimaryKey?.columns.map((key) => ({
@@ -1302,7 +1302,7 @@ const collectCodeFkeys = (config, { codeTable, changeTableAst: { shape } }, curr
1302
1302
  };
1303
1303
  const fnOrTableToString = (fnOrTable) => {
1304
1304
  if (typeof fnOrTable !== "string") {
1305
- const { schema, table, nameInDb } = new (fnOrTable())();
1305
+ const { schema, table, nameInDb } = (0, pqb_internal.getForeignKeyTableInstance)(fnOrTable());
1306
1306
  const name = nameInDb || table;
1307
1307
  if (!name) throw new Error("Referenced table is missing table property");
1308
1308
  fnOrTable = (0, rake_db.concatSchemaAndName)({
@@ -2210,7 +2210,7 @@ const processDefaultPrivileges = (ast, dbStructure, { internal: { roles } }) =>
2210
2210
  const codeObj = codePrivilege.objectConfigs.find((o) => o.object === objectType);
2211
2211
  const dbPrivs = dbObj?.privilegeConfigs ?? [];
2212
2212
  const codePrivs = codeObj?.privilegeConfigs ?? [];
2213
- const collapsedDbPrivs = collapsePrivilegesToAll({
2213
+ const collapsedDbPrivilege = {
2214
2214
  owner: dbPrivilege.owner,
2215
2215
  grantee: dbPrivilege.grantee,
2216
2216
  schema: dbPrivilege.schema,
@@ -2218,7 +2218,8 @@ const processDefaultPrivileges = (ast, dbStructure, { internal: { roles } }) =>
2218
2218
  object: objectType,
2219
2219
  privilegeConfigs: dbPrivs
2220
2220
  }]
2221
- }, objectTypeToAllPrivileges).objectConfigs[0]?.privilegeConfigs ?? [];
2221
+ };
2222
+ const collapsedDbPrivs = collapsePrivilegesToAll(collapsedDbPrivilege, objectTypeToAllPrivileges).objectConfigs[0]?.privilegeConfigs ?? [];
2222
2223
  const toGrant = codePrivs.filter((cp) => !collapsedDbPrivs.some((dp) => privilegeConfigsMatch(cp, dp, objectType, objectTypeToAllPrivileges)));
2223
2224
  const toRevoke = dbPrivs.filter((dp) => !codePrivs.some((cp) => privilegeConfigsMatch(cp, dp, objectType, objectTypeToAllPrivileges)));
2224
2225
  if (toGrant.length) {
@@ -2642,9 +2643,7 @@ const dbViewOptionsToAst = (view) => {
2642
2643
  case "security_barrier":
2643
2644
  options.securityBarrier = value === "true";
2644
2645
  break;
2645
- case "security_invoker":
2646
- options.securityInvoker = value === "true";
2647
- break;
2646
+ case "security_invoker": options.securityInvoker = value === "true";
2648
2647
  }
2649
2648
  }
2650
2649
  return options;
@@ -3069,10 +3068,11 @@ const report = (ast, config, currentSchema) => {
3069
3068
  break;
3070
3069
  }
3071
3070
  case "policy": {
3072
- const summary = formatPolicySummary(a, dbItemName({
3071
+ const table = dbItemName({
3073
3072
  schema: a.schema,
3074
3073
  name: a.table
3075
- }, currentSchema));
3074
+ }, currentSchema);
3075
+ const summary = formatPolicySummary(a, table);
3076
3076
  const message = a.action === "create" ? `${green("+ create policy")} ${a.name}: ${summary}` : `${red("- drop policy")} ${a.name}: ${summary}`;
3077
3077
  code.push(message);
3078
3078
  break;
@@ -3159,7 +3159,7 @@ const formatPolicyChangeDefinition = (policy) => {
3159
3159
  var AbortSignal = class extends Error {};
3160
3160
  const generate = async (adapters, config, args, afterPull) => {
3161
3161
  let { dbPath } = config;
3162
- if (!dbPath || !config.baseTable) throw invalidConfig(config);
3162
+ if (!dbPath || !(0, rake_db.getTableFactoryConfig)(config)) throw invalidConfig(config);
3163
3163
  if (!adapters.length) throw new Error(`Database options must not be empty`);
3164
3164
  if (!dbPath.endsWith(".ts")) dbPath += ".ts";
3165
3165
  let migrationName = args[0] ?? "generated";
@@ -3229,7 +3229,7 @@ const generate = async (adapters, config, args, afterPull) => {
3229
3229
  if (up) for (const adapter of adapters) await (0, rake_db.migrateAndClose)(adapter, config);
3230
3230
  else if (!afterPull) await closeAdapters(adapters);
3231
3231
  };
3232
- const invalidConfig = (config) => /* @__PURE__ */ new Error(`\`${config.dbPath ? "baseTable" : "dbPath"}\` setting must be set in the migrations config for the generator to work`);
3232
+ const invalidConfig = (config) => /* @__PURE__ */ new Error(`\`${config.dbPath ? "baseTable` or `defineTable" : "dbPath"}\` setting must be set in the migrations config for the generator to work`);
3233
3233
  const getDbFromConfig = async (config, dbPath) => {
3234
3234
  const db = (await config.import((0, node_url.pathToFileURL)(node_path.default.resolve(config.basePath, dbPath)).toString()))[config.dbExportedAs ?? "db"];
3235
3235
  if (!db?.$qb) throw new Error(`Unable to import OrchidORM instance as ${config.dbExportedAs ?? "db"} from ${config.dbPath}`);
@@ -3507,95 +3507,128 @@ const processHasAndBelongsToManyColumn = (column, habtmTables, codeItems) => {
3507
3507
  const closeAdapters = (adapters) => {
3508
3508
  return Promise.all(adapters.map((x) => x.close()));
3509
3509
  };
3510
- const getTableInfosAndFKeys = (asts, config) => {
3510
+ const getTableInfos = (asts, config) => {
3511
3511
  const generateTableTo = config.generateTableTo ?? ((name) => `./tables/${name}.table.ts`);
3512
3512
  const tableInfos = {};
3513
- const fkeys = {};
3514
3513
  for (const ast of asts) if (ast.type === "table") {
3515
3514
  const tableKey = (0, pqb_internal.toCamelCase)(ast.name);
3516
3515
  const dbTableName = ast.schema ? `${ast.schema}.${ast.name}` : ast.name;
3517
3516
  let tablePath = node_path.default.resolve(config.basePath, generateTableTo(tableKey));
3518
3517
  if (!tablePath.endsWith(".ts")) tablePath += ".ts";
3519
3518
  const name = (0, pqb_internal.toPascalCase)(ast.name);
3520
- const info = {
3519
+ tableInfos[dbTableName] = {
3521
3520
  dbTableName,
3522
3521
  key: tableKey,
3523
3522
  path: tablePath,
3524
3523
  name,
3525
3524
  className: `${name}Table`
3526
3525
  };
3527
- tableInfos[dbTableName] = info;
3528
- if (ast.constraints) for (const { references } of ast.constraints) {
3529
- if (!references) continue;
3530
- (fkeys[references.fnOrTable] ??= []).push({
3531
- table: info,
3532
- references
3533
- });
3534
- }
3535
3526
  }
3536
- return {
3537
- tableInfos,
3538
- fkeys
3539
- };
3527
+ return tableInfos;
3540
3528
  };
3541
- const appCodeGenTable = (tableInfos, fkeys, ast, baseTablePath, baseTableExportedAs, currentSchema) => {
3529
+ const appCodeGenTable = (tableInfos, ast, tableFactorySource, currentSchema) => {
3542
3530
  const tableInfo = tableInfos[ast.schema ? `${ast.schema}.${ast.name}` : ast.name];
3543
- const imports = {
3544
- "orchid-orm": "Selectable, Insertable, Updatable",
3545
- [(0, pqb_internal.getImportPath)(tableInfo.path, baseTablePath)]: baseTableExportedAs
3531
+ const content = appCodeGenDefineTable(tableInfo, ast, tableFactorySource, currentSchema);
3532
+ return {
3533
+ ...tableInfo,
3534
+ content
3546
3535
  };
3547
- const props = [];
3548
- if (ast.schema) props.push(`schema = ${(0, pqb_internal.singleQuote)(ast.schema)};`);
3549
- props.push(`readonly table = ${(0, pqb_internal.singleQuote)(ast.name)};`);
3550
- if (ast.comment) props.push(`comment = ${(0, pqb_internal.singleQuote)(ast.comment)};`);
3551
- if (ast.noPrimaryKey === "ignore") props.push("noPrimaryKey = true;");
3536
+ };
3537
+ const appCodeGenDefineTable = (tableInfo, ast, tableFactorySource, currentSchema) => {
3538
+ const tableOptions = getDefineTableOptions(tableInfo, ast);
3552
3539
  const hasTableData = Boolean(ast.primaryKey || ast.indexes?.length || ast.excludes?.length || ast.constraints?.length);
3553
- const shapeCode = (0, pqb_internal.columnsShapeToCode)({
3540
+ const ctx = {
3554
3541
  t: "t",
3542
+ sql: "sql",
3555
3543
  table: ast.name,
3556
3544
  currentSchema
3557
- }, ast.shape);
3558
- props.push(`columns = this.setColumns(${hasTableData ? "\n " : ""}(t) => ({`, hasTableData ? [shapeCode] : shapeCode, hasTableData ? " })," : "}));");
3559
- if (hasTableData) props.push((0, pqb_internal.pushTableDataCode)([], ast), ");");
3560
- const relations = [];
3561
- const belongsTo = fkeys[ast.schema ? `${ast.schema}.${ast.name}` : ast.name];
3562
- if (belongsTo) for (const { table, references } of belongsTo) {
3563
- imports[(0, pqb_internal.getImportPath)(tableInfo.path, table.path)] = table.className;
3564
- relations.push(`${table.key}: this.belongsTo(() => ${table.className}, {`, [`columns: [${references.foreignColumns.map(pqb_internal.singleQuote).join(", ")}],`, `references: [${references.columns.map(pqb_internal.singleQuote).join(", ")}],`], "}),");
3565
- }
3566
- if (ast.constraints) for (const { references } of ast.constraints) {
3567
- if (!references) continue;
3568
- const table = tableInfos[references.fnOrTable];
3569
- imports[(0, pqb_internal.getImportPath)(tableInfo.path, table.path)] = table.className;
3570
- relations.push(`${table.key}: this.hasMany(() => ${table.className}, {`, [`columns: [${references.columns.map(pqb_internal.singleQuote).join(", ")}],`, `references: [${references.foreignColumns.map(pqb_internal.singleQuote).join(", ")}],`], "}),");
3571
- }
3572
- if (relations.length) props.push("", "relations = {", relations, "};");
3573
- const importsCode = importsToCode(imports);
3574
- const { name, className } = tableInfo;
3575
- const code = [
3576
- `export type ${name} = Selectable<${className}>;
3577
- export type ${name}New = Insertable<${className}>;
3578
- export type ${name}Update = Updatable<${className}>;
3579
-
3580
- export class ${className} extends ${baseTableExportedAs} {`,
3581
- props,
3582
- "}\n"
3583
- ];
3584
- return {
3585
- ...tableInfo,
3586
- content: importsCode + "\n\n" + (0, pqb_internal.codeToString)(code, "", " ")
3587
3545
  };
3546
+ const shapeCode = (0, pqb_internal.columnsShapeToCode)(ctx, ast.shape);
3547
+ const { name, className } = tableInfo;
3548
+ const code = [`export type ${name} = Selectable<typeof ${className}>;
3549
+ export type ${name}New = Insertable<typeof ${className}>;
3550
+ export type ${name}Update = Updatable<typeof ${className}>;
3551
+ `];
3552
+ if (tableOptions.length) code.push(`export const ${className} = ${tableFactorySource.exportedAs}(`, [
3553
+ `${(0, pqb_internal.singleQuote)(tableInfo.key)},`,
3554
+ ...tableOptions,
3555
+ "(t) => ({",
3556
+ shapeCode,
3557
+ "}),"
3558
+ ], `)${hasTableData ? "" : ";"}`);
3559
+ else if (hasTableData && getTableDataItemsCount(ast) === 1) code.push(`export const ${className} = ${tableFactorySource.exportedAs}(`, [
3560
+ `${(0, pqb_internal.singleQuote)(tableInfo.key)},`,
3561
+ "(t) => ({",
3562
+ shapeCode,
3563
+ "}),"
3564
+ ], ")");
3565
+ else code.push(`export const ${className} = ${tableFactorySource.exportedAs}(${(0, pqb_internal.singleQuote)(tableInfo.key)}, (t) => ({`, shapeCode, `}))${hasTableData ? "" : ";"}`);
3566
+ if (hasTableData) {
3567
+ let tableDataCode = getTableDataChainCode(ast, ctx);
3568
+ if (ast.constraints?.some(({ check }) => check)) tableDataCode = addTrailingSemicolon(tableDataCode);
3569
+ code.push(tableDataCode, ";");
3570
+ }
3571
+ return importsToCode({
3572
+ "orchid-orm": "Selectable, Insertable, Updatable",
3573
+ [(0, pqb_internal.getImportPath)(tableInfo.path, tableFactorySource.path)]: ctx.isSqlUsed ? `${tableFactorySource.exportedAs}, sql` : tableFactorySource.exportedAs
3574
+ }) + "\n\n" + formatColumnSqlChains((0, pqb_internal.codeToString)(code, "", " ")) + "\n";
3575
+ };
3576
+ const getDefineTableOptions = (tableInfo, ast) => {
3577
+ const options = [];
3578
+ if (ast.schema) options.push(`schema: ${(0, pqb_internal.singleQuote)(ast.schema)},`);
3579
+ if (tableInfo.key !== ast.name) options.push(`nameInDb: ${(0, pqb_internal.singleQuote)(ast.name)},`);
3580
+ if (ast.comment) options.push(`comment: ${(0, pqb_internal.singleQuote)(ast.comment)},`);
3581
+ if (ast.noPrimaryKey === "ignore") options.push("noPrimaryKey: true,");
3582
+ return options.length ? [
3583
+ "{",
3584
+ options,
3585
+ "},"
3586
+ ] : [];
3587
+ };
3588
+ const getTableDataChainCode = (ast, ctx) => {
3589
+ const code = [];
3590
+ if (ast.primaryKey) code.push((0, pqb_internal.primaryKeyInnerToCode)(ast.primaryKey, ""));
3591
+ if (ast.indexes) for (const index of ast.indexes) code.push(...removeTrailingComma((0, pqb_internal.indexToCode)(index, "")));
3592
+ if (ast.excludes) for (const exclude of ast.excludes) code.push(...removeTrailingComma((0, pqb_internal.excludeToCode)(exclude, "")));
3593
+ if (ast.constraints) for (const constraint of ast.constraints) code.push(...removeTrailingComma((0, pqb_internal.constraintToCode)(constraint, "", true, "", ctx)));
3594
+ return code;
3595
+ };
3596
+ const getTableDataItemsCount = (ast) => {
3597
+ return (ast.primaryKey ? 1 : 0) + (ast.indexes?.length ?? 0) + (ast.excludes?.length ?? 0) + (ast.constraints?.length ?? 0);
3598
+ };
3599
+ const removeTrailingComma = (code) => {
3600
+ if (typeof code === "string") return removeComma(code);
3601
+ const copy = [...code];
3602
+ const lastIndex = copy.length - 1;
3603
+ const last = copy[lastIndex];
3604
+ if (last !== void 0) copy[lastIndex] = removeTrailingComma(last);
3605
+ return copy;
3606
+ };
3607
+ const removeComma = (code) => code.endsWith(",") ? code.slice(0, -1) : code;
3608
+ const formatColumnSqlChains = (code) => {
3609
+ return code.replace(/^(\s+\S+: )t((?:\.\w+\([^{}\n]*\))+)\.index\(\{\n((?:\s+[^\n]*\n)*?)(\s+)\}\)(\.check\(sql[^\n]*)$/gm, (line, prefix, chain, options, _closeIndent, check) => {
3610
+ const methodIndent = `${" ".repeat(line.match(/^\s*/)?.[0].length ?? 0)} `;
3611
+ const optionIndent = `${methodIndent} `;
3612
+ const optionLines = options.split("\n").filter(Boolean).map((line) => `${optionIndent}${line.trimStart()}`).join("\n");
3613
+ return `${prefix}t${chain.replace(/\./g, `\n${methodIndent}.`)}\n${methodIndent}.index({\n${optionLines}\n${methodIndent}})\n${methodIndent}${check}`;
3614
+ });
3615
+ };
3616
+ const addTrailingSemicolon = (code) => {
3617
+ if (typeof code === "string") return `${code};`;
3618
+ const copy = [...code];
3619
+ const lastIndex = copy.length - 1;
3620
+ const last = copy[lastIndex];
3621
+ if (last !== void 0) copy[lastIndex] = addTrailingSemicolon(last);
3622
+ return copy;
3588
3623
  };
3589
3624
  function importsToCode(imports) {
3590
3625
  return Object.entries(imports).map(([from, name]) => `import { ${name} } from '${from}';`).join("\n");
3591
3626
  }
3592
- const { createSourceFile, ScriptTarget, SyntaxKind } = typescript.default;
3593
3627
  const appCodeGenUpdateDbFile = async (dbPath, tables, extensions, domains, currentSchema) => {
3594
3628
  const content = await node_fs_promises.default.readFile(dbPath, "utf-8");
3595
- const statements = getTsStatements(content);
3596
- const importName = getOrchidOrmImportName(statements);
3597
- if (!importName) throw new Error(`Main file does not contain import of orchid-orm`);
3598
- const { config, tablesList } = getOrchidOrmArgs(importName, statements);
3629
+ const importInfo = getOrchidOrmImport(content);
3630
+ if (!importInfo) throw new Error(`Main file does not contain import of orchid-orm`);
3631
+ const { config, tablesList } = getOrchidOrmArgs(content, importInfo.importName);
3599
3632
  const changes = [];
3600
3633
  let replacedConfig;
3601
3634
  if (extensions.length || domains.length) {
@@ -3611,32 +3644,18 @@ const appCodeGenUpdateDbFile = async (dbPath, tables, extensions, domains, curre
3611
3644
  }, ast.baseType.data.name ?? "")},`).join("\n ")}\n },`;
3612
3645
  replacedConfig = code + "\n}";
3613
3646
  }
3614
- const tablesChanges = makeTablesListChanges(content, statements, tablesList, tables, dbPath);
3647
+ const tablesChanges = makeTablesListChanges(content, importInfo.lastImportEnd, tablesList, tables, dbPath);
3615
3648
  if (tablesChanges) addChange(content, changes, tablesChanges.imports.pos, tablesChanges.imports.text);
3616
3649
  if (replacedConfig) replaceContent(content, changes, config.pos, config.end, replacedConfig);
3617
3650
  if (tablesChanges) addChange(content, changes, tablesChanges.tablesList.pos, tablesChanges.tablesList.text);
3618
3651
  return applyChanges(content, changes);
3619
3652
  };
3620
- const getTsStatements = (content) => {
3621
- return createSourceFile("file.ts", content, ScriptTarget.Latest, true).statements;
3622
- };
3623
- const getOrchidOrmImportName = (statements) => {
3624
- for (const node of statements) {
3625
- if (node.kind !== SyntaxKind.ImportDeclaration) continue;
3626
- const imp = node;
3627
- if (imp.moduleSpecifier.getText().slice(1, -1) !== "orchid-orm") continue;
3628
- if (!imp.importClause) continue;
3629
- const elements = imp.importClause.namedBindings?.elements;
3630
- if (!elements);
3631
- for (const element of elements) if (element.name.escapedText === "orchidORM" || element.propertyName && "escapedText" in element.propertyName && element.propertyName.escapedText === "orchidORM") return element.name.escapedText.toString();
3632
- }
3633
- };
3634
- const makeTablesListChanges = (content, statements, object, tables, dbPath) => {
3653
+ const makeTablesListChanges = (content, importPos, object, tables, dbPath) => {
3635
3654
  const spaces = getTablesListSpaces(content, object);
3636
3655
  let imports = "";
3637
3656
  let tablesList = "";
3638
- const prependComma = object.properties.length && !object.properties.hasTrailingComma;
3639
- const tablesListNewLine = content.slice(object.properties.end, object.end).includes("\n");
3657
+ const prependComma = object.hasProperties && !object.hasTrailingComma;
3658
+ const tablesListNewLine = content.slice(object.propertiesEnd, object.end).includes("\n");
3640
3659
  const tablesArr = Object.values(tables);
3641
3660
  for (let i = 0; i < tablesArr.length; i++) {
3642
3661
  const { path, className, key } = tablesArr[i];
@@ -3646,15 +3665,13 @@ const makeTablesListChanges = (content, statements, object, tables, dbPath) => {
3646
3665
  if (i === tablesArr.length - 1 && !tablesListNewLine) tablesList += `\n${spaces}`;
3647
3666
  }
3648
3667
  if (!imports.length) return;
3649
- let importPos = 0;
3650
- for (const node of statements) if (node.kind === SyntaxKind.ImportDeclaration) importPos = node.end;
3651
3668
  return {
3652
3669
  imports: {
3653
3670
  pos: importPos,
3654
3671
  text: imports
3655
3672
  },
3656
3673
  tablesList: {
3657
- pos: object.properties.end,
3674
+ pos: object.propertiesEnd,
3658
3675
  text: tablesList
3659
3676
  }
3660
3677
  };
@@ -3663,24 +3680,165 @@ const getTablesListSpaces = (content, object) => {
3663
3680
  const lines = content.slice(0, object.end).split("\n");
3664
3681
  return lines[lines.length - 1].match(/^\s+/)?.[0] || "";
3665
3682
  };
3666
- const getOrchidOrmArgs = (importName, statements) => {
3667
- for (const v of statements) {
3668
- if (v.kind !== SyntaxKind.VariableStatement) continue;
3669
- for (const node of v.declarationList.declarations) {
3670
- const call = node.initializer;
3671
- if (call?.kind !== SyntaxKind.CallExpression) continue;
3672
- if (call.expression.getText() !== importName) continue;
3673
- if (call.arguments.length !== 2) throw new Error("Invalid number of arguments when initializing orchid orm");
3674
- const object = call.arguments[1];
3675
- if (object?.kind !== SyntaxKind.ObjectLiteralExpression) throw new Error("Second argument of orchidORM must be an object literal");
3676
- return {
3677
- config: call.arguments[0],
3678
- tablesList: object
3679
- };
3683
+ const getOrchidOrmArgs = (content, importName) => {
3684
+ const call = findCall(content, importName);
3685
+ if (!call) throw new Error("List of tables is not found in main file");
3686
+ const closeParen = findClosingBracket(content, call.openParen);
3687
+ if (closeParen === -1) throw new Error("List of tables is not found in main file");
3688
+ const firstComma = findTopLevelComma(content, call.openParen + 1, closeParen);
3689
+ if (firstComma === -1) throw new Error("Invalid number of arguments when initializing orchid orm");
3690
+ if (findTopLevelComma(content, firstComma + 1, closeParen) !== -1) throw new Error("Invalid number of arguments when initializing orchid orm");
3691
+ const config = makeTrimmedRange(content, call.openParen + 1, firstComma);
3692
+ const tablesList = getObjectRange(content, firstComma + 1, closeParen);
3693
+ if (!tablesList) throw new Error("Second argument of orchidORM must be an object literal");
3694
+ return {
3695
+ config,
3696
+ tablesList
3697
+ };
3698
+ };
3699
+ const getOrchidOrmImport = (content) => {
3700
+ let lastImportEnd = 0;
3701
+ let importName;
3702
+ const importRegex = /(^|\n)\s*import\s+([\s\S]*?)\s+from\s+['"]([^'"]+)['"]\s*;?/g;
3703
+ let match;
3704
+ while (match = importRegex.exec(content)) {
3705
+ lastImportEnd = importRegex.lastIndex;
3706
+ if (match[3] !== "orchid-orm") continue;
3707
+ const named = match[2].match(/\{([\s\S]*)\}/);
3708
+ if (!named) continue;
3709
+ for (const part of named[1].split(",")) {
3710
+ const item = part.trim();
3711
+ const alias = item.match(/^orchidORM\s+as\s+([A-Za-z_$][\w$]*)$/);
3712
+ if (alias) {
3713
+ importName = alias[1];
3714
+ continue;
3715
+ }
3716
+ if (item === "orchidORM") importName = "orchidORM";
3680
3717
  }
3681
3718
  }
3719
+ if (!importName) return;
3720
+ return {
3721
+ importName,
3722
+ lastImportEnd
3723
+ };
3724
+ };
3725
+ const findCall = (content, importName) => {
3726
+ let index = 0;
3727
+ while (index < content.length) {
3728
+ const found = content.indexOf(importName, index);
3729
+ if (found === -1) return;
3730
+ const before = content[found - 1];
3731
+ const after = content[found + importName.length];
3732
+ if ((!before || !isIdentifierChar(before)) && (!after || !isIdentifierChar(after))) {
3733
+ const openParen = skipWhitespace(content, found + importName.length);
3734
+ if (content[openParen] === "(") return { openParen };
3735
+ }
3736
+ index = found + importName.length;
3737
+ }
3682
3738
  throw new Error("List of tables is not found in main file");
3683
3739
  };
3740
+ const getObjectRange = (content, from, to) => {
3741
+ const pos = skipWhitespace(content, from);
3742
+ if (content[pos] !== "{") return;
3743
+ const end = findClosingBracket(content, pos);
3744
+ if (end === -1 || skipWhitespace(content, end + 1) < to) return;
3745
+ const lastBodyChar = findLastNonWhitespace(content, pos + 1, end);
3746
+ const hasProperties = lastBodyChar !== -1;
3747
+ const hasTrailingComma = hasProperties && content[lastBodyChar] === ",";
3748
+ const propertiesEnd = hasProperties ? lastBodyChar + 1 : pos + 1;
3749
+ return {
3750
+ pos,
3751
+ end: end + 1,
3752
+ propertiesEnd,
3753
+ hasProperties,
3754
+ hasTrailingComma
3755
+ };
3756
+ };
3757
+ const makeTrimmedRange = (content, from, to) => {
3758
+ return {
3759
+ pos: skipWhitespace(content, from),
3760
+ end: trimWhitespaceEnd(content, from, to)
3761
+ };
3762
+ };
3763
+ const findTopLevelComma = (content, from, to) => {
3764
+ let depth = 0;
3765
+ for (let i = from; i < to; i++) {
3766
+ const skipped = skipCodeFragment(content, i);
3767
+ if (skipped !== i) {
3768
+ i = skipped - 1;
3769
+ continue;
3770
+ }
3771
+ const char = content[i];
3772
+ if (char === "(" || char === "{" || char === "[") depth++;
3773
+ else if (char === ")" || char === "}" || char === "]") depth--;
3774
+ else if (char === "," && depth === 0) return i;
3775
+ }
3776
+ return -1;
3777
+ };
3778
+ const findClosingBracket = (content, open) => {
3779
+ const close = getClosingBracket(content[open]);
3780
+ if (!close) return -1;
3781
+ let depth = 1;
3782
+ for (let i = open + 1; i < content.length; i++) {
3783
+ const skipped = skipCodeFragment(content, i);
3784
+ if (skipped !== i) {
3785
+ i = skipped - 1;
3786
+ continue;
3787
+ }
3788
+ const char = content[i];
3789
+ if (char === content[open]) depth++;
3790
+ else if (char === close) {
3791
+ depth--;
3792
+ if (depth === 0) return i;
3793
+ }
3794
+ }
3795
+ return -1;
3796
+ };
3797
+ const getClosingBracket = (char) => {
3798
+ if (char === "(") return ")";
3799
+ if (char === "{") return "}";
3800
+ if (char === "[") return "]";
3801
+ };
3802
+ const skipCodeFragment = (content, i) => {
3803
+ const char = content[i];
3804
+ if (char === "'" || char === "\"" || char === "`") return skipQuoted(content, i, char);
3805
+ if (char === "/" && content[i + 1] === "/") {
3806
+ const nextLine = content.indexOf("\n", i + 2);
3807
+ return nextLine === -1 ? content.length : nextLine + 1;
3808
+ }
3809
+ if (char === "/" && content[i + 1] === "*") {
3810
+ const end = content.indexOf("*/", i + 2);
3811
+ return end === -1 ? content.length : end + 2;
3812
+ }
3813
+ return i;
3814
+ };
3815
+ const skipQuoted = (content, i, quote) => {
3816
+ for (let j = i + 1; j < content.length; j++) {
3817
+ if (content[j] === "\\") {
3818
+ j++;
3819
+ continue;
3820
+ }
3821
+ if (content[j] === quote) return j + 1;
3822
+ }
3823
+ return content.length;
3824
+ };
3825
+ const skipWhitespace = (content, from) => {
3826
+ let i = from;
3827
+ while (/\s/.test(content[i])) i++;
3828
+ return i;
3829
+ };
3830
+ const trimWhitespaceEnd = (content, from, to) => {
3831
+ let i = to;
3832
+ while (i > from && /\s/.test(content[i - 1])) i--;
3833
+ return i;
3834
+ };
3835
+ const findLastNonWhitespace = (content, from, to) => {
3836
+ for (let i = to - 1; i >= from; i--) if (!/\s/.test(content[i])) return i;
3837
+ return -1;
3838
+ };
3839
+ const isIdentifierChar = (char) => {
3840
+ return /[A-Za-z0-9_$]/.test(char);
3841
+ };
3684
3842
  const addChange = (content, changes, at, text, end = at) => {
3685
3843
  if (changes.length === 0) changes.push([0, at], text, [end, content.length]);
3686
3844
  else {
@@ -3696,14 +3854,21 @@ const applyChanges = (content, changes) => {
3696
3854
  return changes.length ? changes.map((item) => typeof item === "string" ? item : content.slice(item[0], item[1])).join("") : content;
3697
3855
  };
3698
3856
  const pull = async (adapters, config) => {
3699
- if (!config.dbPath || !config.baseTable) throw new Error(`\`${config.dbPath ? "baseTable" : "dbPath"}\` setting must be set in the migrations config for pull command`);
3700
- const baseTablePath = config.baseTable.getFilePath();
3701
- const baseTableExportedAs = config.baseTable.exportAs;
3857
+ const { defineTable } = config;
3858
+ if (!config.dbPath || !defineTable) throw new Error(`\`${config.dbPath ? "defineTable" : "dbPath"}\` setting must be set in the migrations config for pull command`);
3859
+ if (!defineTable.types) throw new Error("defineTable is missing types");
3860
+ if (!defineTable.exportAs) throw new Error("defineTable is missing exportAs");
3861
+ if (typeof defineTable.getFilePath !== "function") throw new Error("defineTable is missing getFilePath");
3862
+ const tableFactorySource = {
3863
+ path: defineTable.getFilePath(),
3864
+ exportedAs: defineTable.exportAs
3865
+ };
3702
3866
  const [adapter] = adapters;
3703
3867
  const adapterSchema = adapter.getSchema();
3704
3868
  const currentSchema = (typeof adapterSchema === "function" ? adapterSchema() : adapterSchema) ?? "public";
3705
- const asts = await (0, rake_db.structureToAst)((0, rake_db.makeStructureToAstCtx)(config, currentSchema), adapter, config);
3706
- const { tableInfos, fkeys } = getTableInfosAndFKeys(asts, config);
3869
+ const ctx = (0, rake_db.makeStructureToAstCtx)(config, currentSchema);
3870
+ const asts = await (0, rake_db.structureToAst)(ctx, adapter, config);
3871
+ const tableInfos = getTableInfos(asts, config);
3707
3872
  const exclusiveWriteOptions = { flag: "wx" };
3708
3873
  const pendingFileWrites = [];
3709
3874
  const tables = {};
@@ -3712,7 +3877,7 @@ const pull = async (adapters, config) => {
3712
3877
  let firstTable;
3713
3878
  for (const ast of asts) switch (ast.type) {
3714
3879
  case "table": {
3715
- const table = appCodeGenTable(tableInfos, fkeys, ast, baseTablePath, baseTableExportedAs, currentSchema);
3880
+ const table = appCodeGenTable(tableInfos, ast, tableFactorySource, currentSchema);
3716
3881
  tables[table.key] = table;
3717
3882
  if (!firstTable) firstTable = table;
3718
3883
  pendingFileWrites.push([
@@ -3728,9 +3893,7 @@ const pull = async (adapters, config) => {
3728
3893
  version: ast.version
3729
3894
  });
3730
3895
  break;
3731
- case "domain":
3732
- domains.push(ast);
3733
- break;
3896
+ case "domain": domains.push(ast);
3734
3897
  }
3735
3898
  if (!firstTable && !extensions.length && !domains.length) {
3736
3899
  await adapter.close();