metal-orm 1.0.83 → 1.0.86
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/index.cjs +299 -233
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -13
- package/dist/index.d.ts +28 -13
- package/dist/index.js +297 -233
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/ast/ast-validation.ts +11 -180
- package/src/core/ast/expression-nodes.ts +35 -25
- package/src/core/ast/expression-visitor.ts +53 -25
- package/src/core/ast/query-visitor.ts +273 -0
- package/src/core/dialect/abstract.ts +11 -7
- package/src/orm/execute.ts +60 -46
- package/src/query-builder/query-ast-service.ts +13 -0
- package/src/query-builder/select/select-operations.ts +32 -24
- package/src/query-builder/select.ts +49 -35
|
@@ -68,7 +68,7 @@ import { SelectCTEFacet } from './select/cte-facet.js';
|
|
|
68
68
|
import { SelectSetOpFacet } from './select/setop-facet.js';
|
|
69
69
|
import { SelectRelationFacet } from './select/relation-facet.js';
|
|
70
70
|
import { buildFilterParameters, extractSchema, SchemaOptions, OpenApiSchemaBundle } from '../openapi/index.js';
|
|
71
|
-
import {
|
|
71
|
+
import { findFirstParamOperandName } from '../core/ast/ast-validation.js';
|
|
72
72
|
|
|
73
73
|
type ColumnSelectionValue =
|
|
74
74
|
| ColumnDef
|
|
@@ -82,10 +82,14 @@ type SelectionValueType<TValue> =
|
|
|
82
82
|
TValue extends ColumnDef ? ColumnToTs<TValue> :
|
|
83
83
|
unknown;
|
|
84
84
|
|
|
85
|
-
type SelectionResult<TSelection extends Record<string, ColumnSelectionValue>> = {
|
|
86
|
-
[K in keyof TSelection]: SelectionValueType<TSelection[K]>;
|
|
87
|
-
};
|
|
88
|
-
|
|
85
|
+
type SelectionResult<TSelection extends Record<string, ColumnSelectionValue>> = {
|
|
86
|
+
[K in keyof TSelection]: SelectionValueType<TSelection[K]>;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type ParamOperandOptions = {
|
|
90
|
+
allowParamOperands?: boolean;
|
|
91
|
+
};
|
|
92
|
+
|
|
89
93
|
type SelectionFromKeys<
|
|
90
94
|
TTable extends TableDef,
|
|
91
95
|
K extends keyof TTable['columns'] & string
|
|
@@ -730,11 +734,12 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
730
734
|
* Validates that the query does not contain Param operands.
|
|
731
735
|
* Param proxies are only for schema generation, not execution.
|
|
732
736
|
*/
|
|
733
|
-
private validateNoParamOperands(): void {
|
|
737
|
+
private validateNoParamOperands(options?: ParamOperandOptions): void {
|
|
738
|
+
if (options?.allowParamOperands) return;
|
|
734
739
|
const ast = this.context.hydration.applyToAst(this.context.state.ast);
|
|
735
|
-
const
|
|
736
|
-
if (
|
|
737
|
-
throw new Error(
|
|
740
|
+
const paramName = findFirstParamOperandName(ast);
|
|
741
|
+
if (paramName) {
|
|
742
|
+
throw new Error(`Cannot execute query containing Param operand "${paramName}". Param proxies are only for schema generation (getSchema()). If you need real parameters, use literal values.`);
|
|
738
743
|
}
|
|
739
744
|
}
|
|
740
745
|
|
|
@@ -750,13 +755,13 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
750
755
|
* // users is User[]
|
|
751
756
|
* users[0] instanceof User; // true
|
|
752
757
|
*/
|
|
753
|
-
async execute(ctx: OrmSession): Promise<T[]> {
|
|
754
|
-
this.validateNoParamOperands();
|
|
758
|
+
async execute(ctx: OrmSession, options?: ParamOperandOptions): Promise<T[]> {
|
|
759
|
+
this.validateNoParamOperands(options);
|
|
755
760
|
if (this.entityConstructor) {
|
|
756
|
-
return this.executeAs(this.entityConstructor, ctx) as unknown as T[];
|
|
761
|
+
return this.executeAs(this.entityConstructor, ctx, options) as unknown as T[];
|
|
757
762
|
}
|
|
758
763
|
const builder = this.ensureDefaultSelection();
|
|
759
|
-
return executeHydrated(ctx, builder) as unknown as T[];
|
|
764
|
+
return executeHydrated(ctx, builder, options) as unknown as T[];
|
|
760
765
|
}
|
|
761
766
|
|
|
762
767
|
/**
|
|
@@ -770,10 +775,10 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
770
775
|
* // rows is EntityInstance<UserTable>[] (plain objects)
|
|
771
776
|
* rows[0] instanceof User; // false
|
|
772
777
|
*/
|
|
773
|
-
async executePlain(ctx: OrmSession): Promise<EntityInstance<TTable>[]> {
|
|
774
|
-
this.validateNoParamOperands();
|
|
778
|
+
async executePlain(ctx: OrmSession, options?: ParamOperandOptions): Promise<EntityInstance<TTable>[]> {
|
|
779
|
+
this.validateNoParamOperands(options);
|
|
775
780
|
const builder = this.ensureDefaultSelection();
|
|
776
|
-
const rows = await executeHydratedPlain(ctx, builder);
|
|
781
|
+
const rows = await executeHydratedPlain(ctx, builder, options);
|
|
777
782
|
return rows as EntityInstance<TTable>[];
|
|
778
783
|
}
|
|
779
784
|
|
|
@@ -793,11 +798,12 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
793
798
|
*/
|
|
794
799
|
async executeAs<TEntity extends object>(
|
|
795
800
|
entityClass: EntityConstructor<TEntity>,
|
|
796
|
-
ctx: OrmSession
|
|
801
|
+
ctx: OrmSession,
|
|
802
|
+
options?: ParamOperandOptions
|
|
797
803
|
): Promise<TEntity[]> {
|
|
798
|
-
this.validateNoParamOperands();
|
|
804
|
+
this.validateNoParamOperands(options);
|
|
799
805
|
const builder = this.ensureDefaultSelection();
|
|
800
|
-
const results = await executeHydrated(ctx, builder);
|
|
806
|
+
const results = await executeHydrated(ctx, builder, options);
|
|
801
807
|
return materializeAs(entityClass, results as unknown as Record<string, unknown>[]);
|
|
802
808
|
}
|
|
803
809
|
|
|
@@ -807,9 +813,9 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
807
813
|
* @example
|
|
808
814
|
* const total = await qb.count(session);
|
|
809
815
|
*/
|
|
810
|
-
async count(session: OrmSession): Promise<number> {
|
|
811
|
-
this.validateNoParamOperands();
|
|
812
|
-
return executeCount(this.context, this.env, session);
|
|
816
|
+
async count(session: OrmSession, options?: ParamOperandOptions): Promise<number> {
|
|
817
|
+
this.validateNoParamOperands(options);
|
|
818
|
+
return executeCount(this.context, this.env, session, options);
|
|
813
819
|
}
|
|
814
820
|
|
|
815
821
|
/**
|
|
@@ -820,11 +826,11 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
820
826
|
*/
|
|
821
827
|
async executePaged(
|
|
822
828
|
session: OrmSession,
|
|
823
|
-
options: { page: number; pageSize: number }
|
|
829
|
+
options: { page: number; pageSize: number } & ParamOperandOptions
|
|
824
830
|
): Promise<PaginatedResult<T>> {
|
|
825
|
-
this.validateNoParamOperands();
|
|
831
|
+
this.validateNoParamOperands(options);
|
|
826
832
|
const builder = this.ensureDefaultSelection();
|
|
827
|
-
return executePagedQuery(builder, session, options, sess => builder.count(sess));
|
|
833
|
+
return executePagedQuery(builder, session, options, sess => builder.count(sess, options), options);
|
|
828
834
|
}
|
|
829
835
|
|
|
830
836
|
/**
|
|
@@ -837,10 +843,10 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
837
843
|
* const hydCtx = new HydrationContext();
|
|
838
844
|
* const users = await qb.executeWithContexts(execCtx, hydCtx);
|
|
839
845
|
*/
|
|
840
|
-
async executeWithContexts(execCtx: ExecutionContext, hydCtx: HydrationContext): Promise<T[]> {
|
|
841
|
-
this.validateNoParamOperands();
|
|
846
|
+
async executeWithContexts(execCtx: ExecutionContext, hydCtx: HydrationContext, options?: ParamOperandOptions): Promise<T[]> {
|
|
847
|
+
this.validateNoParamOperands(options);
|
|
842
848
|
const builder = this.ensureDefaultSelection();
|
|
843
|
-
const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
|
|
849
|
+
const results = await executeHydratedWithContexts(execCtx, hydCtx, builder, options);
|
|
844
850
|
if (this.entityConstructor) {
|
|
845
851
|
return materializeAs(this.entityConstructor, results as unknown as Record<string, unknown>[]) as unknown as T[];
|
|
846
852
|
}
|
|
@@ -1109,10 +1115,18 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
1109
1115
|
* .compile('postgres');
|
|
1110
1116
|
* console.log(compiled.sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
|
|
1111
1117
|
*/
|
|
1112
|
-
compile(dialect: SelectDialectInput): CompiledQuery {
|
|
1113
|
-
const resolved = resolveDialectInput(dialect);
|
|
1114
|
-
|
|
1115
|
-
|
|
1118
|
+
compile(dialect: SelectDialectInput, options?: ParamOperandOptions): CompiledQuery {
|
|
1119
|
+
const resolved = resolveDialectInput(dialect);
|
|
1120
|
+
const ast = this.getAST();
|
|
1121
|
+
if (!options?.allowParamOperands) {
|
|
1122
|
+
const paramName = findFirstParamOperandName(ast);
|
|
1123
|
+
if (paramName) {
|
|
1124
|
+
throw new Error(`Cannot compile query containing Param operand "${paramName}". Param proxies are only for schema generation (getSchema()). If you need real parameters, use literal values.`);
|
|
1125
|
+
}
|
|
1126
|
+
return resolved.compileSelect(ast);
|
|
1127
|
+
}
|
|
1128
|
+
return resolved.compileSelectWithOptions(ast, { allowParams: true });
|
|
1129
|
+
}
|
|
1116
1130
|
|
|
1117
1131
|
/**
|
|
1118
1132
|
* Converts the query to SQL string for a specific dialect
|
|
@@ -1124,9 +1138,9 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
1124
1138
|
* .toSql('postgres');
|
|
1125
1139
|
* console.log(sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
|
|
1126
1140
|
*/
|
|
1127
|
-
toSql(dialect: SelectDialectInput): string {
|
|
1128
|
-
return this.compile(dialect).sql;
|
|
1129
|
-
}
|
|
1141
|
+
toSql(dialect: SelectDialectInput, options?: ParamOperandOptions): string {
|
|
1142
|
+
return this.compile(dialect, options).sql;
|
|
1143
|
+
}
|
|
1130
1144
|
|
|
1131
1145
|
/**
|
|
1132
1146
|
* Gets hydration plan for query
|