arkormx 2.10.2 → 2.11.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.
- package/dist/cli.mjs +474 -17
- package/dist/{index-CGawfwb8.d.cts → index-43R9yWVX.d.mts} +546 -9
- package/dist/{index-ClVzjhGq.d.mts → index-DLNIbeRi.d.cts} +546 -9
- package/dist/index.cjs +630 -58
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +611 -59
- package/dist/relationship/index.cjs +1 -1
- package/dist/relationship/index.d.cts +1 -1
- package/dist/relationship/index.d.mts +1 -1
- package/dist/relationship/index.mjs +1 -1
- package/dist/{relationship-SFhKrphd.mjs → relationship-CP1xbMOa.mjs} +448 -1
- package/dist/{relationship-DWtfgLfh.cjs → relationship-IC-TAFyG.cjs} +567 -0
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_relationship = require('./relationship-
|
|
2
|
+
const require_relationship = require('./relationship-IC-TAFyG.cjs');
|
|
3
3
|
let pg = require("pg");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
let module$1 = require("module");
|
|
@@ -65,7 +65,8 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
65
65
|
rawWhere: true,
|
|
66
66
|
distinct: true,
|
|
67
67
|
groupBy: true,
|
|
68
|
-
joins: true
|
|
68
|
+
joins: true,
|
|
69
|
+
expressions: true
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
resolveConfiguredDatabaseName(connectionString) {
|
|
@@ -386,6 +387,13 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
386
387
|
}
|
|
387
388
|
buildSchemaColumnDefinition(table, column) {
|
|
388
389
|
const parts = [this.quoteIdentifier(column.map ?? column.name), this.resolveSchemaColumnType(table, column)];
|
|
390
|
+
if (column.generatedExpression) {
|
|
391
|
+
const storage = column.generatedStored === false ? "" : " stored";
|
|
392
|
+
parts.push(`generated always as (${column.generatedExpression})${storage}`);
|
|
393
|
+
if (column.unique) parts.push("unique");
|
|
394
|
+
if (!column.nullable && !column.primary) parts.push("not null");
|
|
395
|
+
return parts.join(" ");
|
|
396
|
+
}
|
|
389
397
|
if (this.shouldUseIdentity(column)) parts.push("generated by default as identity");
|
|
390
398
|
const defaultValue = this.resolveSchemaColumnDefault(column);
|
|
391
399
|
if (defaultValue && !this.shouldUseIdentity(column)) parts.push(`default ${defaultValue}`);
|
|
@@ -643,11 +651,16 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
643
651
|
}
|
|
644
652
|
buildSelectList(target, columns) {
|
|
645
653
|
if (!columns || columns.length === 0) return kysely.sql.raw("*");
|
|
646
|
-
return kysely.sql.join(columns.map(({ column, alias, raw, wildcard }) => {
|
|
654
|
+
return kysely.sql.join(columns.map(({ column, alias, raw, wildcard, expression }) => {
|
|
647
655
|
if (wildcard) return kysely.sql.raw("*");
|
|
656
|
+
if (expression) {
|
|
657
|
+
const compiled = this.buildExpression(target, expression);
|
|
658
|
+
const resultAlias = alias ?? column;
|
|
659
|
+
return resultAlias ? kysely.sql`${compiled} as ${kysely.sql.id(resultAlias)}` : compiled;
|
|
660
|
+
}
|
|
648
661
|
if (raw) {
|
|
649
|
-
const
|
|
650
|
-
return alias ? kysely.sql`${
|
|
662
|
+
const rawExpression = kysely.sql.raw(column);
|
|
663
|
+
return alias ? kysely.sql`${rawExpression} as ${kysely.sql.id(alias)}` : rawExpression;
|
|
651
664
|
}
|
|
652
665
|
const mappedColumn = this.mapColumn(target, column);
|
|
653
666
|
const resultAlias = alias ?? column;
|
|
@@ -657,13 +670,18 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
657
670
|
}
|
|
658
671
|
buildOrderBy(target, orderBy) {
|
|
659
672
|
if (!orderBy || orderBy.length === 0) return kysely.sql``;
|
|
660
|
-
return kysely.sql` order by ${kysely.sql.join(orderBy.map(({ column, direction }) => {
|
|
661
|
-
return kysely.sql`${kysely.sql.ref(this.mapColumn(target, column))} ${kysely.sql.raw(direction === "desc" ? "desc" : "asc")}`;
|
|
673
|
+
return kysely.sql` order by ${kysely.sql.join(orderBy.map(({ column, direction, expression }) => {
|
|
674
|
+
return kysely.sql`${expression ? this.buildExpression(target, expression) : kysely.sql.ref(this.mapColumn(target, column))} ${kysely.sql.raw(direction === "desc" ? "desc" : "asc")}`;
|
|
662
675
|
}), kysely.sql`, `)}`;
|
|
663
676
|
}
|
|
664
677
|
buildGroupBy(target, groupBy) {
|
|
665
678
|
if (!groupBy || groupBy.length === 0) return kysely.sql``;
|
|
666
|
-
return kysely.sql` group by ${kysely.sql.join(groupBy.map((
|
|
679
|
+
return kysely.sql` group by ${kysely.sql.join(groupBy.map((item) => {
|
|
680
|
+
if (typeof item === "string") return kysely.sql.ref(this.mapColumn(target, item));
|
|
681
|
+
if ("alias" in item) return kysely.sql.ref(item.alias);
|
|
682
|
+
if ("expression" in item) return this.buildExpression(target, item.expression);
|
|
683
|
+
return this.buildRawExpressionFragment(item.raw.sql, item.raw.bindings ?? []);
|
|
684
|
+
}), kysely.sql`, `)}`;
|
|
667
685
|
}
|
|
668
686
|
buildHavingClause(target, having) {
|
|
669
687
|
if (!having) return kysely.sql``;
|
|
@@ -812,6 +830,96 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
812
830
|
const contains = kysely.sql`${accessor} @> ${jsonValue}::jsonb`;
|
|
813
831
|
return condition.not ? kysely.sql`not (${contains})` : contains;
|
|
814
832
|
}
|
|
833
|
+
/**
|
|
834
|
+
* Compiles a serialized {@link ExpressionNode} into a parameterized SQL fragment.
|
|
835
|
+
* Shared by expression-backed select columns, `group by`, `order by`, and any
|
|
836
|
+
* boolean expression used as a `where`/`having` predicate.
|
|
837
|
+
*
|
|
838
|
+
* @param target
|
|
839
|
+
* @param node
|
|
840
|
+
* @returns
|
|
841
|
+
*/
|
|
842
|
+
buildExpression(target, node) {
|
|
843
|
+
switch (node.kind) {
|
|
844
|
+
case "column": return this.buildExpressionColumn(target, node.name);
|
|
845
|
+
case "value": return kysely.sql`${node.value}`;
|
|
846
|
+
case "raw": return this.buildRawExpressionFragment(node.sql, node.bindings);
|
|
847
|
+
case "json": return this.buildJsonValueExpression(target, node);
|
|
848
|
+
case "function": {
|
|
849
|
+
const args = node.args.map((arg) => this.buildExpression(target, arg));
|
|
850
|
+
return kysely.sql`${kysely.sql.raw(this.sanitizeFunctionName(node.name))}(${kysely.sql.join(args, kysely.sql`, `)})`;
|
|
851
|
+
}
|
|
852
|
+
case "case": {
|
|
853
|
+
const branches = node.cases.map((branch) => kysely.sql`when ${this.buildExpression(target, branch.when)} then ${this.buildExpression(target, branch.then)}`);
|
|
854
|
+
const elseClause = node.else ? kysely.sql` else ${this.buildExpression(target, node.else)}` : kysely.sql``;
|
|
855
|
+
return kysely.sql`case ${kysely.sql.join(branches, kysely.sql` `)}${elseClause} end`;
|
|
856
|
+
}
|
|
857
|
+
case "binary": return this.buildBinaryExpression(target, node);
|
|
858
|
+
case "in": {
|
|
859
|
+
const operand = this.buildExpression(target, node.operand);
|
|
860
|
+
const values = node.values.map((value) => this.buildExpression(target, value));
|
|
861
|
+
const list = values.length > 0 ? kysely.sql.join(values, kysely.sql`, `) : kysely.sql`null`;
|
|
862
|
+
return node.not ? kysely.sql`(${operand} not in (${list}))` : kysely.sql`(${operand} in (${list}))`;
|
|
863
|
+
}
|
|
864
|
+
case "null-check": {
|
|
865
|
+
const operand = this.buildExpression(target, node.operand);
|
|
866
|
+
return node.not ? kysely.sql`(${operand} is not null)` : kysely.sql`(${operand} is null)`;
|
|
867
|
+
}
|
|
868
|
+
case "aggregate": return this.buildAggregateExpression(target, node);
|
|
869
|
+
default: throw new require_relationship.ArkormException(`Unsupported expression node [${node.kind}].`);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
buildExpressionColumn(target, name) {
|
|
873
|
+
if (name.includes(".")) return kysely.sql.ref(name);
|
|
874
|
+
return kysely.sql.ref(this.mapColumn(target, name));
|
|
875
|
+
}
|
|
876
|
+
buildBinaryExpression(target, node) {
|
|
877
|
+
const left = this.buildExpression(target, node.left);
|
|
878
|
+
const right = this.buildExpression(target, node.right);
|
|
879
|
+
switch (node.operator) {
|
|
880
|
+
case "like": return kysely.sql`(${left} like ${right})`;
|
|
881
|
+
case "ilike": return kysely.sql`(${left} ilike ${right})`;
|
|
882
|
+
case "not-like": return kysely.sql`(${left} not like ${right})`;
|
|
883
|
+
case "not-ilike": return kysely.sql`(${left} not ilike ${right})`;
|
|
884
|
+
case "and": return kysely.sql`(${left} and ${right})`;
|
|
885
|
+
case "or": return kysely.sql`(${left} or ${right})`;
|
|
886
|
+
default: return kysely.sql`(${left} ${kysely.sql.raw(node.operator)} ${right})`;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
buildAggregateExpression(target, node) {
|
|
890
|
+
const argument = node.arg ? this.buildExpression(target, node.arg) : kysely.sql.raw("*");
|
|
891
|
+
const distinctKeyword = node.distinct ? kysely.sql`distinct ` : kysely.sql``;
|
|
892
|
+
let call = kysely.sql`${kysely.sql.raw(node.fn)}(${distinctKeyword}${argument})`;
|
|
893
|
+
if (node.filter) call = kysely.sql`${call} filter (where ${this.buildExpression(target, node.filter)})`;
|
|
894
|
+
if (node.fn === "sum" || node.fn === "avg") return kysely.sql`(${call})::double precision`;
|
|
895
|
+
if (node.fn === "count") return kysely.sql`(${call})::bigint`;
|
|
896
|
+
return call;
|
|
897
|
+
}
|
|
898
|
+
buildJsonValueExpression(target, node) {
|
|
899
|
+
const base = kysely.sql`${kysely.sql.ref(this.mapColumn(target, node.column))}::jsonb`;
|
|
900
|
+
let accessor;
|
|
901
|
+
if (node.path.length === 0) accessor = base;
|
|
902
|
+
else if (node.path.length === 1) accessor = kysely.sql`(${base} ->> ${node.path[0]})`;
|
|
903
|
+
else accessor = kysely.sql`(${base} #>> ${`{${node.path.join(",")}}`}::text[])`;
|
|
904
|
+
if (node.cast === "number") return kysely.sql`(${accessor})::numeric`;
|
|
905
|
+
if (node.cast === "boolean") return kysely.sql`(${accessor})::boolean`;
|
|
906
|
+
return accessor;
|
|
907
|
+
}
|
|
908
|
+
buildRawExpressionFragment(rawSql, bindings) {
|
|
909
|
+
const segments = rawSql.split("?");
|
|
910
|
+
if (segments.length !== bindings.length + 1) throw new require_relationship.ArkormException("Raw expression bindings do not match the number of placeholders.");
|
|
911
|
+
const parts = [];
|
|
912
|
+
segments.forEach((segment, index) => {
|
|
913
|
+
if (segment.length > 0) parts.push(kysely.sql.raw(this.quoteCamelCaseIdentifiers(segment)));
|
|
914
|
+
if (index < bindings.length) parts.push(kysely.sql`${bindings[index]}`);
|
|
915
|
+
});
|
|
916
|
+
if (parts.length === 0) return kysely.sql``;
|
|
917
|
+
return kysely.sql`${kysely.sql.join(parts, kysely.sql``)}`;
|
|
918
|
+
}
|
|
919
|
+
sanitizeFunctionName(name) {
|
|
920
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_.]*$/.test(name)) throw new require_relationship.ArkormException(`Unsupported SQL function name [${name}].`);
|
|
921
|
+
return name;
|
|
922
|
+
}
|
|
815
923
|
buildWhereCondition(target, condition) {
|
|
816
924
|
if (!condition) return kysely.sql`1 = 1`;
|
|
817
925
|
if (condition.type === "comparison") return this.buildComparisonCondition(target, condition);
|
|
@@ -821,6 +929,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
|
|
|
821
929
|
if (condition.type === "exists") return this.buildExistsCondition(condition);
|
|
822
930
|
if (condition.type === "full-text") return this.buildFullTextCondition(target, condition);
|
|
823
931
|
if (condition.type === "json") return this.buildJsonCondition(target, condition);
|
|
932
|
+
if (condition.type === "expression") return kysely.sql`${this.buildExpression(target, condition.expression)}`;
|
|
824
933
|
if (condition.type === "group") {
|
|
825
934
|
const group = condition;
|
|
826
935
|
const conditions = group.conditions.map((entry) => {
|
|
@@ -1693,6 +1802,7 @@ var PrismaDatabaseAdapter = class PrismaDatabaseAdapter {
|
|
|
1693
1802
|
rawWhere: false,
|
|
1694
1803
|
distinct: false,
|
|
1695
1804
|
groupBy: false,
|
|
1805
|
+
expressions: false,
|
|
1696
1806
|
returning: false
|
|
1697
1807
|
};
|
|
1698
1808
|
}
|
|
@@ -1728,6 +1838,14 @@ var PrismaDatabaseAdapter = class PrismaDatabaseAdapter {
|
|
|
1728
1838
|
}
|
|
1729
1839
|
toQuerySelect(columns) {
|
|
1730
1840
|
if (!columns || columns.length === 0) return void 0;
|
|
1841
|
+
const expressionColumn = columns.find((column) => column.expression);
|
|
1842
|
+
if (expressionColumn) throw new require_relationship.UnsupportedAdapterFeatureException("Expression select columns are not supported by the Prisma compatibility adapter; use a SQL-backed adapter.", {
|
|
1843
|
+
operation: "adapter.select",
|
|
1844
|
+
meta: {
|
|
1845
|
+
feature: "expressions",
|
|
1846
|
+
alias: expressionColumn.alias
|
|
1847
|
+
}
|
|
1848
|
+
});
|
|
1731
1849
|
const rawColumn = columns.find((column) => column.raw);
|
|
1732
1850
|
if (rawColumn) throw new require_relationship.UnsupportedAdapterFeatureException("Raw select expressions are not supported by the Prisma compatibility adapter; use a SQL-backed adapter or DB.raw().", {
|
|
1733
1851
|
operation: "adapter.select",
|
|
@@ -1745,6 +1863,10 @@ var PrismaDatabaseAdapter = class PrismaDatabaseAdapter {
|
|
|
1745
1863
|
}
|
|
1746
1864
|
toQueryOrderBy(orderBy) {
|
|
1747
1865
|
if (!orderBy || orderBy.length === 0) return void 0;
|
|
1866
|
+
if (orderBy.some((entry) => entry.expression)) throw new require_relationship.UnsupportedAdapterFeatureException("Order-by expressions are not supported by the Prisma compatibility adapter; use a SQL-backed adapter.", {
|
|
1867
|
+
operation: "adapter.select",
|
|
1868
|
+
meta: { feature: "expressions" }
|
|
1869
|
+
});
|
|
1748
1870
|
return orderBy.map((entry) => ({ [entry.column]: entry.direction }));
|
|
1749
1871
|
}
|
|
1750
1872
|
toComparisonWhere(condition) {
|
|
@@ -3388,7 +3510,8 @@ var Migration = class {
|
|
|
3388
3510
|
//#region src/cli/commands/MigrateCommand.ts
|
|
3389
3511
|
/**
|
|
3390
3512
|
* The MigrateCommand class implements the CLI command for applying migration
|
|
3391
|
-
* classes to the Prisma schema and running the Prisma workflow
|
|
3513
|
+
* classes to the database or Prisma schema and running the Prisma workflow when
|
|
3514
|
+
* using the Prisma compatibility driver.
|
|
3392
3515
|
*
|
|
3393
3516
|
* @author Legacy (3m1n3nc3)
|
|
3394
3517
|
* @since 0.1.0
|
|
@@ -3399,22 +3522,22 @@ var MigrateCommand = class extends _h3ravel_musket.Command {
|
|
|
3399
3522
|
this.signature = `migrate
|
|
3400
3523
|
{name? : Migration class or file name}
|
|
3401
3524
|
{--all : Run all migrations from the configured migrations directory}
|
|
3402
|
-
{--deploy : Use prisma migrate deploy instead of migrate dev}
|
|
3403
|
-
{--skip-generate : Skip prisma generate}
|
|
3525
|
+
{--deploy : Use prisma migrate deploy instead of migrate dev (Prisma compatibility driver only)}
|
|
3526
|
+
{--skip-generate : Skip prisma generate (Prisma compatibility driver only)}
|
|
3404
3527
|
{--skip-migrate : Skip prisma migrate command}
|
|
3405
3528
|
{--state-file= : Path to applied migration state file}
|
|
3406
|
-
{--schema= : Explicit prisma schema path}
|
|
3407
|
-
{--migration-name= : Name for prisma migrate dev}
|
|
3529
|
+
{--schema= : Explicit prisma schema path (Prisma compatibility driver only)}
|
|
3530
|
+
{--migration-name= : Name for prisma migrate dev (Prisma compatibility driver only)}
|
|
3408
3531
|
{--create-database : Create the configured database without prompting}
|
|
3409
3532
|
`;
|
|
3410
|
-
this.description = "Apply migration classes to schema.prisma and run Prisma workflow";
|
|
3533
|
+
this.description = "Apply migration classes to the database or schema.prisma and run Prisma workflow when using the Prisma compatibility driver";
|
|
3411
3534
|
}
|
|
3412
3535
|
/**
|
|
3413
3536
|
* Command handler for the migrate command.
|
|
3414
3537
|
* This method is responsible for orchestrating the migration
|
|
3415
3538
|
* process, including loading migration classes, applying them to
|
|
3416
|
-
* the Prisma schema, and running the appropriate Prisma commands
|
|
3417
|
-
* based on the provided options.
|
|
3539
|
+
* the the database or Prisma schema, and running the appropriate Prisma commands
|
|
3540
|
+
* when using the Prisma compatibility driver based on the provided options.
|
|
3418
3541
|
*
|
|
3419
3542
|
* @returns
|
|
3420
3543
|
*/
|
|
@@ -3623,10 +3746,10 @@ var MigrateFreshCommand = class extends _h3ravel_musket.Command {
|
|
|
3623
3746
|
constructor(..._args) {
|
|
3624
3747
|
super(..._args);
|
|
3625
3748
|
this.signature = `migrate:fresh
|
|
3626
|
-
{--skip-generate : Skip prisma generate}
|
|
3627
|
-
{--skip-migrate : Skip prisma database sync}
|
|
3749
|
+
{--skip-generate : Skip prisma generate (Prisma compatibility driver only)}
|
|
3750
|
+
{--skip-migrate : Skip prisma database sync (Prisma compatibility driver only)}
|
|
3628
3751
|
{--state-file= : Path to applied migration state file}
|
|
3629
|
-
{--schema= : Explicit prisma schema path}
|
|
3752
|
+
{--schema= : Explicit prisma schema path (Prisma compatibility driver only)}
|
|
3630
3753
|
{--create-database : Create the configured database without prompting}
|
|
3631
3754
|
`;
|
|
3632
3755
|
this.description = "Reset the database and rerun all migration classes";
|
|
@@ -3781,12 +3904,12 @@ var MigrateRollbackCommand = class extends _h3ravel_musket.Command {
|
|
|
3781
3904
|
this.signature = `migrate:rollback
|
|
3782
3905
|
{--step= : Number of latest applied migration classes to rollback}
|
|
3783
3906
|
{--dry-run : Preview rollback targets without applying changes}
|
|
3784
|
-
{--deploy : Use prisma migrate deploy instead of migrate dev}
|
|
3785
|
-
{--skip-generate : Skip prisma generate}
|
|
3786
|
-
{--skip-migrate : Skip prisma migrate command}
|
|
3907
|
+
{--deploy : Use prisma migrate deploy instead of migrate dev (Prisma compatibility driver only)}
|
|
3908
|
+
{--skip-generate : Skip prisma generate (Prisma compatibility driver only)}
|
|
3909
|
+
{--skip-migrate : Skip prisma migrate command (Prisma compatibility driver only)}
|
|
3787
3910
|
{--state-file= : Path to applied migration state file}
|
|
3788
|
-
{--schema= : Explicit prisma schema path}
|
|
3789
|
-
{--migration-name= : Name for prisma migrate dev}
|
|
3911
|
+
{--schema= : Explicit prisma schema path (Prisma compatibility driver only)}
|
|
3912
|
+
{--migration-name= : Name for prisma migrate dev (Prisma compatibility driver only)}
|
|
3790
3913
|
`;
|
|
3791
3914
|
this.description = "Rollback migration classes from schema.prisma and run Prisma workflow";
|
|
3792
3915
|
}
|
|
@@ -3801,7 +3924,7 @@ var MigrateRollbackCommand = class extends _h3ravel_musket.Command {
|
|
|
3801
3924
|
const useDatabaseMigrations = require_relationship.supportsDatabaseMigrationExecution(adapter);
|
|
3802
3925
|
const persistedFeatures = require_relationship.resolvePersistedMetadataFeatures(this.app.getConfig("features"));
|
|
3803
3926
|
let appliedState = await require_relationship.readAppliedMigrationsStateFromStore(adapter, stateFilePath);
|
|
3804
|
-
const stepOption = this.option("step");
|
|
3927
|
+
const stepOption = this.option("step", 1);
|
|
3805
3928
|
const stepCount = stepOption == null ? void 0 : Number(stepOption);
|
|
3806
3929
|
if (stepCount != null && (!Number.isFinite(stepCount) || stepCount <= 0 || !Number.isInteger(stepCount))) return void this.error("Error: --step must be a positive integer.");
|
|
3807
3930
|
const targets = stepCount ? require_relationship.getLatestAppliedMigrations(appliedState, stepCount) : (() => {
|
|
@@ -4476,14 +4599,34 @@ var QueryBuilder = class QueryBuilder {
|
|
|
4476
4599
|
return Math.max(1, resolvedPage);
|
|
4477
4600
|
}
|
|
4478
4601
|
where(whereOrCallback) {
|
|
4602
|
+
if (whereOrCallback instanceof require_relationship.Expression) return this.appendExpressionCondition("AND", whereOrCallback);
|
|
4479
4603
|
if (typeof whereOrCallback === "function") return this.appendNestedWhere("AND", whereOrCallback);
|
|
4480
4604
|
return this.addLogicalWhere("AND", whereOrCallback);
|
|
4481
4605
|
}
|
|
4482
4606
|
orWhere(whereOrCallback) {
|
|
4607
|
+
if (whereOrCallback instanceof require_relationship.Expression) return this.appendExpressionCondition("OR", whereOrCallback);
|
|
4483
4608
|
if (typeof whereOrCallback === "function") return this.appendNestedWhere("OR", whereOrCallback);
|
|
4484
4609
|
return this.addLogicalWhere("OR", whereOrCallback);
|
|
4485
4610
|
}
|
|
4486
4611
|
/**
|
|
4612
|
+
* Appends a boolean {@link Expression} as a where predicate. When the query is
|
|
4613
|
+
* using the Prisma-like legacy where representation, the expression is merged in
|
|
4614
|
+
* as a structured condition alongside it.
|
|
4615
|
+
*/
|
|
4616
|
+
appendExpressionCondition(boolean, expression) {
|
|
4617
|
+
const condition = {
|
|
4618
|
+
type: "expression",
|
|
4619
|
+
expression: expression.toExpressionNode()
|
|
4620
|
+
};
|
|
4621
|
+
if (this.legacyWhere) {
|
|
4622
|
+
const existing = this.tryBuildQueryCondition(this.legacyWhere);
|
|
4623
|
+
this.legacyWhere = void 0;
|
|
4624
|
+
if (existing) this.queryWhere = existing;
|
|
4625
|
+
}
|
|
4626
|
+
this.appendQueryCondition(boolean, condition);
|
|
4627
|
+
return this;
|
|
4628
|
+
}
|
|
4629
|
+
/**
|
|
4487
4630
|
* Resolve a callback into a parenthesized group condition and append it.
|
|
4488
4631
|
*/
|
|
4489
4632
|
appendNestedWhere(boolean, callback) {
|
|
@@ -5133,15 +5276,17 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5133
5276
|
whereIn(key, values) {
|
|
5134
5277
|
return this.where({ [key]: { in: values } });
|
|
5135
5278
|
}
|
|
5136
|
-
|
|
5137
|
-
* Adds an orderBy clause to the query. This will overwrite any existing orderBy clause.
|
|
5138
|
-
*
|
|
5139
|
-
* @param orderBy
|
|
5140
|
-
* @returns
|
|
5141
|
-
*/
|
|
5142
|
-
orderBy(orderBy) {
|
|
5279
|
+
orderBy(orderByOrExpression, direction = "asc") {
|
|
5143
5280
|
this.randomOrderEnabled = false;
|
|
5144
|
-
|
|
5281
|
+
if (orderByOrExpression instanceof require_relationship.Expression) {
|
|
5282
|
+
this.queryOrderBy = [...this.queryOrderBy ?? [], {
|
|
5283
|
+
column: "",
|
|
5284
|
+
direction,
|
|
5285
|
+
expression: orderByOrExpression.toExpressionNode()
|
|
5286
|
+
}];
|
|
5287
|
+
return this;
|
|
5288
|
+
}
|
|
5289
|
+
const normalized = this.normalizeQueryOrderBy(orderByOrExpression);
|
|
5145
5290
|
if (!normalized) throw new require_relationship.UnsupportedAdapterFeatureException("Order clauses must use Arkorm-normalizable column directions.", {
|
|
5146
5291
|
operation: "orderBy",
|
|
5147
5292
|
model: this.model.name
|
|
@@ -5150,6 +5295,28 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5150
5295
|
return this;
|
|
5151
5296
|
}
|
|
5152
5297
|
/**
|
|
5298
|
+
* Appends a raw SQL `order by` fragment (with positional `?` bindings), useful
|
|
5299
|
+
* for ordering by a computed expression the builder does not model directly.
|
|
5300
|
+
*
|
|
5301
|
+
* @param sql
|
|
5302
|
+
* @param bindings
|
|
5303
|
+
* @param direction
|
|
5304
|
+
* @returns
|
|
5305
|
+
*/
|
|
5306
|
+
orderByRaw(sql, bindings = [], direction = "asc") {
|
|
5307
|
+
this.randomOrderEnabled = false;
|
|
5308
|
+
this.queryOrderBy = [...this.queryOrderBy ?? [], {
|
|
5309
|
+
column: "",
|
|
5310
|
+
direction,
|
|
5311
|
+
expression: {
|
|
5312
|
+
kind: "raw",
|
|
5313
|
+
sql,
|
|
5314
|
+
bindings
|
|
5315
|
+
}
|
|
5316
|
+
}];
|
|
5317
|
+
return this;
|
|
5318
|
+
}
|
|
5319
|
+
/**
|
|
5153
5320
|
* Puts the query results in random order.
|
|
5154
5321
|
*
|
|
5155
5322
|
* @returns
|
|
@@ -5515,12 +5682,6 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5515
5682
|
pipe(callback) {
|
|
5516
5683
|
return callback(this);
|
|
5517
5684
|
}
|
|
5518
|
-
/**
|
|
5519
|
-
* Adds a select clause to the query. This will overwrite any existing select clause.
|
|
5520
|
-
*
|
|
5521
|
-
* @param select
|
|
5522
|
-
* @returns
|
|
5523
|
-
*/
|
|
5524
5685
|
select(select) {
|
|
5525
5686
|
const normalized = this.normalizeQuerySelect(select);
|
|
5526
5687
|
if (normalized === null) throw new require_relationship.UnsupportedAdapterFeatureException("Select clauses must use Arkorm-normalizable column projections.", {
|
|
@@ -5530,12 +5691,6 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5530
5691
|
this.querySelect = normalized;
|
|
5531
5692
|
return this;
|
|
5532
5693
|
}
|
|
5533
|
-
/**
|
|
5534
|
-
* Appends columns or expressions to the existing select clause.
|
|
5535
|
-
*
|
|
5536
|
-
* @param select
|
|
5537
|
-
* @returns
|
|
5538
|
-
*/
|
|
5539
5694
|
addSelect(select) {
|
|
5540
5695
|
const normalized = this.normalizeQuerySelect(select);
|
|
5541
5696
|
if (normalized === null) throw new require_relationship.UnsupportedAdapterFeatureException("Select clauses must use Arkorm-normalizable column projections.", {
|
|
@@ -5559,6 +5714,8 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5559
5714
|
return this;
|
|
5560
5715
|
}
|
|
5561
5716
|
groupBy(...columns) {
|
|
5717
|
+
const first = columns[0];
|
|
5718
|
+
if (columns.length === 1 && this.isGroupByAggregateSpec(first)) return this.executeGroupByAggregate(first);
|
|
5562
5719
|
const normalized = Array.isArray(columns[0]) ? columns[0] : columns;
|
|
5563
5720
|
if (normalized.length === 0) throw new QueryConstraintException("groupBy requires at least one column.", {
|
|
5564
5721
|
operation: "groupBy",
|
|
@@ -5567,6 +5724,109 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5567
5724
|
this.queryGroupBy = [...normalized];
|
|
5568
5725
|
return this;
|
|
5569
5726
|
}
|
|
5727
|
+
/**
|
|
5728
|
+
* Appends a raw SQL `group by` fragment (with positional `?` bindings), mirroring
|
|
5729
|
+
* `whereRaw`/`havingRaw`. Combines with any columns/expressions already grouped.
|
|
5730
|
+
*
|
|
5731
|
+
* @param sql
|
|
5732
|
+
* @param bindings
|
|
5733
|
+
* @returns
|
|
5734
|
+
*/
|
|
5735
|
+
groupByRaw(sql, bindings = []) {
|
|
5736
|
+
this.queryGroupBy = [...this.queryGroupBy ?? [], { raw: {
|
|
5737
|
+
sql,
|
|
5738
|
+
bindings
|
|
5739
|
+
} }];
|
|
5740
|
+
return this;
|
|
5741
|
+
}
|
|
5742
|
+
/**
|
|
5743
|
+
* Resolves the recorded group-by sources into adapter {@link QueryGroupByItem}s.
|
|
5744
|
+
* A bare string that matches a select-column alias is expanded to that column's
|
|
5745
|
+
* underlying expression (group-by-alias); otherwise it is treated as a column.
|
|
5746
|
+
*/
|
|
5747
|
+
buildGroupByItems(selectColumns) {
|
|
5748
|
+
if (!this.queryGroupBy || this.queryGroupBy.length === 0) return void 0;
|
|
5749
|
+
const expressionAliases = /* @__PURE__ */ new Map();
|
|
5750
|
+
selectColumns?.forEach((column) => {
|
|
5751
|
+
if (column.expression && column.alias) expressionAliases.set(JSON.stringify(column.expression), column.alias);
|
|
5752
|
+
});
|
|
5753
|
+
const aliasNames = new Set(expressionAliases.values());
|
|
5754
|
+
return this.queryGroupBy.map((source) => {
|
|
5755
|
+
if (source instanceof require_relationship.Expression) {
|
|
5756
|
+
const node = source.toExpressionNode();
|
|
5757
|
+
const alias = expressionAliases.get(JSON.stringify(node));
|
|
5758
|
+
return alias ? { alias } : { expression: node };
|
|
5759
|
+
}
|
|
5760
|
+
if (typeof source === "object") return { raw: source.raw };
|
|
5761
|
+
return aliasNames.has(source) ? { alias: source } : source;
|
|
5762
|
+
});
|
|
5763
|
+
}
|
|
5764
|
+
isGroupByAggregateSpec(value) {
|
|
5765
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof require_relationship.Expression) && Array.isArray(value.by);
|
|
5766
|
+
}
|
|
5767
|
+
/**
|
|
5768
|
+
* Executes the query and returns plain, un-hydrated rows keyed by their select
|
|
5769
|
+
* alias — the natural shape for `select` + `groupBy` aggregate reports. Pass a
|
|
5770
|
+
* row type to describe the projection.
|
|
5771
|
+
*
|
|
5772
|
+
* @returns
|
|
5773
|
+
*/
|
|
5774
|
+
async getRows() {
|
|
5775
|
+
return await this.executeReadRows();
|
|
5776
|
+
}
|
|
5777
|
+
/**
|
|
5778
|
+
* Runs a Prisma-style grouped aggregate and returns typed rows shaped as
|
|
5779
|
+
* `{ <by columns>, _sum, _avg, _min, _max, _count }`.
|
|
5780
|
+
*/
|
|
5781
|
+
async executeGroupByAggregate(spec) {
|
|
5782
|
+
const selectMap = {};
|
|
5783
|
+
spec.by.forEach((column) => {
|
|
5784
|
+
selectMap[column] = true;
|
|
5785
|
+
});
|
|
5786
|
+
const aggregates = [];
|
|
5787
|
+
const register = (group, factory, map, numeric) => {
|
|
5788
|
+
Object.keys(map).forEach((column) => {
|
|
5789
|
+
if (!map[column]) return;
|
|
5790
|
+
const alias = `${group}_${column}`;
|
|
5791
|
+
selectMap[alias] = factory(column);
|
|
5792
|
+
aggregates.push({
|
|
5793
|
+
group,
|
|
5794
|
+
column,
|
|
5795
|
+
alias,
|
|
5796
|
+
numeric
|
|
5797
|
+
});
|
|
5798
|
+
});
|
|
5799
|
+
};
|
|
5800
|
+
if (spec._sum) register("_sum", (column) => require_relationship.sum(column), spec._sum, true);
|
|
5801
|
+
if (spec._avg) register("_avg", (column) => require_relationship.avg(column), spec._avg, true);
|
|
5802
|
+
if (spec._min) register("_min", (column) => require_relationship.min(column), spec._min, false);
|
|
5803
|
+
if (spec._max) register("_max", (column) => require_relationship.max(column), spec._max, false);
|
|
5804
|
+
let countAllAlias;
|
|
5805
|
+
if (spec._count === true) {
|
|
5806
|
+
countAllAlias = "_count_all";
|
|
5807
|
+
selectMap[countAllAlias] = require_relationship.count();
|
|
5808
|
+
} else if (spec._count) register("_count", (column) => require_relationship.count(column), spec._count, true);
|
|
5809
|
+
this.select(selectMap);
|
|
5810
|
+
this.groupBy(spec.by);
|
|
5811
|
+
return (await this.getRows()).map((row) => {
|
|
5812
|
+
const result = {};
|
|
5813
|
+
spec.by.forEach((column) => {
|
|
5814
|
+
result[column] = row[column];
|
|
5815
|
+
});
|
|
5816
|
+
const grouped = {};
|
|
5817
|
+
aggregates.forEach(({ group, column, alias, numeric }) => {
|
|
5818
|
+
grouped[group] ??= {};
|
|
5819
|
+
grouped[group][column] = numeric ? this.coerceNumeric(row[alias]) : row[alias];
|
|
5820
|
+
});
|
|
5821
|
+
Object.assign(result, grouped);
|
|
5822
|
+
if (countAllAlias) result._count = this.coerceNumeric(row[countAllAlias]);
|
|
5823
|
+
return result;
|
|
5824
|
+
});
|
|
5825
|
+
}
|
|
5826
|
+
coerceNumeric(value) {
|
|
5827
|
+
if (value === null || value === void 0) return null;
|
|
5828
|
+
return Number(value);
|
|
5829
|
+
}
|
|
5570
5830
|
appendHavingCondition(boolean, condition) {
|
|
5571
5831
|
if (!this.queryHaving) {
|
|
5572
5832
|
this.queryHaving = condition;
|
|
@@ -5587,12 +5847,35 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5587
5847
|
value: hasOperator ? maybeValue : operatorOrValue
|
|
5588
5848
|
};
|
|
5589
5849
|
}
|
|
5590
|
-
|
|
5591
|
-
|
|
5850
|
+
/**
|
|
5851
|
+
* Resolves the three `having` call shapes into a condition: `having(column, …)`,
|
|
5852
|
+
* `having(expression)` (a boolean expression predicate), and
|
|
5853
|
+
* `having(expression, operator, value)` (compare an aggregate to a value).
|
|
5854
|
+
*/
|
|
5855
|
+
buildHavingCondition(columnOrExpression, operatorOrValue, maybeValue) {
|
|
5856
|
+
if (columnOrExpression instanceof require_relationship.Expression) return {
|
|
5857
|
+
type: "expression",
|
|
5858
|
+
expression: (operatorOrValue === void 0 ? columnOrExpression : this.compareExpression(columnOrExpression, operatorOrValue, maybeValue)).toExpressionNode()
|
|
5859
|
+
};
|
|
5860
|
+
return this.buildHavingComparison(operatorOrValue, maybeValue, columnOrExpression);
|
|
5861
|
+
}
|
|
5862
|
+
compareExpression(expression, operator, value) {
|
|
5863
|
+
switch (operator) {
|
|
5864
|
+
case "=": return expression.eq(value);
|
|
5865
|
+
case "!=": return expression.ne(value);
|
|
5866
|
+
case ">": return expression.gt(value);
|
|
5867
|
+
case ">=": return expression.gte(value);
|
|
5868
|
+
case "<": return expression.lt(value);
|
|
5869
|
+
case "<=": return expression.lte(value);
|
|
5870
|
+
default: return expression.eq(value);
|
|
5871
|
+
}
|
|
5872
|
+
}
|
|
5873
|
+
having(columnOrExpression, operatorOrValue, maybeValue) {
|
|
5874
|
+
this.appendHavingCondition("AND", this.buildHavingCondition(columnOrExpression, operatorOrValue, maybeValue));
|
|
5592
5875
|
return this;
|
|
5593
5876
|
}
|
|
5594
|
-
orHaving(
|
|
5595
|
-
this.appendHavingCondition("OR", this.
|
|
5877
|
+
orHaving(columnOrExpression, operatorOrValue, maybeValue) {
|
|
5878
|
+
this.appendHavingCondition("OR", this.buildHavingCondition(columnOrExpression, operatorOrValue, maybeValue));
|
|
5596
5879
|
return this;
|
|
5597
5880
|
}
|
|
5598
5881
|
/**
|
|
@@ -5979,6 +6262,173 @@ var QueryBuilder = class QueryBuilder {
|
|
|
5979
6262
|
return new require_relationship.ArkormCollection(filteredModels);
|
|
5980
6263
|
}
|
|
5981
6264
|
/**
|
|
6265
|
+
* Processes the query results in chunks, invoking the callback with each chunk
|
|
6266
|
+
* as a collection. Return `false` from the callback to stop early. Resolves to
|
|
6267
|
+
* `false` when stopped early, otherwise `true`.
|
|
6268
|
+
*
|
|
6269
|
+
* Chunking pages with `offset`/`limit`, so add an `orderBy` for stable results
|
|
6270
|
+
* and prefer {@link chunkById} when modifying the records being iterated.
|
|
6271
|
+
*
|
|
6272
|
+
* @param count Rows per chunk.
|
|
6273
|
+
* @param callback Receives each chunk and its 1-based page number.
|
|
6274
|
+
* @returns
|
|
6275
|
+
*/
|
|
6276
|
+
async chunk(count, callback) {
|
|
6277
|
+
this.assertPositiveChunkSize(count, "chunk");
|
|
6278
|
+
let page = 1;
|
|
6279
|
+
for (;;) {
|
|
6280
|
+
const results = await this.clone().skip((page - 1) * count).take(count).get();
|
|
6281
|
+
const size = results.count();
|
|
6282
|
+
if (size === 0) break;
|
|
6283
|
+
if (await callback(results, page) === false) return false;
|
|
6284
|
+
if (size < count) break;
|
|
6285
|
+
page++;
|
|
6286
|
+
}
|
|
6287
|
+
return true;
|
|
6288
|
+
}
|
|
6289
|
+
/**
|
|
6290
|
+
* Chunks the results by comparing a monotonically increasing key column
|
|
6291
|
+
* (`id > lastId`) rather than by offset — safe when the callback updates the
|
|
6292
|
+
* records being iterated. Return `false` from the callback to stop early.
|
|
6293
|
+
*
|
|
6294
|
+
* @param count Rows per chunk.
|
|
6295
|
+
* @param callback Receives each chunk and its 1-based page number.
|
|
6296
|
+
* @param column The key column to page by (defaults to the primary key).
|
|
6297
|
+
* @param alias The result attribute holding the key value (defaults to `column`).
|
|
6298
|
+
* @returns
|
|
6299
|
+
*/
|
|
6300
|
+
async chunkById(count, callback, column, alias) {
|
|
6301
|
+
this.assertPositiveChunkSize(count, "chunkById");
|
|
6302
|
+
const keyColumn = column ?? this.model.getPrimaryKey();
|
|
6303
|
+
const keyAlias = alias ?? keyColumn;
|
|
6304
|
+
let lastId = null;
|
|
6305
|
+
let page = 1;
|
|
6306
|
+
for (;;) {
|
|
6307
|
+
const builder = this.clone().take(count).orderBy({ [keyColumn]: "asc" });
|
|
6308
|
+
if (lastId !== null) builder.where({ [keyColumn]: { gt: lastId } });
|
|
6309
|
+
const results = await builder.get();
|
|
6310
|
+
const size = results.count();
|
|
6311
|
+
if (size === 0) break;
|
|
6312
|
+
if (await callback(results, page) === false) return false;
|
|
6313
|
+
lastId = this.readModelAttribute(results.last(), keyAlias);
|
|
6314
|
+
if (lastId === null || lastId === void 0) break;
|
|
6315
|
+
if (size < count) break;
|
|
6316
|
+
page++;
|
|
6317
|
+
}
|
|
6318
|
+
return true;
|
|
6319
|
+
}
|
|
6320
|
+
/**
|
|
6321
|
+
* Iterates the query results one record at a time (chunking under the hood).
|
|
6322
|
+
* Return `false` from the callback to stop early.
|
|
6323
|
+
*
|
|
6324
|
+
* @param callback Receives each record and its 0-based index.
|
|
6325
|
+
* @param count Rows fetched per chunk (default 1000).
|
|
6326
|
+
* @returns
|
|
6327
|
+
*/
|
|
6328
|
+
async each(callback, count = 1e3) {
|
|
6329
|
+
let index = 0;
|
|
6330
|
+
return this.chunk(count, async (models) => {
|
|
6331
|
+
for (const model of models.all()) {
|
|
6332
|
+
if (await callback(model, index) === false) return false;
|
|
6333
|
+
index++;
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
}
|
|
6337
|
+
/**
|
|
6338
|
+
* Like {@link each}, but pages by key column ({@link chunkById}) — safe when the
|
|
6339
|
+
* callback updates the records being iterated.
|
|
6340
|
+
*
|
|
6341
|
+
* @param callback Receives each record and its 0-based index.
|
|
6342
|
+
* @param count Rows fetched per chunk (default 1000).
|
|
6343
|
+
* @param column The key column to page by (defaults to the primary key).
|
|
6344
|
+
* @param alias The result attribute holding the key value (defaults to `column`).
|
|
6345
|
+
* @returns
|
|
6346
|
+
*/
|
|
6347
|
+
async eachById(callback, count = 1e3, column, alias) {
|
|
6348
|
+
let index = 0;
|
|
6349
|
+
return this.chunkById(count, async (models) => {
|
|
6350
|
+
for (const model of models.all()) {
|
|
6351
|
+
if (await callback(model, index) === false) return false;
|
|
6352
|
+
index++;
|
|
6353
|
+
}
|
|
6354
|
+
}, column, alias);
|
|
6355
|
+
}
|
|
6356
|
+
/**
|
|
6357
|
+
* Streams the query results lazily as an async iterator, fetching one chunk at
|
|
6358
|
+
* a time so only a small window is held in memory. Iterate with `for await`.
|
|
6359
|
+
*
|
|
6360
|
+
* ```ts
|
|
6361
|
+
* for await (const user of User.query().orderBy({ id: 'asc' }).lazy()) {
|
|
6362
|
+
* // …
|
|
6363
|
+
* }
|
|
6364
|
+
* ```
|
|
6365
|
+
*
|
|
6366
|
+
* @param chunkSize Rows fetched per underlying query (default 1000).
|
|
6367
|
+
* @returns
|
|
6368
|
+
*/
|
|
6369
|
+
async *lazy(chunkSize = 1e3) {
|
|
6370
|
+
this.assertPositiveChunkSize(chunkSize, "lazy");
|
|
6371
|
+
let page = 1;
|
|
6372
|
+
for (;;) {
|
|
6373
|
+
const items = (await this.clone().skip((page - 1) * chunkSize).take(chunkSize).get()).all();
|
|
6374
|
+
if (items.length === 0) break;
|
|
6375
|
+
yield* items;
|
|
6376
|
+
if (items.length < chunkSize) break;
|
|
6377
|
+
page++;
|
|
6378
|
+
}
|
|
6379
|
+
}
|
|
6380
|
+
/**
|
|
6381
|
+
* Streams the results lazily, paging by an ascending key column — safe when the
|
|
6382
|
+
* consumer updates records mid-iteration. Iterate with `for await`.
|
|
6383
|
+
*
|
|
6384
|
+
* @param chunkSize Rows fetched per underlying query (default 1000).
|
|
6385
|
+
* @param column The key column to page by (defaults to the primary key).
|
|
6386
|
+
* @param alias The result attribute holding the key value (defaults to `column`).
|
|
6387
|
+
* @returns
|
|
6388
|
+
*/
|
|
6389
|
+
lazyById(chunkSize = 1e3, column, alias) {
|
|
6390
|
+
return this.lazyByKey(chunkSize, "asc", column, alias);
|
|
6391
|
+
}
|
|
6392
|
+
/**
|
|
6393
|
+
* Streams the results lazily, paging by a descending key column. Iterate with
|
|
6394
|
+
* `for await`.
|
|
6395
|
+
*
|
|
6396
|
+
* @param chunkSize Rows fetched per underlying query (default 1000).
|
|
6397
|
+
* @param column The key column to page by (defaults to the primary key).
|
|
6398
|
+
* @param alias The result attribute holding the key value (defaults to `column`).
|
|
6399
|
+
* @returns
|
|
6400
|
+
*/
|
|
6401
|
+
lazyByIdDesc(chunkSize = 1e3, column, alias) {
|
|
6402
|
+
return this.lazyByKey(chunkSize, "desc", column, alias);
|
|
6403
|
+
}
|
|
6404
|
+
async *lazyByKey(chunkSize, direction, column, alias) {
|
|
6405
|
+
this.assertPositiveChunkSize(chunkSize, "lazyById");
|
|
6406
|
+
const keyColumn = column ?? this.model.getPrimaryKey();
|
|
6407
|
+
const keyAlias = alias ?? keyColumn;
|
|
6408
|
+
const operator = direction === "asc" ? "gt" : "lt";
|
|
6409
|
+
let lastId = null;
|
|
6410
|
+
for (;;) {
|
|
6411
|
+
const builder = this.clone().take(chunkSize).orderBy({ [keyColumn]: direction });
|
|
6412
|
+
if (lastId !== null) builder.where({ [keyColumn]: { [operator]: lastId } });
|
|
6413
|
+
const items = (await builder.get()).all();
|
|
6414
|
+
if (items.length === 0) break;
|
|
6415
|
+
yield* items;
|
|
6416
|
+
lastId = this.readModelAttribute(items[items.length - 1], keyAlias);
|
|
6417
|
+
if (lastId === null || lastId === void 0) break;
|
|
6418
|
+
if (items.length < chunkSize) break;
|
|
6419
|
+
}
|
|
6420
|
+
}
|
|
6421
|
+
assertPositiveChunkSize(count, operation) {
|
|
6422
|
+
if (!Number.isInteger(count) || count < 1) throw new QueryConstraintException("Chunk size must be a positive integer.", {
|
|
6423
|
+
operation,
|
|
6424
|
+
model: this.model.name
|
|
6425
|
+
});
|
|
6426
|
+
}
|
|
6427
|
+
readModelAttribute(model, attribute) {
|
|
6428
|
+
if (!model) return null;
|
|
6429
|
+
return model.getAttribute(attribute);
|
|
6430
|
+
}
|
|
6431
|
+
/**
|
|
5982
6432
|
* Executes the query and returns the first result as a model
|
|
5983
6433
|
* instance, or null if no results are found.
|
|
5984
6434
|
*
|
|
@@ -6750,12 +7200,19 @@ var QueryBuilder = class QueryBuilder {
|
|
|
6750
7200
|
}
|
|
6751
7201
|
if (typeof select !== "object" || !select) return null;
|
|
6752
7202
|
const entries = Object.entries(select);
|
|
6753
|
-
if (entries.some(([, value]) => value !== true && value !== false && value !== void 0 && typeof value !== "string")) return null;
|
|
6754
|
-
const columns = entries.filter(([, value]) => value === true || typeof value === "string").map(([column, value]) =>
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
7203
|
+
if (entries.some(([, value]) => value !== true && value !== false && value !== void 0 && typeof value !== "string" && !(value instanceof require_relationship.Expression))) return null;
|
|
7204
|
+
const columns = entries.filter(([, value]) => value === true || typeof value === "string" || value instanceof require_relationship.Expression).map(([column, value]) => {
|
|
7205
|
+
if (value instanceof require_relationship.Expression) return {
|
|
7206
|
+
column,
|
|
7207
|
+
alias: column,
|
|
7208
|
+
expression: value.toExpressionNode()
|
|
7209
|
+
};
|
|
7210
|
+
return typeof value === "string" ? {
|
|
7211
|
+
column,
|
|
7212
|
+
alias: value,
|
|
7213
|
+
raw: true
|
|
7214
|
+
} : { column };
|
|
7215
|
+
});
|
|
6759
7216
|
return columns.length > 0 ? columns : [];
|
|
6760
7217
|
}
|
|
6761
7218
|
normalizeQueryOrderBy(orderBy) {
|
|
@@ -6913,7 +7370,7 @@ var QueryBuilder = class QueryBuilder {
|
|
|
6913
7370
|
offset: normalizedQuery.offsetValue,
|
|
6914
7371
|
columns: normalizedQuery.querySelect ? [...normalizedQuery.querySelect] : void 0,
|
|
6915
7372
|
distinct: normalizedQuery.queryDistinct || void 0,
|
|
6916
|
-
groupBy: normalizedQuery.queryGroupBy ?
|
|
7373
|
+
groupBy: normalizedQuery.queryGroupBy ? normalizedQuery.queryGroupBy.filter((source) => typeof source === "string") : void 0,
|
|
6917
7374
|
relationLoads: this.mergeRelationLoadPlans(normalizedQuery.queryRelationLoads ? this.cloneRelationLoads(normalizedQuery.queryRelationLoads) : void 0, this.mergeRelationLoadPlans(callbackRelationLoads, childRelationLoads))
|
|
6918
7375
|
});
|
|
6919
7376
|
}
|
|
@@ -7177,11 +7634,11 @@ var QueryBuilder = class QueryBuilder {
|
|
|
7177
7634
|
if (columns === null || orderBy === null || condition === null) return null;
|
|
7178
7635
|
if (this.hasRelationFilters() && this.canExecuteRelationFiltersInAdapter() && relationFilters === null) return null;
|
|
7179
7636
|
if (this.hasRelationAggregates() && this.canExecuteRelationAggregatesInAdapter() && relationAggregates === null) return null;
|
|
7180
|
-
return {
|
|
7637
|
+
return this.expandComputedAttributes({
|
|
7181
7638
|
target: this.buildQueryTarget(),
|
|
7182
7639
|
columns,
|
|
7183
7640
|
distinct: this.queryDistinct || void 0,
|
|
7184
|
-
groupBy: this.
|
|
7641
|
+
groupBy: this.buildGroupByItems(columns ?? void 0),
|
|
7185
7642
|
having: this.queryHaving,
|
|
7186
7643
|
joins: this.queryJoins ? [...this.queryJoins] : void 0,
|
|
7187
7644
|
where: condition,
|
|
@@ -7191,7 +7648,86 @@ var QueryBuilder = class QueryBuilder {
|
|
|
7191
7648
|
relationLoads: this.queryRelationLoads,
|
|
7192
7649
|
relationFilters: this.canExecuteRelationFiltersInAdapter() ? relationFilters ?? void 0 : void 0,
|
|
7193
7650
|
relationAggregates: this.canExecuteRelationAggregatesInAdapter() ? relationAggregates ?? void 0 : void 0
|
|
7651
|
+
});
|
|
7652
|
+
}
|
|
7653
|
+
/** Reads and caches the model's resolved `static computed` expression map. */
|
|
7654
|
+
computedAttributes() {
|
|
7655
|
+
const model = this.model;
|
|
7656
|
+
return typeof model.getComputed === "function" ? model.getComputed() : {};
|
|
7657
|
+
}
|
|
7658
|
+
/**
|
|
7659
|
+
* Expands references to `static computed` attribute names into their backing
|
|
7660
|
+
* expressions across a select spec's columns, group by, order by, where, and
|
|
7661
|
+
* having clauses. A no-op when the model declares no computed attributes.
|
|
7662
|
+
*/
|
|
7663
|
+
expandComputedAttributes(spec) {
|
|
7664
|
+
const computed = this.computedAttributes();
|
|
7665
|
+
if (Object.keys(computed).length === 0) return spec;
|
|
7666
|
+
const columns = spec.columns?.map((column) => {
|
|
7667
|
+
if (column.expression || column.raw || column.wildcard) return column;
|
|
7668
|
+
const expression = computed[column.column];
|
|
7669
|
+
return expression ? {
|
|
7670
|
+
...column,
|
|
7671
|
+
expression,
|
|
7672
|
+
alias: column.alias ?? column.column
|
|
7673
|
+
} : column;
|
|
7674
|
+
});
|
|
7675
|
+
const selectedComputedAliases = new Set(columns?.filter((column) => column.expression && column.alias).map((column) => column.alias));
|
|
7676
|
+
return {
|
|
7677
|
+
...spec,
|
|
7678
|
+
columns,
|
|
7679
|
+
groupBy: spec.groupBy?.map((item) => {
|
|
7680
|
+
if (typeof item !== "string") return item;
|
|
7681
|
+
const expression = computed[item];
|
|
7682
|
+
if (!expression) return item;
|
|
7683
|
+
return selectedComputedAliases.has(item) ? { alias: item } : { expression };
|
|
7684
|
+
}),
|
|
7685
|
+
orderBy: spec.orderBy?.map((clause) => {
|
|
7686
|
+
if (clause.expression) return clause;
|
|
7687
|
+
const expression = computed[clause.column];
|
|
7688
|
+
return expression ? {
|
|
7689
|
+
...clause,
|
|
7690
|
+
expression
|
|
7691
|
+
} : clause;
|
|
7692
|
+
}),
|
|
7693
|
+
where: spec.where ? this.expandComputedCondition(spec.where, computed) : spec.where,
|
|
7694
|
+
having: spec.having ? this.expandComputedCondition(spec.having, computed) : spec.having
|
|
7695
|
+
};
|
|
7696
|
+
}
|
|
7697
|
+
expandComputedCondition(condition, computed) {
|
|
7698
|
+
if (condition.type === "comparison" && computed[condition.column]) return {
|
|
7699
|
+
type: "expression",
|
|
7700
|
+
expression: this.computedComparison(computed[condition.column], condition.operator, condition.value)
|
|
7194
7701
|
};
|
|
7702
|
+
if (condition.type === "group") return {
|
|
7703
|
+
...condition,
|
|
7704
|
+
conditions: condition.conditions.map((entry) => this.expandComputedCondition(entry, computed))
|
|
7705
|
+
};
|
|
7706
|
+
if (condition.type === "not") return {
|
|
7707
|
+
...condition,
|
|
7708
|
+
condition: this.expandComputedCondition(condition.condition, computed)
|
|
7709
|
+
};
|
|
7710
|
+
return condition;
|
|
7711
|
+
}
|
|
7712
|
+
/** Converts a where comparison against a computed attribute into an expression. */
|
|
7713
|
+
computedComparison(node, operator, value) {
|
|
7714
|
+
const expression = require_relationship.fromExpressionNode(node);
|
|
7715
|
+
const list = Array.isArray(value) ? value : [];
|
|
7716
|
+
switch (operator) {
|
|
7717
|
+
case "!=": return expression.ne(value).toExpressionNode();
|
|
7718
|
+
case ">": return expression.gt(value).toExpressionNode();
|
|
7719
|
+
case ">=": return expression.gte(value).toExpressionNode();
|
|
7720
|
+
case "<": return expression.lt(value).toExpressionNode();
|
|
7721
|
+
case "<=": return expression.lte(value).toExpressionNode();
|
|
7722
|
+
case "in": return expression.in(list).toExpressionNode();
|
|
7723
|
+
case "not-in": return expression.notIn(list).toExpressionNode();
|
|
7724
|
+
case "is-null": return expression.isNull().toExpressionNode();
|
|
7725
|
+
case "is-not-null": return expression.isNotNull().toExpressionNode();
|
|
7726
|
+
case "contains": return expression.like(`%${String(value)}%`).toExpressionNode();
|
|
7727
|
+
case "starts-with": return expression.like(`${String(value)}%`).toExpressionNode();
|
|
7728
|
+
case "ends-with": return expression.like(`%${String(value)}`).toExpressionNode();
|
|
7729
|
+
default: return expression.eq(value).toExpressionNode();
|
|
7730
|
+
}
|
|
7195
7731
|
}
|
|
7196
7732
|
tryBuildAggregateSpec() {
|
|
7197
7733
|
const condition = this.buildQueryWhereCondition(false);
|
|
@@ -7691,6 +8227,9 @@ var Model = class Model {
|
|
|
7691
8227
|
static {
|
|
7692
8228
|
this.castMapCache = /* @__PURE__ */ new WeakMap();
|
|
7693
8229
|
}
|
|
8230
|
+
static {
|
|
8231
|
+
this.computedCache = /* @__PURE__ */ new WeakMap();
|
|
8232
|
+
}
|
|
7694
8233
|
static {
|
|
7695
8234
|
this.emittedDeprecationWarnings = /* @__PURE__ */ new Set();
|
|
7696
8235
|
}
|
|
@@ -7841,6 +8380,19 @@ var Model = class Model {
|
|
|
7841
8380
|
return casts;
|
|
7842
8381
|
}
|
|
7843
8382
|
/**
|
|
8383
|
+
* Resolves the model's `static computed` declarations into expression nodes,
|
|
8384
|
+
* cached per class. Returns an empty map when no computed attributes exist.
|
|
8385
|
+
*/
|
|
8386
|
+
static getComputed() {
|
|
8387
|
+
const cached = Model.computedCache.get(this);
|
|
8388
|
+
if (cached) return cached;
|
|
8389
|
+
const definitions = this.computed;
|
|
8390
|
+
const resolved = {};
|
|
8391
|
+
if (definitions) for (const [name, factory] of Object.entries(definitions)) resolved[name] = factory(require_relationship.expressionBuilder).toExpressionNode();
|
|
8392
|
+
Model.computedCache.set(this, resolved);
|
|
8393
|
+
return resolved;
|
|
8394
|
+
}
|
|
8395
|
+
/**
|
|
7844
8396
|
* Apply built-in persistence casts (currently `json` serialisation) to a raw
|
|
7845
8397
|
* attribute payload, without re-running arbitrary custom setters. Used by
|
|
7846
8398
|
* both instance `save()` and the query-builder insert/update paths so a JS
|
|
@@ -9697,18 +10249,22 @@ var PivotModel = class extends Model {
|
|
|
9697
10249
|
};
|
|
9698
10250
|
|
|
9699
10251
|
//#endregion
|
|
10252
|
+
exports.AggregateExpression = require_relationship.AggregateExpression;
|
|
9700
10253
|
exports.Arkorm = Arkorm;
|
|
9701
10254
|
exports.ArkormCollection = require_relationship.ArkormCollection;
|
|
9702
10255
|
exports.ArkormException = require_relationship.ArkormException;
|
|
9703
10256
|
exports.Arkormx = Arkormx;
|
|
9704
10257
|
exports.Attribute = Attribute;
|
|
10258
|
+
exports.CaseExpression = require_relationship.CaseExpression;
|
|
9705
10259
|
exports.CliApp = CliApp;
|
|
9706
10260
|
exports.DB = DB;
|
|
9707
10261
|
exports.EnumBuilder = require_relationship.EnumBuilder;
|
|
10262
|
+
exports.Expression = require_relationship.Expression;
|
|
9708
10263
|
exports.ForeignKeyBuilder = require_relationship.ForeignKeyBuilder;
|
|
9709
10264
|
exports.InitCommand = InitCommand;
|
|
9710
10265
|
exports.InlineFactory = InlineFactory;
|
|
9711
10266
|
exports.JoinClause = JoinClause;
|
|
10267
|
+
exports.JsonExpression = require_relationship.JsonExpression;
|
|
9712
10268
|
exports.KyselyDatabaseAdapter = KyselyDatabaseAdapter;
|
|
9713
10269
|
exports.LengthAwarePaginator = require_relationship.LengthAwarePaginator;
|
|
9714
10270
|
exports.MIGRATION_BRAND = MIGRATION_BRAND;
|
|
@@ -9756,6 +10312,7 @@ exports.applyMigrationToDatabase = require_relationship.applyMigrationToDatabase
|
|
|
9756
10312
|
exports.applyMigrationToPrismaSchema = require_relationship.applyMigrationToPrismaSchema;
|
|
9757
10313
|
exports.applyOperationsToPersistedColumnMappingsState = require_relationship.applyOperationsToPersistedColumnMappingsState;
|
|
9758
10314
|
exports.applyOperationsToPrismaSchema = require_relationship.applyOperationsToPrismaSchema;
|
|
10315
|
+
exports.avg = require_relationship.avg;
|
|
9759
10316
|
exports.awaitConfiguredModelsRegistration = require_relationship.awaitConfiguredModelsRegistration;
|
|
9760
10317
|
exports.bindAdapterToModels = require_relationship.bindAdapterToModels;
|
|
9761
10318
|
exports.buildEnumBlock = require_relationship.buildEnumBlock;
|
|
@@ -9769,8 +10326,12 @@ exports.buildModelBlock = require_relationship.buildModelBlock;
|
|
|
9769
10326
|
exports.buildPrimaryKeyLine = require_relationship.buildPrimaryKeyLine;
|
|
9770
10327
|
exports.buildRelationLine = require_relationship.buildRelationLine;
|
|
9771
10328
|
exports.buildUniqueConstraintLine = require_relationship.buildUniqueConstraintLine;
|
|
10329
|
+
exports.caseWhen = require_relationship.caseWhen;
|
|
10330
|
+
exports.coalesce = require_relationship.coalesce;
|
|
10331
|
+
exports.col = require_relationship.col;
|
|
9772
10332
|
exports.computeMigrationChecksum = require_relationship.computeMigrationChecksum;
|
|
9773
10333
|
exports.configureArkormRuntime = require_relationship.configureArkormRuntime;
|
|
10334
|
+
exports.count = require_relationship.count;
|
|
9774
10335
|
exports.createEmptyAppliedMigrationsState = require_relationship.createEmptyAppliedMigrationsState;
|
|
9775
10336
|
exports.createEmptyPersistedColumnMappingsState = require_relationship.createEmptyPersistedColumnMappingsState;
|
|
9776
10337
|
exports.createKyselyAdapter = createKyselyAdapter;
|
|
@@ -9791,12 +10352,15 @@ exports.deriveSingularFieldName = require_relationship.deriveSingularFieldName;
|
|
|
9791
10352
|
exports.emitRuntimeDebugEvent = require_relationship.emitRuntimeDebugEvent;
|
|
9792
10353
|
exports.ensureArkormConfigLoading = require_relationship.ensureArkormConfigLoading;
|
|
9793
10354
|
exports.escapeRegex = require_relationship.escapeRegex;
|
|
10355
|
+
exports.expressionBuilder = require_relationship.expressionBuilder;
|
|
9794
10356
|
exports.findAppliedMigration = require_relationship.findAppliedMigration;
|
|
9795
10357
|
exports.findEnumBlock = require_relationship.findEnumBlock;
|
|
9796
10358
|
exports.findModelBlock = require_relationship.findModelBlock;
|
|
10359
|
+
exports.fn = require_relationship.fn;
|
|
9797
10360
|
exports.formatDefaultValue = require_relationship.formatDefaultValue;
|
|
9798
10361
|
exports.formatEnumDefaultValue = require_relationship.formatEnumDefaultValue;
|
|
9799
10362
|
exports.formatRelationAction = require_relationship.formatRelationAction;
|
|
10363
|
+
exports.fromExpressionNode = require_relationship.fromExpressionNode;
|
|
9800
10364
|
exports.generateMigrationFile = require_relationship.generateMigrationFile;
|
|
9801
10365
|
exports.getActiveTransactionAdapter = require_relationship.getActiveTransactionAdapter;
|
|
9802
10366
|
exports.getActiveTransactionClient = require_relationship.getActiveTransactionClient;
|
|
@@ -9828,6 +10392,7 @@ exports.isDelegateLike = require_relationship.isDelegateLike;
|
|
|
9828
10392
|
exports.isMigrationApplied = require_relationship.isMigrationApplied;
|
|
9829
10393
|
exports.isQuerySchemaLike = require_relationship.isQuerySchemaLike;
|
|
9830
10394
|
exports.isTransactionCapableClient = require_relationship.isTransactionCapableClient;
|
|
10395
|
+
exports.json = require_relationship.json;
|
|
9831
10396
|
exports.loadArkormConfig = require_relationship.loadArkormConfig;
|
|
9832
10397
|
exports.loadFactoriesFrom = require_relationship.loadFactoriesFrom;
|
|
9833
10398
|
exports.loadMigrationsFrom = require_relationship.loadMigrationsFrom;
|
|
@@ -9835,7 +10400,10 @@ exports.loadModelsFrom = require_relationship.loadModelsFrom;
|
|
|
9835
10400
|
exports.loadSeedersFrom = require_relationship.loadSeedersFrom;
|
|
9836
10401
|
exports.markMigrationApplied = require_relationship.markMigrationApplied;
|
|
9837
10402
|
exports.markMigrationRun = require_relationship.markMigrationRun;
|
|
10403
|
+
exports.max = require_relationship.max;
|
|
10404
|
+
exports.min = require_relationship.min;
|
|
9838
10405
|
exports.pad = require_relationship.pad;
|
|
10406
|
+
exports.raw = require_relationship.raw;
|
|
9839
10407
|
exports.readAppliedMigrationsState = require_relationship.readAppliedMigrationsState;
|
|
9840
10408
|
exports.readAppliedMigrationsStateFromStore = require_relationship.readAppliedMigrationsStateFromStore;
|
|
9841
10409
|
exports.readPersistedColumnMappingsState = require_relationship.readPersistedColumnMappingsState;
|
|
@@ -9852,6 +10420,7 @@ exports.resetRuntimeRegistryForTests = require_relationship.resetRuntimeRegistry
|
|
|
9852
10420
|
exports.resolveCast = resolveCast;
|
|
9853
10421
|
exports.resolveColumnMappingsFilePath = require_relationship.resolveColumnMappingsFilePath;
|
|
9854
10422
|
exports.resolveEnumName = require_relationship.resolveEnumName;
|
|
10423
|
+
exports.resolveGeneratedExpression = require_relationship.resolveGeneratedExpression;
|
|
9855
10424
|
exports.resolveMigrationClassName = require_relationship.resolveMigrationClassName;
|
|
9856
10425
|
exports.resolveMigrationStateFilePath = require_relationship.resolveMigrationStateFilePath;
|
|
9857
10426
|
exports.resolvePersistedMetadataFeatures = require_relationship.resolvePersistedMetadataFeatures;
|
|
@@ -9862,6 +10431,7 @@ exports.runArkormTransaction = require_relationship.runArkormTransaction;
|
|
|
9862
10431
|
exports.runMigrationWithPrisma = require_relationship.runMigrationWithPrisma;
|
|
9863
10432
|
exports.runPrismaCommand = require_relationship.runPrismaCommand;
|
|
9864
10433
|
exports.stripPrismaSchemaModelsAndEnums = require_relationship.stripPrismaSchemaModelsAndEnums;
|
|
10434
|
+
exports.sum = require_relationship.sum;
|
|
9865
10435
|
exports.supportsDatabaseCreation = require_relationship.supportsDatabaseCreation;
|
|
9866
10436
|
exports.supportsDatabaseMigrationExecution = require_relationship.supportsDatabaseMigrationExecution;
|
|
9867
10437
|
exports.supportsDatabaseMigrationState = require_relationship.supportsDatabaseMigrationState;
|
|
@@ -9869,7 +10439,9 @@ exports.supportsDatabaseReset = require_relationship.supportsDatabaseReset;
|
|
|
9869
10439
|
exports.syncPersistedColumnMappingsFromState = require_relationship.syncPersistedColumnMappingsFromState;
|
|
9870
10440
|
exports.toMigrationFileSlug = require_relationship.toMigrationFileSlug;
|
|
9871
10441
|
exports.toModelName = require_relationship.toModelName;
|
|
10442
|
+
exports.val = require_relationship.val;
|
|
9872
10443
|
exports.validatePersistedMetadataFeaturesForMigrations = require_relationship.validatePersistedMetadataFeaturesForMigrations;
|
|
10444
|
+
exports.where = require_relationship.where;
|
|
9873
10445
|
exports.writeAppliedMigrationsState = require_relationship.writeAppliedMigrationsState;
|
|
9874
10446
|
exports.writeAppliedMigrationsStateToStore = require_relationship.writeAppliedMigrationsStateToStore;
|
|
9875
10447
|
exports.writePersistedColumnMappingsState = require_relationship.writePersistedColumnMappingsState;
|