@prisma-next/sql-orm-lane 0.3.0-pr.96.1 → 0.3.0-pr.96.3

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.
@@ -4,21 +4,22 @@ import type { SqlContract, SqlStorage } from '@prisma-next/sql-contract/types';
4
4
  import type {
5
5
  BinaryExpr,
6
6
  ExistsExpr,
7
+ Expression,
7
8
  LoweredStatement,
8
- OperationExpr,
9
9
  SelectAst,
10
10
  TableRef,
11
11
  } from '@prisma-next/sql-relational-core/ast';
12
12
  import { compact } from '@prisma-next/sql-relational-core/ast';
13
13
  import type {
14
- AnyColumnBuilder,
14
+ AnyExpressionSource,
15
15
  AnyOrderBuilder,
16
16
  BinaryBuilder,
17
17
  } from '@prisma-next/sql-relational-core/types';
18
18
  import {
19
19
  collectColumnRefs,
20
- getColumnInfo,
21
20
  getColumnMeta,
21
+ isColumnBuilder,
22
+ isExpressionBuilder,
22
23
  isOperationExpr,
23
24
  } from '@prisma-next/sql-relational-core/utils/guards';
24
25
  import type { IncludeState } from '../relations/include-plan';
@@ -35,30 +36,67 @@ export interface MetaBuildArgs {
35
36
  readonly paramCodecs?: Record<string, string>;
36
37
  }
37
38
 
38
- export function buildMeta(args: MetaBuildArgs): PlanMeta {
39
- const refsColumns = new Map<string, { table: string; column: string }>();
40
- const refsTables = new Set<string>([args.table.name]);
41
-
42
- for (const column of args.projection.columns) {
43
- const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
44
- if (operationExpr) {
45
- const allRefs = collectColumnRefs(operationExpr);
46
- for (const ref of allRefs) {
39
+ /**
40
+ * Extracts column references from an ExpressionSource (ColumnBuilder or ExpressionBuilder).
41
+ * Skips entries with empty table or column names (e.g., placeholder columns for includes).
42
+ */
43
+ function collectRefsFromExpressionSource(
44
+ source: AnyExpressionSource,
45
+ refsColumns: Map<string, { table: string; column: string }>,
46
+ ): void {
47
+ if (isExpressionBuilder(source)) {
48
+ const allRefs = collectColumnRefs(source.expr);
49
+ for (const ref of allRefs) {
50
+ // Skip empty table/column (placeholders for includes)
51
+ if (ref.table && ref.column) {
47
52
  refsColumns.set(`${ref.table}.${ref.column}`, {
48
53
  table: ref.table,
49
54
  column: ref.column,
50
55
  });
51
56
  }
52
- } else {
53
- const col = column as unknown as { table?: string; column?: string };
54
- if (col.table && col.column) {
55
- refsColumns.set(`${col.table}.${col.column}`, {
56
- table: col.table,
57
- column: col.column,
58
- });
59
- }
57
+ }
58
+ } else if (isColumnBuilder(source)) {
59
+ const col = source as unknown as { table: string; column: string };
60
+ // Skip empty table/column (placeholders for includes)
61
+ if (col.table && col.column) {
62
+ refsColumns.set(`${col.table}.${col.column}`, {
63
+ table: col.table,
64
+ column: col.column,
65
+ });
60
66
  }
61
67
  }
68
+ }
69
+
70
+ /**
71
+ * Extracts column references from an Expression (AST node).
72
+ */
73
+ function collectRefsFromExpression(
74
+ expr: Expression,
75
+ refsColumns: Map<string, { table: string; column: string }>,
76
+ ): void {
77
+ if (isOperationExpr(expr)) {
78
+ const allRefs = collectColumnRefs(expr);
79
+ for (const ref of allRefs) {
80
+ refsColumns.set(`${ref.table}.${ref.column}`, {
81
+ table: ref.table,
82
+ column: ref.column,
83
+ });
84
+ }
85
+ } else if (expr.kind === 'col') {
86
+ refsColumns.set(`${expr.table}.${expr.column}`, {
87
+ table: expr.table,
88
+ column: expr.column,
89
+ });
90
+ }
91
+ }
92
+
93
+ export function buildMeta(args: MetaBuildArgs): PlanMeta {
94
+ const refsColumns = new Map<string, { table: string; column: string }>();
95
+ const refsTables = new Set<string>([args.table.name]);
96
+
97
+ for (const column of args.projection.columns) {
98
+ collectRefsFromExpressionSource(column, refsColumns);
99
+ }
62
100
 
63
101
  if (args.includes) {
64
102
  for (const include of args.includes) {
@@ -85,32 +123,21 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
85
123
  }
86
124
  }
87
125
  if (include.childWhere) {
88
- const colInfo = getColumnInfo(include.childWhere.left);
89
- refsColumns.set(`${colInfo.table}.${colInfo.column}`, {
90
- table: colInfo.table,
91
- column: colInfo.column,
92
- });
126
+ // childWhere.left is Expression (already converted at builder creation time)
127
+ collectRefsFromExpression(include.childWhere.left, refsColumns);
93
128
  }
94
129
  if (include.childOrderBy) {
95
- const orderBy = include.childOrderBy as unknown as {
96
- expr?: AnyColumnBuilder | OperationExpr;
97
- };
98
- if (orderBy.expr) {
99
- const colInfo = getColumnInfo(orderBy.expr);
100
- refsColumns.set(`${colInfo.table}.${colInfo.column}`, {
101
- table: colInfo.table,
102
- column: colInfo.column,
103
- });
104
- }
130
+ // childOrderBy.expr is Expression (already converted at builder creation time)
131
+ collectRefsFromExpression(include.childOrderBy.expr, refsColumns);
105
132
  }
106
133
  }
107
134
  }
108
135
 
109
136
  if (args.where) {
110
- const whereLeft = args.where.left;
111
- const operationExpr = (whereLeft as { _operationExpr?: OperationExpr })._operationExpr;
112
- if (operationExpr) {
113
- const allRefs = collectColumnRefs(operationExpr);
137
+ // args.where.left is Expression (already converted at builder creation time)
138
+ const leftExpr: Expression = args.where.left;
139
+ if (isOperationExpr(leftExpr)) {
140
+ const allRefs = collectColumnRefs(leftExpr);
114
141
  for (const ref of allRefs) {
115
142
  refsColumns.set(`${ref.table}.${ref.column}`, {
116
143
  table: ref.table,
@@ -118,39 +145,31 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
118
145
  });
119
146
  }
120
147
  } else {
121
- const colBuilder = whereLeft as unknown as { table?: string; column?: string };
122
- if (colBuilder.table && colBuilder.column) {
123
- refsColumns.set(`${colBuilder.table}.${colBuilder.column}`, {
124
- table: colBuilder.table,
125
- column: colBuilder.column,
126
- });
127
- }
148
+ // leftExpr is ColumnRef
149
+ refsColumns.set(`${leftExpr.table}.${leftExpr.column}`, {
150
+ table: leftExpr.table,
151
+ column: leftExpr.column,
152
+ });
128
153
  }
129
154
  }
130
155
 
131
156
  if (args.orderBy) {
132
- const orderBy = args.orderBy as unknown as {
133
- expr?: AnyColumnBuilder | OperationExpr;
134
- };
135
- const orderByExpr = orderBy.expr;
136
- if (orderByExpr) {
137
- if (isOperationExpr(orderByExpr)) {
138
- const allRefs = collectColumnRefs(orderByExpr);
139
- for (const ref of allRefs) {
140
- refsColumns.set(`${ref.table}.${ref.column}`, {
141
- table: ref.table,
142
- column: ref.column,
143
- });
144
- }
145
- } else {
146
- const colBuilder = orderByExpr as unknown as { table?: string; column?: string };
147
- if (colBuilder.table && colBuilder.column) {
148
- refsColumns.set(`${colBuilder.table}.${colBuilder.column}`, {
149
- table: colBuilder.table,
150
- column: colBuilder.column,
151
- });
152
- }
157
+ // args.orderBy.expr is Expression (already converted at builder creation time)
158
+ const orderByExpr: Expression = args.orderBy.expr;
159
+ if (isOperationExpr(orderByExpr)) {
160
+ const allRefs = collectColumnRefs(orderByExpr);
161
+ for (const ref of allRefs) {
162
+ refsColumns.set(`${ref.table}.${ref.column}`, {
163
+ table: ref.table,
164
+ column: ref.column,
165
+ });
153
166
  }
167
+ } else {
168
+ // orderByExpr is ColumnRef
169
+ refsColumns.set(`${orderByExpr.table}.${orderByExpr.column}`, {
170
+ table: orderByExpr.table,
171
+ column: orderByExpr.column,
172
+ });
154
173
  }
155
174
  }
156
175
 
@@ -164,18 +183,14 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
164
183
  if (!column) {
165
184
  throw planInvalid(`Missing column for alias ${alias} at index ${index}`);
166
185
  }
167
- const col = column as unknown as {
168
- table?: string;
169
- column?: string;
170
- _operationExpr?: OperationExpr;
171
- };
186
+ if (isExpressionBuilder(column)) {
187
+ return [alias, `operation:${column.expr.method}`];
188
+ }
189
+ // column is ColumnBuilder
190
+ const col = column as unknown as { table?: string; column?: string };
172
191
  if (!col.table || !col.column) {
173
192
  return [alias, `include:${alias}`];
174
193
  }
175
- const operationExpr = col._operationExpr;
176
- if (operationExpr) {
177
- return [alias, `operation:${operationExpr.method}`];
178
- }
179
194
  return [alias, `${col.table}.${col.column}`];
180
195
  }),
181
196
  );
@@ -190,8 +205,8 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
190
205
  if (!col) {
191
206
  continue;
192
207
  }
193
- const operationExpr = (col as { _operationExpr?: OperationExpr })._operationExpr;
194
- if (operationExpr) {
208
+ if (isExpressionBuilder(col)) {
209
+ const operationExpr = col.expr;
195
210
  if (operationExpr.returns.kind === 'typeId') {
196
211
  projectionTypes[alias] = operationExpr.returns.type;
197
212
  } else if (operationExpr.returns.kind === 'builtin') {
@@ -216,8 +231,8 @@ export function buildMeta(args: MetaBuildArgs): PlanMeta {
216
231
  if (!column) {
217
232
  continue;
218
233
  }
219
- const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
220
- if (operationExpr) {
234
+ if (isExpressionBuilder(column)) {
235
+ const operationExpr = column.expr;
221
236
  if (operationExpr.returns.kind === 'typeId') {
222
237
  projectionCodecs[alias] = operationExpr.returns.type;
223
238
  }
@@ -19,6 +19,7 @@ import type {
19
19
  BuildOptions,
20
20
  NestedProjection,
21
21
  } from '@prisma-next/sql-relational-core/types';
22
+ import { isExpressionBuilder } from '@prisma-next/sql-relational-core/utils/guards';
22
23
  import { checkIncludeCapabilities } from '../orm/capabilities';
23
24
  import type { OrmIncludeState, RelationFilter } from '../orm/state';
24
25
  import { buildJoinOnExpr } from '../selection/join';
@@ -175,12 +176,11 @@ export function buildIncludeAsts(input: BuildIncludeAstsInput): {
175
176
  if (!column) {
176
177
  errorMissingColumn(alias, i);
177
178
  }
178
- const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
179
- if (operationExpr) {
180
- childProjectionItems.push({ alias, expr: operationExpr });
179
+ if (isExpressionBuilder(column)) {
180
+ childProjectionItems.push({ alias, expr: column.expr });
181
181
  } else {
182
- const col = column as { table: string; column: string };
183
- childProjectionItems.push({ alias, expr: createColumnRef(col.table, col.column) });
182
+ // ColumnBuilder - use toExpr() to get ColumnRef
183
+ childProjectionItems.push({ alias, expr: column.toExpr() });
184
184
  }
185
185
  }
186
186
 
@@ -1,21 +1,14 @@
1
1
  import type { ParamDescriptor } from '@prisma-next/contract/types';
2
2
  import type { SqlContract, SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
3
- import type {
4
- BinaryExpr,
5
- ColumnRef,
6
- OperationExpr,
7
- ParamRef,
8
- } from '@prisma-next/sql-relational-core/ast';
3
+ import type { BinaryExpr, Expression, ParamRef } from '@prisma-next/sql-relational-core/ast';
9
4
  import { augmentDescriptorWithColumnMeta } from '@prisma-next/sql-relational-core/plan';
10
5
  import type { BinaryBuilder, ParamPlaceholder } from '@prisma-next/sql-relational-core/types';
11
6
  import {
12
- getColumnInfo,
13
- getColumnMeta,
14
- getOperationExpr,
15
7
  isColumnBuilder,
8
+ isExpressionBuilder,
16
9
  isParamPlaceholder,
17
10
  } from '@prisma-next/sql-relational-core/utils/guards';
18
- import { createBinaryExpr, createColumnRef, createParamRef } from '../utils/ast';
11
+ import { createBinaryExpr, createParamRef } from '../utils/ast';
19
12
  import {
20
13
  errorFailedToBuildWhereClause,
21
14
  errorMissingParameter,
@@ -33,16 +26,17 @@ export function buildWhereExpr(
33
26
  codecId?: string;
34
27
  paramName: string;
35
28
  } {
36
- let leftExpr: ColumnRef | OperationExpr;
29
+ let leftExpr: Expression;
37
30
  let codecId: string | undefined;
38
- let rightExpr: ColumnRef | ParamRef;
31
+ let rightExpr: Expression | ParamRef;
39
32
  let paramName: string;
40
33
 
41
- const operationExpr = getOperationExpr(where.left);
42
- if (operationExpr) {
43
- leftExpr = operationExpr;
44
- } else if (isColumnBuilder(where.left)) {
45
- const { table, column } = getColumnInfo(where.left);
34
+ // where.left is now an Expression (ColumnRef or OperationExpr)
35
+ leftExpr = where.left;
36
+
37
+ // If leftExpr is a ColumnRef, extract codecId from contract
38
+ if (leftExpr.kind === 'col') {
39
+ const { table, column } = leftExpr;
46
40
 
47
41
  const contractTable = contract.storage.tables[table];
48
42
  if (!contractTable) {
@@ -55,12 +49,9 @@ export function buildWhereExpr(
55
49
  if (columnMeta) {
56
50
  codecId = columnMeta.codecId;
57
51
  }
58
- leftExpr = createColumnRef(table, column);
59
- } else {
60
- errorFailedToBuildWhereClause();
61
52
  }
62
53
 
63
- // Handle where.right - can be ParamPlaceholder or AnyColumnBuilder
54
+ // Handle where.right - can be ParamPlaceholder or AnyExpressionSource
64
55
  if (isParamPlaceholder(where.right)) {
65
56
  // Handle param placeholder (existing logic)
66
57
  const placeholder: ParamPlaceholder = where.right;
@@ -73,42 +64,35 @@ export function buildWhereExpr(
73
64
  const value = paramsMap[paramName];
74
65
  const index = values.push(value);
75
66
 
76
- // Construct descriptor if where.left is a ColumnBuilder
77
- if (isColumnBuilder(where.left)) {
78
- const { table, column } = getColumnInfo(where.left);
67
+ // Construct descriptor from where.left Expression
68
+ // For ColumnRef, we can extract table/column directly
69
+ // For OperationExpr, we extract the base column reference
70
+ if (leftExpr.kind === 'col') {
71
+ const { table, column } = leftExpr;
79
72
  const contractTable = contract.storage.tables[table];
80
73
  const columnMeta = contractTable?.columns[column];
81
- const builderColumnMeta = getColumnMeta(where.left);
82
74
 
83
75
  descriptors.push({
84
76
  name: paramName,
85
77
  source: 'dsl',
86
78
  refs: { table, column },
87
- ...(typeof builderColumnMeta?.nullable === 'boolean'
88
- ? { nullable: builderColumnMeta.nullable }
79
+ ...(columnMeta && typeof columnMeta.nullable === 'boolean'
80
+ ? { nullable: columnMeta.nullable }
89
81
  : {}),
90
82
  });
91
83
 
92
84
  augmentDescriptorWithColumnMeta(descriptors, columnMeta);
93
85
  }
86
+ // For OperationExpr, we don't create descriptors since we can't reliably extract column info
94
87
 
95
88
  rightExpr = createParamRef(index, paramName);
96
- } else if (isColumnBuilder(where.right)) {
97
- // Handle column builder on the right
98
- const { table, column } = getColumnInfo(where.right);
99
-
100
- const contractTable = contract.storage.tables[table];
101
- if (!contractTable) {
102
- errorUnknownTable(table);
103
- }
104
-
105
- // If column not found in contract, still build expression
106
- // This allows flexibility when columnMeta is available on the column builder
107
- rightExpr = createColumnRef(table, column);
108
- // Use a placeholder paramName for column references (not used for params)
89
+ } else if (isColumnBuilder(where.right) || isExpressionBuilder(where.right)) {
90
+ // Handle ExpressionSource on the right - use toExpr() to get the Expression
91
+ rightExpr = where.right.toExpr();
92
+ // Use a placeholder paramName for expression references (not used for params)
109
93
  paramName = '';
110
94
  } else {
111
- // where.right is neither ParamPlaceholder nor ColumnBuilder - invalid state
95
+ // where.right is neither ParamPlaceholder nor ExpressionSource - invalid state
112
96
  errorFailedToBuildWhereClause();
113
97
  }
114
98
 
@@ -1,12 +1,15 @@
1
1
  import type { TableRef } from '@prisma-next/sql-relational-core/ast';
2
2
  import type {
3
3
  AnyBinaryBuilder,
4
- AnyColumnBuilder,
4
+ AnyExpressionSource,
5
5
  AnyOrderBuilder,
6
6
  JoinOnPredicate,
7
7
  NestedProjection,
8
8
  } from '@prisma-next/sql-relational-core/types';
9
- import { isColumnBuilder } from '@prisma-next/sql-relational-core/utils/guards';
9
+ import {
10
+ isColumnBuilder,
11
+ isExpressionBuilder,
12
+ } from '@prisma-next/sql-relational-core/utils/guards';
10
13
  import {
11
14
  errorAliasCollision,
12
15
  errorAliasPathEmpty,
@@ -18,10 +21,10 @@ import {
18
21
 
19
22
  export interface ProjectionState {
20
23
  readonly aliases: string[];
21
- readonly columns: AnyColumnBuilder[];
24
+ readonly columns: AnyExpressionSource[];
22
25
  }
23
26
 
24
- export type ProjectionInput = Record<string, AnyColumnBuilder | boolean | NestedProjection>;
27
+ export type ProjectionInput = Record<string, AnyExpressionSource | boolean | NestedProjection>;
25
28
 
26
29
  function generateAlias(path: string[]): string {
27
30
  if (path.length === 0) {
@@ -58,14 +61,14 @@ export function flattenProjection(
58
61
  projection: NestedProjection,
59
62
  tracker: AliasTracker,
60
63
  currentPath: string[] = [],
61
- ): { aliases: string[]; columns: AnyColumnBuilder[] } {
64
+ ): { aliases: string[]; columns: AnyExpressionSource[] } {
62
65
  const aliases: string[] = [];
63
- const columns: AnyColumnBuilder[] = [];
66
+ const columns: AnyExpressionSource[] = [];
64
67
 
65
68
  for (const [key, value] of Object.entries(projection)) {
66
69
  const path = [...currentPath, key];
67
70
 
68
- if (isColumnBuilder(value)) {
71
+ if (isColumnBuilder(value) || isExpressionBuilder(value)) {
69
72
  const alias = tracker.register(path);
70
73
  aliases.push(alias);
71
74
  columns.push(value);
@@ -96,7 +99,7 @@ export function buildProjectionState(
96
99
  ): ProjectionState {
97
100
  const tracker = new AliasTracker();
98
101
  const aliases: string[] = [];
99
- const columns: AnyColumnBuilder[] = [];
102
+ const columns: AnyExpressionSource[] = [];
100
103
 
101
104
  for (const [key, value] of Object.entries(projection)) {
102
105
  if (value === true) {
@@ -114,8 +117,11 @@ export function buildProjectionState(
114
117
  codecId: 'core/json@1',
115
118
  nullable: true,
116
119
  },
117
- } as AnyColumnBuilder);
118
- } else if (isColumnBuilder(value)) {
120
+ toExpr() {
121
+ return { kind: 'col', table: matchingInclude.table.name, column: '' };
122
+ },
123
+ } as AnyExpressionSource);
124
+ } else if (isColumnBuilder(value) || isExpressionBuilder(value)) {
119
125
  const alias = tracker.register([key]);
120
126
  aliases.push(alias);
121
127
  columns.push(value);
@@ -1,24 +1,24 @@
1
1
  import type {
2
2
  BinaryExpr,
3
- ColumnRef,
4
3
  Direction,
5
4
  ExistsExpr,
5
+ Expression,
6
6
  IncludeAst,
7
7
  IncludeRef,
8
- OperationExpr,
9
8
  SelectAst,
10
9
  TableRef,
11
10
  } from '@prisma-next/sql-relational-core/ast';
11
+ import { isExpressionBuilder } from '@prisma-next/sql-relational-core/utils/guards';
12
12
  import type { IncludeState } from '../relations/include-plan';
13
- import { createColumnRef, createSelectAst, createTableRef } from '../utils/ast';
13
+ import { createSelectAst, createTableRef } from '../utils/ast';
14
14
  import { errorInvalidColumn, errorMissingAlias, errorMissingColumn } from '../utils/errors';
15
15
  import type { ProjectionState } from './projection';
16
16
 
17
17
  export function buildProjectionItems(
18
18
  projectionState: ProjectionState,
19
19
  includesForMeta: ReadonlyArray<IncludeState>,
20
- ): Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }> {
21
- const projectEntries: Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }> = [];
20
+ ): Array<{ alias: string; expr: Expression | IncludeRef }> {
21
+ const projectEntries: Array<{ alias: string; expr: Expression | IncludeRef }> = [];
22
22
  for (let i = 0; i < projectionState.aliases.length; i++) {
23
23
  const alias = projectionState.aliases[i];
24
24
  if (!alias) {
@@ -35,25 +35,23 @@ export function buildProjectionItems(
35
35
  alias,
36
36
  expr: { kind: 'includeRef', alias },
37
37
  });
38
+ } else if (isExpressionBuilder(column)) {
39
+ // ExpressionBuilder (operation result) - use its expr
40
+ projectEntries.push({
41
+ alias,
42
+ expr: column.expr,
43
+ });
38
44
  } else {
39
- const operationExpr = (column as { _operationExpr?: OperationExpr })._operationExpr;
40
- if (operationExpr) {
41
- projectEntries.push({
42
- alias,
43
- expr: operationExpr,
44
- });
45
- } else {
46
- const col = column as { table: string; column: string };
47
- const tableName = col.table;
48
- const columnName = col.column;
49
- if (!tableName || !columnName) {
50
- errorInvalidColumn(alias, i);
51
- }
52
- projectEntries.push({
53
- alias,
54
- expr: createColumnRef(tableName, columnName),
55
- });
45
+ // ColumnBuilder - use toExpr() to get ColumnRef
46
+ const expr = column.toExpr();
47
+ // Validate the expression has valid table and column values
48
+ if (expr.kind === 'col' && (!expr.table || !expr.column)) {
49
+ errorInvalidColumn(alias, i);
56
50
  }
51
+ projectEntries.push({
52
+ alias,
53
+ expr,
54
+ });
57
55
  }
58
56
  }
59
57
  return projectEntries;
@@ -61,11 +59,11 @@ export function buildProjectionItems(
61
59
 
62
60
  export function buildSelectAst(params: {
63
61
  table: TableRef;
64
- projectEntries: Array<{ alias: string; expr: ColumnRef | IncludeRef | OperationExpr }>;
62
+ projectEntries: Array<{ alias: string; expr: Expression | IncludeRef }>;
65
63
  includesAst?: ReadonlyArray<IncludeAst>;
66
64
  whereExpr?: BinaryExpr | ExistsExpr;
67
65
  orderByClause?: ReadonlyArray<{
68
- expr: ColumnRef | OperationExpr;
66
+ expr: Expression;
69
67
  dir: Direction;
70
68
  }>;
71
69
  limit?: number;