Skip to content

Commit 6106a33

Browse files
committed
feat: 添加字段引用模式和连接执行策略,优化聚合节点的过滤条件
1 parent 09fa25b commit 6106a33

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

packages/spec/src/data/filter.zod.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ import { z } from 'zod';
2222
* 4. Convention over Configuration: Implicit syntax for common queries
2323
*/
2424

25+
/**
26+
* Field Reference
27+
* Represents a reference to another field/column instead of a literal value.
28+
* Used for joins (ON clause) and cross-field comparisons.
29+
*
30+
* @example
31+
* // user.id = order.owner_id
32+
* { "$eq": { "$field": "order.owner_id" } }
33+
*/
34+
export const FieldReferenceSchema = z.object({
35+
$field: z.string().describe('Field Reference/Column Name')
36+
});
37+
38+
export type FieldReference = z.infer<typeof FieldReferenceSchema>;
39+
2540
// ============================================================================
2641
// 3.1 Comparison Operators
2742
// ============================================================================
@@ -44,16 +59,16 @@ export const EqualityOperatorSchema = z.object({
4459
*/
4560
export const ComparisonOperatorSchema = z.object({
4661
/** Greater than - SQL: > | MongoDB: $gt */
47-
$gt: z.union([z.number(), z.date()]).optional(),
62+
$gt: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
4863

4964
/** Greater than or equal to - SQL: >= | MongoDB: $gte */
50-
$gte: z.union([z.number(), z.date()]).optional(),
65+
$gte: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
5166

5267
/** Less than - SQL: < | MongoDB: $lt */
53-
$lt: z.union([z.number(), z.date()]).optional(),
68+
$lt: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
5469

5570
/** Less than or equal to - SQL: <= | MongoDB: $lte */
56-
$lte: z.union([z.number(), z.date()]).optional(),
71+
$lte: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
5772
});
5873

5974
// ============================================================================
@@ -78,8 +93,8 @@ export const SetOperatorSchema = z.object({
7893
export const RangeOperatorSchema = z.object({
7994
/** Between (inclusive) - takes [min, max] array */
8095
$between: z.tuple([
81-
z.union([z.number(), z.date()]),
82-
z.union([z.number(), z.date()])
96+
z.union([z.number(), z.date(), FieldReferenceSchema]),
97+
z.union([z.number(), z.date(), FieldReferenceSchema])
8398
]).optional(),
8499
});
85100

@@ -131,17 +146,17 @@ export const FieldOperatorsSchema = z.object({
131146
$ne: z.any().optional(),
132147

133148
// Comparison (numeric/date)
134-
$gt: z.union([z.number(), z.date()]).optional(),
135-
$gte: z.union([z.number(), z.date()]).optional(),
136-
$lt: z.union([z.number(), z.date()]).optional(),
137-
$lte: z.union([z.number(), z.date()]).optional(),
149+
$gt: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
150+
$gte: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
151+
$lt: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
152+
$lte: z.union([z.number(), z.date(), FieldReferenceSchema]).optional(),
138153

139154
// Set & Range
140155
$in: z.array(z.any()).optional(),
141156
$nin: z.array(z.any()).optional(),
142157
$between: z.tuple([
143-
z.union([z.number(), z.date()]),
144-
z.union([z.number(), z.date()])
158+
z.union([z.number(), z.date(), FieldReferenceSchema]),
159+
z.union([z.number(), z.date(), FieldReferenceSchema])
145160
]).optional(),
146161

147162
// String-specific

packages/spec/src/data/query.zod.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export const AggregationNodeSchema = z.object({
9090
field: z.string().optional().describe('Field to aggregate (optional for COUNT(*))'),
9191
alias: z.string().describe('Result column alias'),
9292
distinct: z.boolean().optional().describe('Apply DISTINCT before aggregation'),
93+
filter: FilterConditionSchema.optional().describe('Filter/Condition to apply to the aggregation (FILTER WHERE clause)'),
9394
});
9495

9596
/**
@@ -130,6 +131,18 @@ export const AggregationNodeSchema = z.object({
130131
*/
131132
export const JoinType = z.enum(['inner', 'left', 'right', 'full']);
132133

134+
/**
135+
* Join Execution Strategy
136+
* Hints to the query engine on how to execute the join.
137+
*
138+
* Strategies:
139+
* - **auto**: Engine decides best strategy (Default).
140+
* - **database**: Push down join to the database (Requires same datasource).
141+
* - **hash**: Load both sets into memory and hash join (Cross-datasource, memory intensive).
142+
* - **loop**: Nested loop lookup (N+1 safe version). (Good for small right-side lookups).
143+
*/
144+
export const JoinStrategy = z.enum(['auto', 'database', 'hash', 'loop']);
145+
133146
/**
134147
* Join Node
135148
* Represents table joins for combining data from multiple objects.
@@ -211,6 +224,7 @@ export const JoinType = z.enum(['inner', 'left', 'right', 'full']);
211224
export const JoinNodeSchema: z.ZodType<any> = z.lazy(() =>
212225
z.object({
213226
type: JoinType.describe('Join type'),
227+
strategy: JoinStrategy.optional().describe('Execution strategy hint'),
214228
object: z.string().describe('Object/table to join'),
215229
alias: z.string().optional().describe('Table alias'),
216230
on: FilterConditionSchema.describe('Join condition'),

0 commit comments

Comments
 (0)