metal-orm 1.0.89 → 1.0.91
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 +2968 -2983
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +784 -251
- package/dist/index.d.ts +784 -251
- package/dist/index.js +2913 -2975
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/src/codegen/typescript.ts +29 -40
- package/src/core/ast/expression-builders.ts +34 -53
- package/src/core/ast/expression-nodes.ts +51 -72
- package/src/core/ast/expression-visitor.ts +219 -252
- package/src/core/ast/expression.ts +20 -21
- package/src/core/ddl/introspect/utils.ts +45 -45
- package/src/core/dialect/abstract.ts +55 -81
- package/src/core/execution/db-executor.ts +4 -5
- package/src/core/execution/executors/mysql-executor.ts +7 -9
- package/src/decorators/bootstrap.ts +29 -26
- package/src/dto/apply-filter.ts +279 -0
- package/src/dto/dto-types.ts +229 -0
- package/src/dto/filter-types.ts +193 -0
- package/src/dto/index.ts +97 -0
- package/src/dto/openapi/generators/base.ts +29 -0
- package/src/dto/openapi/generators/column.ts +34 -0
- package/src/dto/openapi/generators/dto.ts +94 -0
- package/src/dto/openapi/generators/filter.ts +74 -0
- package/src/dto/openapi/generators/nested-dto.ts +532 -0
- package/src/dto/openapi/generators/pagination.ts +111 -0
- package/src/dto/openapi/generators/relation-filter.ts +210 -0
- package/src/dto/openapi/index.ts +17 -0
- package/src/dto/openapi/type-mappings.ts +191 -0
- package/src/dto/openapi/types.ts +90 -0
- package/src/dto/openapi/utilities.ts +45 -0
- package/src/dto/pagination-utils.ts +150 -0
- package/src/dto/transform.ts +197 -0
- package/src/index.ts +5 -3
- package/src/orm/entity-context.ts +9 -9
- package/src/orm/entity.ts +74 -74
- package/src/orm/orm-session.ts +159 -159
- package/src/orm/relation-change-processor.ts +3 -3
- package/src/orm/runtime-types.ts +5 -5
- package/src/orm/unit-of-work.ts +13 -25
- package/src/query-builder/query-ast-service.ts +287 -300
- package/src/query-builder/relation-filter-utils.ts +159 -160
- package/src/query-builder/select.ts +137 -192
- package/src/schema/column-types.ts +4 -4
- package/src/schema/types.ts +5 -1
- package/src/core/ast/ast-validation.ts +0 -19
- package/src/core/ast/param-proxy.ts +0 -47
- package/src/core/ast/query-visitor.ts +0 -273
- package/src/openapi/index.ts +0 -4
- package/src/openapi/query-parameters.ts +0 -207
- package/src/openapi/schema-extractor-input.ts +0 -193
- package/src/openapi/schema-extractor-output.ts +0 -427
- package/src/openapi/schema-extractor-utils.ts +0 -110
- package/src/openapi/schema-extractor.ts +0 -120
- package/src/openapi/schema-types.ts +0 -187
- package/src/openapi/type-mappers.ts +0 -227
|
@@ -66,9 +66,7 @@ import { SelectProjectionFacet } from './select/projection-facet.js';
|
|
|
66
66
|
import { SelectPredicateFacet } from './select/predicate-facet.js';
|
|
67
67
|
import { SelectCTEFacet } from './select/cte-facet.js';
|
|
68
68
|
import { SelectSetOpFacet } from './select/setop-facet.js';
|
|
69
|
-
import { SelectRelationFacet } from './select/relation-facet.js';
|
|
70
|
-
import { buildFilterParameters, extractSchema, SchemaOptions, OpenApiSchemaBundle } from '../openapi/index.js';
|
|
71
|
-
import { findFirstParamOperandName } from '../core/ast/ast-validation.js';
|
|
69
|
+
import { SelectRelationFacet } from './select/relation-facet.js';
|
|
72
70
|
|
|
73
71
|
type ColumnSelectionValue =
|
|
74
72
|
| ColumnDef
|
|
@@ -82,14 +80,10 @@ type SelectionValueType<TValue> =
|
|
|
82
80
|
TValue extends ColumnDef ? ColumnToTs<TValue> :
|
|
83
81
|
unknown;
|
|
84
82
|
|
|
85
|
-
type SelectionResult<TSelection extends Record<string, ColumnSelectionValue>> = {
|
|
86
|
-
[K in keyof TSelection]: SelectionValueType<TSelection[K]>;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
type ParamOperandCompileOptions = {
|
|
90
|
-
allowParamOperands?: boolean;
|
|
91
|
-
};
|
|
92
|
-
|
|
83
|
+
type SelectionResult<TSelection extends Record<string, ColumnSelectionValue>> = {
|
|
84
|
+
[K in keyof TSelection]: SelectionValueType<TSelection[K]>;
|
|
85
|
+
};
|
|
86
|
+
|
|
93
87
|
type SelectionFromKeys<
|
|
94
88
|
TTable extends TableDef,
|
|
95
89
|
K extends keyof TTable['columns'] & string
|
|
@@ -718,138 +712,120 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
718
712
|
return this.env.table as TTable;
|
|
719
713
|
}
|
|
720
714
|
|
|
721
|
-
/**
|
|
722
|
-
* Ensures that if no columns are selected, all columns from the table are selected by default.
|
|
723
|
-
*/
|
|
724
|
-
private ensureDefaultSelection(): SelectQueryBuilder<T, TTable> {
|
|
725
|
-
const columns = this.context.state.ast.columns;
|
|
726
|
-
if (!columns || columns.length === 0) {
|
|
727
|
-
const columnKeys = Object.keys(this.env.table.columns) as (keyof TTable['columns'] & string)[];
|
|
728
|
-
return this.select(...columnKeys);
|
|
729
|
-
}
|
|
730
|
-
return this;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
/**
|
|
734
|
-
*
|
|
735
|
-
*
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
*
|
|
755
|
-
*
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
*
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
*
|
|
821
|
-
*
|
|
822
|
-
* @example
|
|
823
|
-
* const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
* Executes the query with provided execution and hydration contexts
|
|
836
|
-
* @param execCtx - Execution context
|
|
837
|
-
* @param hydCtx - Hydration context
|
|
838
|
-
* @returns Promise of entity instances
|
|
839
|
-
* @example
|
|
840
|
-
* const execCtx = new ExecutionContext(session);
|
|
841
|
-
* const hydCtx = new HydrationContext();
|
|
842
|
-
* const users = await qb.executeWithContexts(execCtx, hydCtx);
|
|
843
|
-
*/
|
|
844
|
-
async executeWithContexts(execCtx: ExecutionContext, hydCtx: HydrationContext): Promise<T[]> {
|
|
845
|
-
this.validateNoParamOperands();
|
|
846
|
-
const builder = this.ensureDefaultSelection();
|
|
847
|
-
const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
|
|
848
|
-
if (this.entityConstructor) {
|
|
849
|
-
return materializeAs(this.entityConstructor, results as unknown as Record<string, unknown>[]) as unknown as T[];
|
|
850
|
-
}
|
|
851
|
-
return results as unknown as T[];
|
|
852
|
-
}
|
|
715
|
+
/**
|
|
716
|
+
* Ensures that if no columns are selected, all columns from the table are selected by default.
|
|
717
|
+
*/
|
|
718
|
+
private ensureDefaultSelection(): SelectQueryBuilder<T, TTable> {
|
|
719
|
+
const columns = this.context.state.ast.columns;
|
|
720
|
+
if (!columns || columns.length === 0) {
|
|
721
|
+
const columnKeys = Object.keys(this.env.table.columns) as (keyof TTable['columns'] & string)[];
|
|
722
|
+
return this.select(...columnKeys);
|
|
723
|
+
}
|
|
724
|
+
return this;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Executes the query and returns hydrated results.
|
|
729
|
+
* If the builder was created with an entity constructor (e.g. via selectFromEntity),
|
|
730
|
+
* this will automatically return fully materialized entity instances.
|
|
731
|
+
*
|
|
732
|
+
* @param ctx - ORM session context
|
|
733
|
+
* @returns Promise of entity instances (or objects if generic T is not an entity)
|
|
734
|
+
* @example
|
|
735
|
+
* const users = await selectFromEntity(User).execute(session);
|
|
736
|
+
* // users is User[]
|
|
737
|
+
* users[0] instanceof User; // true
|
|
738
|
+
*/
|
|
739
|
+
async execute(ctx: OrmSession): Promise<T[]> {
|
|
740
|
+
if (this.entityConstructor) {
|
|
741
|
+
return this.executeAs(this.entityConstructor, ctx) as unknown as T[];
|
|
742
|
+
}
|
|
743
|
+
const builder = this.ensureDefaultSelection();
|
|
744
|
+
return executeHydrated(ctx, builder) as unknown as T[];
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Executes the query and returns plain row objects (POJOs), ignoring any entity materialization.
|
|
749
|
+
* Use this if you want raw data even when using selectFromEntity.
|
|
750
|
+
*
|
|
751
|
+
* @param ctx - ORM session context
|
|
752
|
+
* @returns Promise of plain entity instances
|
|
753
|
+
* @example
|
|
754
|
+
* const rows = await selectFromEntity(User).executePlain(session);
|
|
755
|
+
* // rows is EntityInstance<UserTable>[] (plain objects)
|
|
756
|
+
* rows[0] instanceof User; // false
|
|
757
|
+
*/
|
|
758
|
+
async executePlain(ctx: OrmSession): Promise<EntityInstance<TTable>[]> {
|
|
759
|
+
const builder = this.ensureDefaultSelection();
|
|
760
|
+
const rows = await executeHydratedPlain(ctx, builder);
|
|
761
|
+
return rows as EntityInstance<TTable>[];
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Executes the query and returns results as real class instances.
|
|
766
|
+
* Unlike execute(), this returns actual instances of the decorated entity class
|
|
767
|
+
* with working methods and proper instanceof checks.
|
|
768
|
+
* @param entityClass - The entity class constructor
|
|
769
|
+
* @param ctx - ORM session context
|
|
770
|
+
* @returns Promise of entity class instances
|
|
771
|
+
* @example
|
|
772
|
+
* const users = await selectFromEntity(User)
|
|
773
|
+
* .include('posts')
|
|
774
|
+
* .executeAs(User, session);
|
|
775
|
+
* users[0] instanceof User; // true!
|
|
776
|
+
* users[0].getFullName(); // works!
|
|
777
|
+
*/
|
|
778
|
+
async executeAs<TEntity extends object>(
|
|
779
|
+
entityClass: EntityConstructor<TEntity>,
|
|
780
|
+
ctx: OrmSession
|
|
781
|
+
): Promise<TEntity[]> {
|
|
782
|
+
const builder = this.ensureDefaultSelection();
|
|
783
|
+
const results = await executeHydrated(ctx, builder);
|
|
784
|
+
return materializeAs(entityClass, results as unknown as Record<string, unknown>[]);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Executes a count query for the current builder without LIMIT/OFFSET clauses.
|
|
789
|
+
*
|
|
790
|
+
* @example
|
|
791
|
+
* const total = await qb.count(session);
|
|
792
|
+
*/
|
|
793
|
+
async count(session: OrmSession): Promise<number> {
|
|
794
|
+
return executeCount(this.context, this.env, session);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Executes the query and returns both the paged items and the total.
|
|
799
|
+
*
|
|
800
|
+
* @example
|
|
801
|
+
* const { items, totalItems, page, pageSize } = await qb.executePaged(session, { page: 1, pageSize: 20 });
|
|
802
|
+
*/
|
|
803
|
+
async executePaged(
|
|
804
|
+
session: OrmSession,
|
|
805
|
+
options: { page: number; pageSize: number }
|
|
806
|
+
): Promise<PaginatedResult<T>> {
|
|
807
|
+
const builder = this.ensureDefaultSelection();
|
|
808
|
+
return executePagedQuery(builder, session, options, sess => builder.count(sess));
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Executes the query with provided execution and hydration contexts
|
|
813
|
+
* @param execCtx - Execution context
|
|
814
|
+
* @param hydCtx - Hydration context
|
|
815
|
+
* @returns Promise of entity instances
|
|
816
|
+
* @example
|
|
817
|
+
* const execCtx = new ExecutionContext(session);
|
|
818
|
+
* const hydCtx = new HydrationContext();
|
|
819
|
+
* const users = await qb.executeWithContexts(execCtx, hydCtx);
|
|
820
|
+
*/
|
|
821
|
+
async executeWithContexts(execCtx: ExecutionContext, hydCtx: HydrationContext): Promise<T[]> {
|
|
822
|
+
const builder = this.ensureDefaultSelection();
|
|
823
|
+
const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
|
|
824
|
+
if (this.entityConstructor) {
|
|
825
|
+
return materializeAs(this.entityConstructor, results as unknown as Record<string, unknown>[]) as unknown as T[];
|
|
826
|
+
}
|
|
827
|
+
return results as unknown as T[];
|
|
828
|
+
}
|
|
853
829
|
|
|
854
830
|
/**
|
|
855
831
|
* Adds a WHERE condition to the query
|
|
@@ -1113,18 +1089,10 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
1113
1089
|
* .compile('postgres');
|
|
1114
1090
|
* console.log(compiled.sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
|
|
1115
1091
|
*/
|
|
1116
|
-
compile(dialect: SelectDialectInput
|
|
1117
|
-
const resolved = resolveDialectInput(dialect);
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
const paramName = findFirstParamOperandName(ast);
|
|
1121
|
-
if (paramName) {
|
|
1122
|
-
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.`);
|
|
1123
|
-
}
|
|
1124
|
-
return resolved.compileSelect(ast);
|
|
1125
|
-
}
|
|
1126
|
-
return resolved.compileSelectWithOptions(ast, { allowParams: true });
|
|
1127
|
-
}
|
|
1092
|
+
compile(dialect: SelectDialectInput): CompiledQuery {
|
|
1093
|
+
const resolved = resolveDialectInput(dialect);
|
|
1094
|
+
return resolved.compileSelect(this.getAST());
|
|
1095
|
+
}
|
|
1128
1096
|
|
|
1129
1097
|
/**
|
|
1130
1098
|
* Converts the query to SQL string for a specific dialect
|
|
@@ -1136,43 +1104,20 @@ export class SelectQueryBuilder<T = EntityInstance<TableDef>, TTable extends Tab
|
|
|
1136
1104
|
* .toSql('postgres');
|
|
1137
1105
|
* console.log(sql); // SELECT "id", "name" FROM "users" WHERE "active" = true
|
|
1138
1106
|
*/
|
|
1139
|
-
toSql(dialect: SelectDialectInput
|
|
1140
|
-
return this.compile(dialect
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
/**
|
|
1144
|
-
* Gets hydration plan for query
|
|
1145
|
-
* @returns Hydration plan or undefined if none exists
|
|
1146
|
-
* @example
|
|
1147
|
-
* const plan = qb.include('posts').getHydrationPlan();
|
|
1148
|
-
* console.log(plan?.relations); // Information about included relations
|
|
1149
|
-
*/
|
|
1150
|
-
getHydrationPlan(): HydrationPlan | undefined {
|
|
1151
|
-
return this.context.hydration.getPlan();
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
/**
|
|
1155
|
-
* Gets OpenAPI 3.1 JSON Schemas for query output and optional input payloads
|
|
1156
|
-
* @param options - Schema generation options
|
|
1157
|
-
* @returns OpenAPI 3.1 JSON Schemas for query output and input payloads
|
|
1158
|
-
* @example
|
|
1159
|
-
* const { output } = qb.select('id', 'title', 'author').getSchema();
|
|
1160
|
-
* console.log(JSON.stringify(output, null, 2));
|
|
1161
|
-
*/
|
|
1162
|
-
getSchema(options?: SchemaOptions): OpenApiSchemaBundle {
|
|
1163
|
-
const plan = this.context.hydration.getPlan();
|
|
1164
|
-
const bundle = extractSchema(this.env.table, plan, this.context.state.ast.columns, options);
|
|
1165
|
-
const parameters = buildFilterParameters(
|
|
1166
|
-
this.env.table,
|
|
1167
|
-
this.context.state.ast.where,
|
|
1168
|
-
this.context.state.ast.from,
|
|
1169
|
-
options ?? {}
|
|
1170
|
-
);
|
|
1171
|
-
if (parameters.length) {
|
|
1172
|
-
return { ...bundle, parameters };
|
|
1173
|
-
}
|
|
1174
|
-
return bundle;
|
|
1175
|
-
}
|
|
1107
|
+
toSql(dialect: SelectDialectInput): string {
|
|
1108
|
+
return this.compile(dialect).sql;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Gets the hydration plan for the query
|
|
1113
|
+
* @returns Hydration plan or undefined if none exists
|
|
1114
|
+
* @example
|
|
1115
|
+
* const plan = qb.include('posts').getHydrationPlan();
|
|
1116
|
+
* console.log(plan?.relations); // Information about included relations
|
|
1117
|
+
*/
|
|
1118
|
+
getHydrationPlan(): HydrationPlan | undefined {
|
|
1119
|
+
return this.context.hydration.getPlan();
|
|
1120
|
+
}
|
|
1176
1121
|
|
|
1177
1122
|
/**
|
|
1178
1123
|
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
@@ -64,7 +64,7 @@ export interface RawDefaultValue {
|
|
|
64
64
|
raw: string;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
export type DefaultValue =
|
|
67
|
+
export type DefaultValue = string | number | boolean | Date | null | RawDefaultValue;
|
|
68
68
|
|
|
69
69
|
export interface ForeignKeyReference {
|
|
70
70
|
/** Target table name */
|
|
@@ -112,7 +112,7 @@ export interface ColumnDef<T extends ColumnType = ColumnType, TRuntime = unknown
|
|
|
112
112
|
/** Column comment/description */
|
|
113
113
|
comment?: string;
|
|
114
114
|
/** Additional arguments for the column type (e.g., VARCHAR length) */
|
|
115
|
-
args?:
|
|
115
|
+
args?: (string | number)[];
|
|
116
116
|
/** Table name this column belongs to (filled at runtime by defineTable) */
|
|
117
117
|
table?: string;
|
|
118
118
|
}
|
|
@@ -240,7 +240,7 @@ export const col = {
|
|
|
240
240
|
* Creates a column definition with a custom SQL type.
|
|
241
241
|
* Useful for dialect-specific types without polluting the standard set.
|
|
242
242
|
*/
|
|
243
|
-
custom: (type: string, opts: { dialect?: string; args?:
|
|
243
|
+
custom: (type: string, opts: { dialect?: string; args?: (string | number)[]; tsType?: unknown } = {}): ColumnDef => ({
|
|
244
244
|
name: '',
|
|
245
245
|
type,
|
|
246
246
|
args: opts.args,
|
|
@@ -274,7 +274,7 @@ export const col = {
|
|
|
274
274
|
/**
|
|
275
275
|
* Sets a default value for the column
|
|
276
276
|
*/
|
|
277
|
-
default: <T extends ColumnType>(def: ColumnDef<T>, value:
|
|
277
|
+
default: <T extends ColumnType>(def: ColumnDef<T>, value: DefaultValue): ColumnDef<T> =>
|
|
278
278
|
({
|
|
279
279
|
...def,
|
|
280
280
|
default: value
|
package/src/schema/types.ts
CHANGED
|
@@ -19,6 +19,10 @@ export type RelationTargetTable<TRel extends RelationDef> =
|
|
|
19
19
|
TRel extends BelongsToManyRelation<infer TTarget, TableDef> ? TTarget :
|
|
20
20
|
never;
|
|
21
21
|
|
|
22
|
+
export type JsonValue = string | number | boolean | null | JsonArray | JsonObject;
|
|
23
|
+
export type JsonArray = Array<JsonValue>;
|
|
24
|
+
export interface JsonObject { [key: string]: JsonValue }
|
|
25
|
+
|
|
22
26
|
type NormalizedColumnType<T extends ColumnDef> = Lowercase<T['type'] & string>;
|
|
23
27
|
|
|
24
28
|
/**
|
|
@@ -30,7 +34,7 @@ export type ColumnToTs<T extends ColumnDef> =
|
|
|
30
34
|
NormalizedColumnType<T> extends 'bigint' ? number | bigint :
|
|
31
35
|
NormalizedColumnType<T> extends 'decimal' | 'float' | 'double' ? number :
|
|
32
36
|
NormalizedColumnType<T> extends 'boolean' ? boolean :
|
|
33
|
-
NormalizedColumnType<T> extends 'json' ?
|
|
37
|
+
NormalizedColumnType<T> extends 'json' ? JsonValue :
|
|
34
38
|
NormalizedColumnType<T> extends 'blob' | 'binary' | 'varbinary' | 'bytea' ? Buffer :
|
|
35
39
|
NormalizedColumnType<T> extends 'date' | 'datetime' | 'timestamp' | 'timestamptz' ? string :
|
|
36
40
|
string
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { SelectQueryNode } from './query.js';
|
|
2
|
-
import { visitSelectQuery } from './query-visitor.js';
|
|
3
|
-
|
|
4
|
-
export const findFirstParamOperandName = (ast: SelectQueryNode): string | undefined => {
|
|
5
|
-
let name: string | undefined;
|
|
6
|
-
|
|
7
|
-
visitSelectQuery(ast, {
|
|
8
|
-
visitParam: (node) => {
|
|
9
|
-
if (!name) {
|
|
10
|
-
name = node.name;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
return name;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const hasParamOperandsInQuery = (ast: SelectQueryNode): boolean =>
|
|
19
|
-
!!findFirstParamOperandName(ast);
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { ParamNode } from './expression-nodes.js';
|
|
2
|
-
|
|
3
|
-
export type ParamProxy = ParamNode & {
|
|
4
|
-
[key: string]: ParamProxy;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export type ParamProxyRoot = {
|
|
8
|
-
[key: string]: ParamProxy;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const buildParamProxy = (name: string): ParamProxy => {
|
|
12
|
-
const target: ParamNode = { type: 'Param', name };
|
|
13
|
-
return new Proxy(target, {
|
|
14
|
-
get(t, prop, receiver) {
|
|
15
|
-
if (prop === 'then') return undefined;
|
|
16
|
-
if (typeof prop === 'symbol') {
|
|
17
|
-
return Reflect.get(t, prop, receiver);
|
|
18
|
-
}
|
|
19
|
-
if (typeof prop === 'string' && prop.startsWith('$')) {
|
|
20
|
-
const trimmed = prop.slice(1);
|
|
21
|
-
const nextName = name ? `${name}.${trimmed}` : trimmed;
|
|
22
|
-
return buildParamProxy(nextName);
|
|
23
|
-
}
|
|
24
|
-
if (prop in t && name === '') {
|
|
25
|
-
return (t as unknown as Record<string, unknown>)[prop];
|
|
26
|
-
}
|
|
27
|
-
const nextName = name ? `${name}.${prop}` : prop;
|
|
28
|
-
return buildParamProxy(nextName);
|
|
29
|
-
}
|
|
30
|
-
}) as ParamProxy;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const createParamProxy = (): ParamProxyRoot => {
|
|
34
|
-
const target: Record<string, unknown> = {};
|
|
35
|
-
return new Proxy(target, {
|
|
36
|
-
get(t, prop, receiver) {
|
|
37
|
-
if (prop === 'then') return undefined;
|
|
38
|
-
if (typeof prop === 'symbol') {
|
|
39
|
-
return Reflect.get(t, prop, receiver);
|
|
40
|
-
}
|
|
41
|
-
if (typeof prop === 'string' && prop.startsWith('$')) {
|
|
42
|
-
return buildParamProxy(prop.slice(1));
|
|
43
|
-
}
|
|
44
|
-
return buildParamProxy(String(prop));
|
|
45
|
-
}
|
|
46
|
-
}) as ParamProxyRoot;
|
|
47
|
-
};
|