metal-orm 1.0.85 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metal-orm",
3
- "version": "1.0.85",
3
+ "version": "1.0.86",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "engines": {
@@ -1,14 +1,19 @@
1
1
  import type { SelectQueryNode } from './query.js';
2
2
  import { visitSelectQuery } from './query-visitor.js';
3
3
 
4
- export const hasParamOperandsInQuery = (ast: SelectQueryNode): boolean => {
5
- let hasParams = false;
4
+ export const findFirstParamOperandName = (ast: SelectQueryNode): string | undefined => {
5
+ let name: string | undefined;
6
6
 
7
7
  visitSelectQuery(ast, {
8
- visitParam: () => {
9
- hasParams = true;
8
+ visitParam: (node) => {
9
+ if (!name) {
10
+ name = node.name;
11
+ }
10
12
  }
11
13
  });
12
14
 
13
- return hasParams;
15
+ return name;
14
16
  };
17
+
18
+ export const hasParamOperandsInQuery = (ast: SelectQueryNode): boolean =>
19
+ !!findFirstParamOperandName(ast);
@@ -21,6 +21,7 @@ import {
21
21
  BitwiseExpressionNode,
22
22
  ParamNode
23
23
  } from './expression-nodes.js';
24
+ import type { SelectQueryNode } from './query.js';
24
25
 
25
26
  /**
26
27
  * Visitor for expression nodes
@@ -34,6 +35,8 @@ export interface ExpressionVisitor<R> {
34
35
  visitBetweenExpression?(node: BetweenExpressionNode): R;
35
36
  visitArithmeticExpression?(node: ArithmeticExpressionNode): R;
36
37
  visitBitwiseExpression?(node: BitwiseExpressionNode): R;
38
+ visitOperand?(node: OperandNode): R;
39
+ visitSelectQuery?(node: SelectQueryNode): R;
37
40
  otherwise?(node: ExpressionNode): R;
38
41
  }
39
42
 
@@ -50,6 +53,10 @@ export interface OperandVisitor<R> {
50
53
  visitCaseExpression?(node: CaseExpressionNode): R;
51
54
  visitCast?(node: CastExpressionNode): R;
52
55
  visitWindowFunction?(node: WindowFunctionNode): R;
56
+ visitArithmeticExpression?(node: ArithmeticExpressionNode): R;
57
+ visitBitwiseExpression?(node: BitwiseExpressionNode): R;
58
+ visitExpression?(node: ExpressionNode): R;
59
+ visitSelectQuery?(node: SelectQueryNode): R;
53
60
  visitCollate?(node: CollateExpressionNode): R;
54
61
  visitAliasRef?(node: AliasRefNode): R;
55
62
  otherwise?(node: OperandNode): R;
@@ -111,6 +118,12 @@ export const registerOperandDispatcher = (type: string, dispatcher: OperandDispa
111
118
  operandRegistry = operandRegistry.register(type, dispatcher);
112
119
  };
113
120
 
121
+ export const hasExpressionDispatcher = (type: string): boolean =>
122
+ expressionRegistry.get(type) !== undefined;
123
+
124
+ export const hasOperandDispatcher = (type: string): boolean =>
125
+ operandRegistry.get(type) !== undefined;
126
+
114
127
  /**
115
128
  * Clears all registered dispatchers. Primarily for tests.
116
129
  */
@@ -225,6 +238,12 @@ export const visitOperand = <R>(node: OperandNode, visitor: OperandVisitor<R>):
225
238
  case 'Collate':
226
239
  if (visitor.visitCollate) return visitor.visitCollate(node as CollateExpressionNode);
227
240
  break;
241
+ case 'ArithmeticExpression':
242
+ if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node as ArithmeticExpressionNode);
243
+ break;
244
+ case 'BitwiseExpression':
245
+ if (visitor.visitBitwiseExpression) return visitor.visitBitwiseExpression(node as BitwiseExpressionNode);
246
+ break;
228
247
  default:
229
248
  break;
230
249
  }
@@ -15,6 +15,13 @@ import type {
15
15
  ParamNode
16
16
  } from './expression-nodes.js';
17
17
  import { isOperandNode } from './expression-nodes.js';
18
+ import {
19
+ hasOperandDispatcher,
20
+ type ExpressionVisitor,
21
+ type OperandVisitor,
22
+ visitExpression,
23
+ visitOperand
24
+ } from './expression-visitor.js';
18
25
 
19
26
  export interface SelectQueryVisitor {
20
27
  visitSelectQuery?(node: SelectQueryNode): void;
@@ -43,142 +50,181 @@ const getNodeType = (value: unknown): string | undefined => {
43
50
  return undefined;
44
51
  };
45
52
 
46
- const visitOrderingTerm = (term: OrderingTerm, visitor: SelectQueryVisitor): void => {
47
- if (isOperandNode(term)) {
48
- visitOperandNode(term, visitor);
49
- return;
50
- }
51
- visitExpressionNode(term as ExpressionNode, visitor);
52
- };
53
+ export const visitSelectQuery = (ast: SelectQueryNode, visitor: SelectQueryVisitor): void => {
54
+ const visitExpressionNode = (node: ExpressionNode): void => {
55
+ visitExpression(node, expressionVisitor);
56
+ };
53
57
 
54
- const visitOrderByNode = (node: OrderByNode, visitor: SelectQueryVisitor): void => {
55
- visitor.visitOrderBy?.(node);
56
- visitOrderingTerm(node.term, visitor);
57
- };
58
+ const visitOperandNode = (node: OperandNode): void => {
59
+ visitOperand(node, operandVisitor);
60
+ };
58
61
 
59
- const visitTableSource = (source: TableSourceNode, visitor: SelectQueryVisitor): void => {
60
- visitor.visitTableSource?.(source);
61
- if (source.type === 'DerivedTable') {
62
- visitor.visitDerivedTable?.(source);
63
- visitSelectQuery(source.query, visitor);
64
- return;
65
- }
66
- if (source.type === 'FunctionTable') {
67
- visitor.visitFunctionTable?.(source);
68
- source.args?.forEach(arg => visitOperandNode(arg, visitor));
69
- }
70
- };
71
-
72
- const visitExpressionNode = (node: ExpressionNode, visitor: SelectQueryVisitor): void => {
73
- visitor.visitExpression?.(node);
74
- const type = getNodeType(node);
75
- if (!type) return;
76
- switch (type) {
77
- case 'BinaryExpression':
78
- visitOperandNode(node.left, visitor);
79
- visitOperandNode(node.right, visitor);
80
- if (node.escape) {
81
- visitOperandNode(node.escape, visitor);
82
- }
62
+ const visitOrderingTerm = (term: OrderingTerm): void => {
63
+ if (!term || typeof term !== 'object') return;
64
+ if (isOperandNode(term)) {
65
+ visitOperandNode(term);
83
66
  return;
84
- case 'LogicalExpression':
85
- node.operands.forEach(operand => visitExpressionNode(operand, visitor));
67
+ }
68
+ const type = getNodeType(term);
69
+ if (type && hasOperandDispatcher(type)) {
70
+ visitOperandNode(term as unknown as OperandNode);
86
71
  return;
87
- case 'NullExpression':
88
- visitOperandNode(node.left, visitor);
72
+ }
73
+ if (type) {
74
+ visitExpressionNode(term as ExpressionNode);
75
+ }
76
+ };
77
+
78
+ const visitOrderByNode = (node: OrderByNode): void => {
79
+ visitor.visitOrderBy?.(node);
80
+ visitOrderingTerm(node.term);
81
+ };
82
+
83
+ const visitTableSource = (source: TableSourceNode): void => {
84
+ visitor.visitTableSource?.(source);
85
+ if (source.type === 'DerivedTable') {
86
+ visitor.visitDerivedTable?.(source);
87
+ visitSelectQuery(source.query, visitor);
89
88
  return;
90
- case 'InExpression':
91
- visitOperandNode(node.left, visitor);
89
+ }
90
+ if (source.type === 'FunctionTable') {
91
+ visitor.visitFunctionTable?.(source);
92
+ source.args?.forEach(arg => visitOperandNode(arg));
93
+ }
94
+ };
95
+
96
+ const expressionVisitor: ExpressionVisitor<void> = {
97
+ visitBinaryExpression: (node) => {
98
+ visitor.visitExpression?.(node);
99
+ visitOperandNode(node.left);
100
+ visitOperandNode(node.right);
101
+ if (node.escape) {
102
+ visitOperandNode(node.escape);
103
+ }
104
+ },
105
+ visitLogicalExpression: (node) => {
106
+ visitor.visitExpression?.(node);
107
+ node.operands.forEach(operand => visitExpressionNode(operand));
108
+ },
109
+ visitNullExpression: (node) => {
110
+ visitor.visitExpression?.(node);
111
+ visitOperandNode(node.left);
112
+ },
113
+ visitInExpression: (node) => {
114
+ visitor.visitExpression?.(node);
115
+ visitOperandNode(node.left);
92
116
  if (Array.isArray(node.right)) {
93
- node.right.forEach(operand => visitOperandNode(operand, visitor));
117
+ node.right.forEach(operand => visitOperandNode(operand));
94
118
  } else {
95
- visitOperandNode(node.right, visitor);
119
+ visitOperandNode(node.right);
96
120
  }
97
- return;
98
- case 'ExistsExpression':
121
+ },
122
+ visitExistsExpression: (node) => {
123
+ visitor.visitExpression?.(node);
99
124
  visitSelectQuery(node.subquery, visitor);
100
- return;
101
- case 'BetweenExpression':
102
- visitOperandNode(node.left, visitor);
103
- visitOperandNode(node.lower, visitor);
104
- visitOperandNode(node.upper, visitor);
105
- return;
106
- case 'ArithmeticExpression':
107
- visitOperandNode(node.left, visitor);
108
- visitOperandNode(node.right, visitor);
109
- return;
110
- case 'BitwiseExpression':
111
- visitOperandNode(node.left, visitor);
112
- visitOperandNode(node.right, visitor);
113
- return;
114
- default: {
115
- return;
125
+ },
126
+ visitBetweenExpression: (node) => {
127
+ visitor.visitExpression?.(node);
128
+ visitOperandNode(node.left);
129
+ visitOperandNode(node.lower);
130
+ visitOperandNode(node.upper);
131
+ },
132
+ visitArithmeticExpression: (node) => {
133
+ visitor.visitExpression?.(node);
134
+ visitOperandNode(node.left);
135
+ visitOperandNode(node.right);
136
+ },
137
+ visitBitwiseExpression: (node) => {
138
+ visitor.visitExpression?.(node);
139
+ visitOperandNode(node.left);
140
+ visitOperandNode(node.right);
141
+ },
142
+ visitOperand: (node) => {
143
+ visitOperandNode(node);
144
+ },
145
+ visitSelectQuery: (node) => {
146
+ visitSelectQuery(node, visitor);
147
+ },
148
+ otherwise: (node) => {
149
+ visitor.visitExpression?.(node);
116
150
  }
117
- }
118
- };
151
+ };
119
152
 
120
- const visitOperandNode = (node: OperandNode, visitor: SelectQueryVisitor): void => {
121
- visitor.visitOperand?.(node);
122
- const type = getNodeType(node);
123
- if (type === 'Param') {
124
- visitor.visitParam?.(node);
125
- }
126
- if (!type) return;
127
- switch (type) {
128
- case 'Column':
129
- case 'Literal':
130
- case 'Param':
131
- case 'AliasRef':
132
- return;
133
- case 'Function':
134
- node.args?.forEach(arg => visitOperandNode(arg, visitor));
135
- node.orderBy?.forEach(order => visitOrderByNode(order, visitor));
153
+ const operandVisitor: OperandVisitor<void> = {
154
+ visitColumn: (node) => {
155
+ visitor.visitOperand?.(node);
156
+ },
157
+ visitLiteral: (node) => {
158
+ visitor.visitOperand?.(node);
159
+ },
160
+ visitParam: (node) => {
161
+ visitor.visitOperand?.(node);
162
+ visitor.visitParam?.(node);
163
+ },
164
+ visitFunction: (node) => {
165
+ visitor.visitOperand?.(node);
166
+ node.args?.forEach(arg => visitOperandNode(arg));
167
+ node.orderBy?.forEach(order => visitOrderByNode(order));
136
168
  if (node.separator) {
137
- visitOperandNode(node.separator, visitor);
169
+ visitOperandNode(node.separator);
138
170
  }
139
- return;
140
- case 'JsonPath':
141
- visitOperandNode(node.column, visitor);
142
- return;
143
- case 'ScalarSubquery':
171
+ },
172
+ visitJsonPath: (node) => {
173
+ visitor.visitOperand?.(node);
174
+ visitOperandNode(node.column);
175
+ },
176
+ visitScalarSubquery: (node) => {
177
+ visitor.visitOperand?.(node);
144
178
  visitSelectQuery(node.query, visitor);
145
- return;
146
- case 'CaseExpression':
179
+ },
180
+ visitCaseExpression: (node) => {
181
+ visitor.visitOperand?.(node);
147
182
  node.conditions.forEach(cond => {
148
- visitExpressionNode(cond.when, visitor);
149
- visitOperandNode(cond.then, visitor);
183
+ visitExpressionNode(cond.when);
184
+ visitOperandNode(cond.then);
150
185
  });
151
186
  if (node.else) {
152
- visitOperandNode(node.else, visitor);
187
+ visitOperandNode(node.else);
153
188
  }
154
- return;
155
- case 'Cast':
156
- visitOperandNode(node.expression, visitor);
157
- return;
158
- case 'WindowFunction':
159
- node.args?.forEach(arg => visitOperandNode(arg, visitor));
160
- node.partitionBy?.forEach(term => visitOperandNode(term, visitor));
161
- node.orderBy?.forEach(order => visitOrderByNode(order, visitor));
162
- return;
163
- case 'ArithmeticExpression':
164
- visitOperandNode(node.left, visitor);
165
- visitOperandNode(node.right, visitor);
166
- return;
167
- case 'BitwiseExpression':
168
- visitOperandNode(node.left, visitor);
169
- visitOperandNode(node.right, visitor);
170
- return;
171
- case 'Collate':
172
- visitOperandNode(node.expression, visitor);
173
- return;
174
- default: {
175
- const _exhaustive: never = node;
176
- return _exhaustive;
189
+ },
190
+ visitCast: (node) => {
191
+ visitor.visitOperand?.(node);
192
+ visitOperandNode(node.expression);
193
+ },
194
+ visitWindowFunction: (node) => {
195
+ visitor.visitOperand?.(node);
196
+ node.args?.forEach(arg => visitOperandNode(arg));
197
+ node.partitionBy?.forEach(term => visitOperandNode(term));
198
+ node.orderBy?.forEach(order => visitOrderByNode(order));
199
+ },
200
+ visitArithmeticExpression: (node) => {
201
+ visitor.visitOperand?.(node);
202
+ visitOperandNode(node.left);
203
+ visitOperandNode(node.right);
204
+ },
205
+ visitBitwiseExpression: (node) => {
206
+ visitor.visitOperand?.(node);
207
+ visitOperandNode(node.left);
208
+ visitOperandNode(node.right);
209
+ },
210
+ visitExpression: (node) => {
211
+ visitExpressionNode(node);
212
+ },
213
+ visitSelectQuery: (node) => {
214
+ visitSelectQuery(node, visitor);
215
+ },
216
+ visitCollate: (node) => {
217
+ visitor.visitOperand?.(node);
218
+ visitOperandNode(node.expression);
219
+ },
220
+ visitAliasRef: (node) => {
221
+ visitor.visitOperand?.(node);
222
+ },
223
+ otherwise: (node) => {
224
+ visitor.visitOperand?.(node);
177
225
  }
178
- }
179
- };
226
+ };
180
227
 
181
- export const visitSelectQuery = (ast: SelectQueryNode, visitor: SelectQueryVisitor): void => {
182
228
  visitor.visitSelectQuery?.(ast);
183
229
 
184
230
  if (ast.ctes) {
@@ -188,36 +234,36 @@ export const visitSelectQuery = (ast: SelectQueryNode, visitor: SelectQueryVisit
188
234
  }
189
235
  }
190
236
 
191
- visitTableSource(ast.from, visitor);
237
+ visitTableSource(ast.from);
192
238
 
193
239
  ast.columns?.forEach(col => {
194
- visitOperandNode(col as OperandNode, visitor);
240
+ visitOperandNode(col as OperandNode);
195
241
  });
196
242
 
197
243
  ast.joins?.forEach(join => {
198
244
  visitor.visitJoin?.(join);
199
- visitTableSource(join.table, visitor);
200
- visitExpressionNode(join.condition, visitor);
245
+ visitTableSource(join.table);
246
+ visitExpressionNode(join.condition);
201
247
  });
202
248
 
203
249
  if (ast.where) {
204
- visitExpressionNode(ast.where, visitor);
250
+ visitExpressionNode(ast.where);
205
251
  }
206
252
 
207
253
  ast.groupBy?.forEach(term => {
208
- visitOrderingTerm(term, visitor);
254
+ visitOrderingTerm(term);
209
255
  });
210
256
 
211
257
  if (ast.having) {
212
- visitExpressionNode(ast.having, visitor);
258
+ visitExpressionNode(ast.having);
213
259
  }
214
260
 
215
261
  ast.orderBy?.forEach(order => {
216
- visitOrderByNode(order, visitor);
262
+ visitOrderByNode(order);
217
263
  });
218
264
 
219
265
  ast.distinct?.forEach(col => {
220
- visitOperandNode(col, visitor);
266
+ visitOperandNode(col);
221
267
  });
222
268
 
223
269
  ast.setOps?.forEach(op => {
@@ -22,9 +22,13 @@ import {
22
22
  loadBelongsToManyRelation
23
23
  } from './lazy-batch.js';
24
24
 
25
- type Row = Record<string, unknown>;
26
-
27
- const flattenResults = (results: { columns: string[]; values: unknown[][] }[]): Row[] => {
25
+ type Row = Record<string, unknown>;
26
+
27
+ type ParamOperandOptions = {
28
+ allowParamOperands?: boolean;
29
+ };
30
+
31
+ const flattenResults = (results: { columns: string[]; values: unknown[][] }[]): Row[] => {
28
32
  const rows: Row[] = [];
29
33
  for (const result of results) {
30
34
  const { columns, values } = result;
@@ -39,13 +43,16 @@ const flattenResults = (results: { columns: string[]; values: unknown[][] }[]):
39
43
  return rows;
40
44
  };
41
45
 
42
- const executeWithContexts = async <TTable extends TableDef>(
43
- execCtx: ExecutionContext,
44
- entityCtx: EntityContext,
45
- qb: SelectQueryBuilder<unknown, TTable>
46
- ): Promise<EntityInstance<TTable>[]> => {
47
- const ast = qb.getAST();
48
- const compiled = execCtx.dialect.compileSelect(ast);
46
+ const executeWithContexts = async <TTable extends TableDef>(
47
+ execCtx: ExecutionContext,
48
+ entityCtx: EntityContext,
49
+ qb: SelectQueryBuilder<unknown, TTable>,
50
+ options?: ParamOperandOptions
51
+ ): Promise<EntityInstance<TTable>[]> => {
52
+ const ast = qb.getAST();
53
+ const compiled = options?.allowParamOperands
54
+ ? execCtx.dialect.compileSelectWithOptions(ast, { allowParams: true })
55
+ : execCtx.dialect.compileSelect(ast);
49
56
  const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
50
57
  const rows = flattenResults(executed);
51
58
  const lazyRelations = qb.getLazyRelations() as RelationKey<TTable>[];
@@ -66,13 +73,16 @@ const executeWithContexts = async <TTable extends TableDef>(
66
73
  return entities;
67
74
  };
68
75
 
69
- const executePlainWithContexts = async <TTable extends TableDef>(
70
- execCtx: ExecutionContext,
71
- qb: SelectQueryBuilder<unknown, TTable>
72
- ): Promise<Record<string, unknown>[]> => {
73
- const ast = qb.getAST();
74
- const compiled = execCtx.dialect.compileSelect(ast);
75
- const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
76
+ const executePlainWithContexts = async <TTable extends TableDef>(
77
+ execCtx: ExecutionContext,
78
+ qb: SelectQueryBuilder<unknown, TTable>,
79
+ options?: ParamOperandOptions
80
+ ): Promise<Record<string, unknown>[]> => {
81
+ const ast = qb.getAST();
82
+ const compiled = options?.allowParamOperands
83
+ ? execCtx.dialect.compileSelectWithOptions(ast, { allowParams: true })
84
+ : execCtx.dialect.compileSelect(ast);
85
+ const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
76
86
  const rows = flattenResults(executed);
77
87
 
78
88
  if (ast.setOps && ast.setOps.length > 0) {
@@ -89,12 +99,13 @@ const executePlainWithContexts = async <TTable extends TableDef>(
89
99
  * @param qb - The select query builder
90
100
  * @returns Promise resolving to array of entity instances
91
101
  */
92
- export async function executeHydrated<TTable extends TableDef>(
93
- session: OrmSession,
94
- qb: SelectQueryBuilder<unknown, TTable>
95
- ): Promise<EntityInstance<TTable>[]> {
96
- return executeWithContexts(session.getExecutionContext(), session, qb);
97
- }
102
+ export async function executeHydrated<TTable extends TableDef>(
103
+ session: OrmSession,
104
+ qb: SelectQueryBuilder<unknown, TTable>,
105
+ options?: ParamOperandOptions
106
+ ): Promise<EntityInstance<TTable>[]> {
107
+ return executeWithContexts(session.getExecutionContext(), session, qb, options);
108
+ }
98
109
 
99
110
  /**
100
111
  * Executes a hydrated query and returns plain row objects (no entity proxies).
@@ -103,12 +114,13 @@ export async function executeHydrated<TTable extends TableDef>(
103
114
  * @param qb - The select query builder
104
115
  * @returns Promise resolving to array of plain row objects
105
116
  */
106
- export async function executeHydratedPlain<TTable extends TableDef>(
107
- session: OrmSession,
108
- qb: SelectQueryBuilder<unknown, TTable>
109
- ): Promise<Record<string, unknown>[]> {
110
- return executePlainWithContexts(session.getExecutionContext(), qb);
111
- }
117
+ export async function executeHydratedPlain<TTable extends TableDef>(
118
+ session: OrmSession,
119
+ qb: SelectQueryBuilder<unknown, TTable>,
120
+ options?: ParamOperandOptions
121
+ ): Promise<Record<string, unknown>[]> {
122
+ return executePlainWithContexts(session.getExecutionContext(), qb, options);
123
+ }
112
124
 
113
125
  /**
114
126
  * Executes a hydrated query using execution and hydration contexts.
@@ -118,17 +130,18 @@ export async function executeHydratedPlain<TTable extends TableDef>(
118
130
  * @param qb - The select query builder
119
131
  * @returns Promise resolving to array of entity instances
120
132
  */
121
- export async function executeHydratedWithContexts<TTable extends TableDef>(
122
- execCtx: ExecutionContext,
123
- hydCtx: HydrationContext,
124
- qb: SelectQueryBuilder<unknown, TTable>
125
- ): Promise<EntityInstance<TTable>[]> {
126
- const entityCtx = hydCtx.entityContext;
127
- if (!entityCtx) {
128
- throw new Error('Hydration context is missing an EntityContext');
129
- }
130
- return executeWithContexts(execCtx, entityCtx, qb);
131
- }
133
+ export async function executeHydratedWithContexts<TTable extends TableDef>(
134
+ execCtx: ExecutionContext,
135
+ hydCtx: HydrationContext,
136
+ qb: SelectQueryBuilder<unknown, TTable>,
137
+ options?: ParamOperandOptions
138
+ ): Promise<EntityInstance<TTable>[]> {
139
+ const entityCtx = hydCtx.entityContext;
140
+ if (!entityCtx) {
141
+ throw new Error('Hydration context is missing an EntityContext');
142
+ }
143
+ return executeWithContexts(execCtx, entityCtx, qb, options);
144
+ }
132
145
 
133
146
  /**
134
147
  * Executes a hydrated query using execution context and returns plain row objects.
@@ -137,12 +150,13 @@ export async function executeHydratedWithContexts<TTable extends TableDef>(
137
150
  * @param qb - The select query builder
138
151
  * @returns Promise resolving to array of plain row objects
139
152
  */
140
- export async function executeHydratedPlainWithContexts<TTable extends TableDef>(
141
- execCtx: ExecutionContext,
142
- qb: SelectQueryBuilder<unknown, TTable>
143
- ): Promise<Record<string, unknown>[]> {
144
- return executePlainWithContexts(execCtx, qb);
145
- }
153
+ export async function executeHydratedPlainWithContexts<TTable extends TableDef>(
154
+ execCtx: ExecutionContext,
155
+ qb: SelectQueryBuilder<unknown, TTable>,
156
+ options?: ParamOperandOptions
157
+ ): Promise<Record<string, unknown>[]> {
158
+ return executePlainWithContexts(execCtx, qb, options);
159
+ }
146
160
 
147
161
  const loadLazyRelationsForTable = async <TTable extends TableDef>(
148
162
  ctx: EntityContext,