orchid-orm 1.76.4 → 1.77.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.
@@ -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)({
@@ -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,84 +3507,119 @@ 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");
@@ -3696,14 +3731,20 @@ const applyChanges = (content, changes) => {
3696
3731
  return changes.length ? changes.map((item) => typeof item === "string" ? item : content.slice(item[0], item[1])).join("") : content;
3697
3732
  };
3698
3733
  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;
3734
+ const { defineTable } = config;
3735
+ if (!config.dbPath || !defineTable) throw new Error(`\`${config.dbPath ? "defineTable" : "dbPath"}\` setting must be set in the migrations config for pull command`);
3736
+ if (!defineTable.types) throw new Error("defineTable is missing types");
3737
+ if (!defineTable.exportAs) throw new Error("defineTable is missing exportAs");
3738
+ if (typeof defineTable.getFilePath !== "function") throw new Error("defineTable is missing getFilePath");
3739
+ const tableFactorySource = {
3740
+ path: defineTable.getFilePath(),
3741
+ exportedAs: defineTable.exportAs
3742
+ };
3702
3743
  const [adapter] = adapters;
3703
3744
  const adapterSchema = adapter.getSchema();
3704
3745
  const currentSchema = (typeof adapterSchema === "function" ? adapterSchema() : adapterSchema) ?? "public";
3705
3746
  const asts = await (0, rake_db.structureToAst)((0, rake_db.makeStructureToAstCtx)(config, currentSchema), adapter, config);
3706
- const { tableInfos, fkeys } = getTableInfosAndFKeys(asts, config);
3747
+ const tableInfos = getTableInfos(asts, config);
3707
3748
  const exclusiveWriteOptions = { flag: "wx" };
3708
3749
  const pendingFileWrites = [];
3709
3750
  const tables = {};
@@ -3712,7 +3753,7 @@ const pull = async (adapters, config) => {
3712
3753
  let firstTable;
3713
3754
  for (const ast of asts) switch (ast.type) {
3714
3755
  case "table": {
3715
- const table = appCodeGenTable(tableInfos, fkeys, ast, baseTablePath, baseTableExportedAs, currentSchema);
3756
+ const table = appCodeGenTable(tableInfos, ast, tableFactorySource, currentSchema);
3716
3757
  tables[table.key] = table;
3717
3758
  if (!firstTable) firstTable = table;
3718
3759
  pendingFileWrites.push([