11import { z } from 'zod' ;
2-
3- /**
4- * Filter Operator Enum
5- * Standard SQL/NoSQL operators supported by the engine.
6- */
7- export const FilterOperator = z . enum ( [
8- '=' , '!=' , '<>' ,
9- '>' , '>=' , '<' , '<=' ,
10- 'startswith' , 'contains' , 'notcontains' ,
11- 'between' , 'in' , 'notin' ,
12- 'is_null' , 'is_not_null'
13- ] ) ;
14-
15- /**
16- * Filter Logic Operator
17- */
18- export const LogicOperator = z . enum ( [ 'and' , 'or' , 'not' ] ) ;
19-
20- /**
21- * Recursive Filter Node
22- * Represents the "Where" clause.
23- *
24- * Structure: [Field, Operator, Value] OR [Logic, Filter, Filter...]
25- * Examples:
26- * - Simple: ["amount", ">", 1000]
27- * - Logic: [["status", "=", "closed"], "or", ["amount", ">", 1000]]
28- */
29- export const FilterNodeSchema : z . ZodType < any > = z . lazy ( ( ) =>
30- z . union ( [
31- // Leaf Node: [Field, Operator, Value]
32- z . tuple ( [ z . string ( ) , FilterOperator , z . any ( ) ] ) ,
33-
34- // Logic Node: [Expression, "or", Expression]
35- z . array ( z . union ( [ z . string ( ) , FilterNodeSchema ] ) )
36- ] )
37- ) ;
2+ import { FilterConditionSchema } from './filter.zod' ;
383
394/**
405 * Sort Node
@@ -248,7 +213,7 @@ export const JoinNodeSchema: z.ZodType<any> = z.lazy(() =>
248213 type : JoinType . describe ( 'Join type' ) ,
249214 object : z . string ( ) . describe ( 'Object/table to join' ) ,
250215 alias : z . string ( ) . optional ( ) . describe ( 'Table alias' ) ,
251- on : FilterNodeSchema . describe ( 'Join condition' ) ,
216+ on : FilterConditionSchema . describe ( 'Join condition' ) ,
252217 subquery : z . lazy ( ( ) => QuerySchema ) . optional ( ) . describe ( 'Subquery instead of object' ) ,
253218 } )
254219) ;
@@ -423,101 +388,28 @@ export const FieldNodeSchema: z.ZodType<any> = z.lazy(() =>
423388 * This schema represents ObjectQL - a universal query language that abstracts
424389 * SQL, NoSQL, and SaaS APIs into a single unified interface.
425390 *
426- * Key Features:
427- * - **Filtering**: WHERE clauses with nested logic
428- * - **Aggregations**: GROUP BY with COUNT, SUM, AVG, MIN, MAX
429- * - **Joins**: INNER, LEFT, RIGHT, FULL OUTER joins
430- * - **Window Functions**: ROW_NUMBER, RANK, LAG, LEAD, running totals
431- * - **Subqueries**: Nested queries in joins and filters
432- * - **Sorting & Pagination**: ORDER BY, LIMIT, OFFSET
391+ * Updates (v2):
392+ * - Aligned with modern ORM standards (Prisma/TypeORM)
393+ * - Added `cursor` based pagination support
394+ * - Renamed `top`/`skip` to `limit`/`offset`
395+ * - Unified filtering syntax with `FilterConditionSchema`
433396 *
434397 * @example
435398 * // Simple query: SELECT name, email FROM account WHERE status = 'active'
436399 * {
437400 * object: 'account',
438401 * fields: ['name', 'email'],
439- * filters: ['status', '=', 'active']
440- * }
441- *
442- * @example
443- * // Aggregation: SELECT region, SUM(amount) as total FROM sales GROUP BY region HAVING total > 10000
444- * {
445- * object: 'sales',
446- * fields: ['region'],
447- * aggregations: [
448- * { function: 'sum', field: 'amount', alias: 'total' }
449- * ],
450- * groupBy: ['region'],
451- * having: ['total', '>', 10000]
402+ * where: { status: 'active' }
452403 * }
453404 *
454405 * @example
455- * // Join: SELECT o.*, c.name FROM orders o INNER JOIN customers c ON o.customer_id = c.id
406+ * // Pagination with Limit/Offset
456407 * {
457- * object: 'order',
458- * fields: ['id', 'amount'],
459- * joins: [
460- * {
461- * type: 'inner',
462- * object: 'customer',
463- * alias: 'c',
464- * on: ['order.customer_id', '=', 'c.id']
465- * }
466- * ]
467- * }
468- *
469- * @example
470- * // Window Function: Top 5 orders per customer
471- * {
472- * object: 'order',
473- * fields: ['customer_id', 'amount', 'created_at'],
474- * windowFunctions: [
475- * {
476- * function: 'row_number',
477- * alias: 'customer_order_rank',
478- * over: {
479- * partitionBy: ['customer_id'],
480- * orderBy: [{ field: 'amount', order: 'desc' }]
481- * }
482- * }
483- * ]
484- * }
485- *
486- * @example
487- * // Complex: Customer lifetime value with rankings
488- * {
489- * object: 'customer',
490- * fields: ['id', 'name'],
491- * joins: [
492- * {
493- * type: 'left',
494- * object: 'order',
495- * alias: 'o',
496- * on: ['customer.id', '=', 'o.customer_id']
497- * }
498- * ],
499- * aggregations: [
500- * { function: 'count', field: 'o.id', alias: 'order_count' },
501- * { function: 'sum', field: 'o.amount', alias: 'lifetime_value' }
502- * ],
503- * groupBy: ['customer.id', 'customer.name'],
504- * having: ['order_count', '>', 0],
505- * sort: [{ field: 'lifetime_value', order: 'desc' }],
506- * top: 100
507- * }
508- *
509- * @example
510- * // Salesforce SOQL: SELECT Name, (SELECT LastName FROM Contacts) FROM Account
511- * {
512- * object: 'account',
513- * fields: ['name'],
514- * joins: [
515- * {
516- * type: 'left',
517- * object: 'contact',
518- * on: ['account.id', '=', 'contact.account_id']
519- * }
520- * ]
408+ * object: 'post',
409+ * where: { published: true },
410+ * orderBy: [{ field: 'created_at', order: 'desc' }],
411+ * limit: 20,
412+ * offset: 40
521413 * }
522414 */
523415export const QuerySchema = z . object ( {
@@ -527,38 +419,38 @@ export const QuerySchema = z.object({
527419 /** Select Clause */
528420 fields : z . array ( FieldNodeSchema ) . optional ( ) . describe ( 'Fields to retrieve' ) ,
529421
530- /** Aggregations */
531- aggregations : z . array ( AggregationNodeSchema ) . optional ( ) . describe ( 'Aggregation functions (GROUP BY )' ) ,
422+ /** Where Clause (Filtering) */
423+ where : FilterConditionSchema . optional ( ) . describe ( 'Filtering criteria (WHERE )' ) ,
532424
533- /** Window Functions */
534- windowFunctions : z . array ( WindowFunctionNodeSchema ) . optional ( ) . describe ( 'Window functions with OVER clause ' ) ,
425+ /** Order By Clause (Sorting) */
426+ orderBy : z . array ( SortNodeSchema ) . optional ( ) . describe ( 'Sorting instructions (ORDER BY) ' ) ,
535427
536- /** Where Clause */
537- filters : FilterNodeSchema . optional ( ) . describe ( 'Filtering criteria' ) ,
428+ /** Pagination */
429+ limit : z . number ( ) . optional ( ) . describe ( 'Max records to return (LIMIT)' ) ,
430+ offset : z . number ( ) . optional ( ) . describe ( 'Records to skip (OFFSET)' ) ,
431+ cursor : z . record ( z . any ( ) ) . optional ( ) . describe ( 'Cursor for keyset pagination' ) ,
538432
539433 /** Joins */
540- joins : z . array ( JoinNodeSchema ) . optional ( ) . describe ( 'Table joins' ) ,
434+ joins : z . array ( JoinNodeSchema ) . optional ( ) . describe ( 'Explicit Table Joins' ) ,
435+
436+ /** Aggregations */
437+ aggregations : z . array ( AggregationNodeSchema ) . optional ( ) . describe ( 'Aggregation functions' ) ,
541438
542439 /** Group By Clause */
543440 groupBy : z . array ( z . string ( ) ) . optional ( ) . describe ( 'GROUP BY fields' ) ,
544441
545442 /** Having Clause */
546- having : FilterNodeSchema . optional ( ) . describe ( 'HAVING clause for aggregation filtering' ) ,
547-
548- /** Order By Clause */
549- sort : z . array ( SortNodeSchema ) . optional ( ) . describe ( 'Sorting instructions' ) ,
443+ having : FilterConditionSchema . optional ( ) . describe ( 'HAVING clause for aggregation filtering' ) ,
550444
551- /** Pagination */
552- top : z . number ( ) . optional ( ) . describe ( 'Limit results' ) ,
553- skip : z . number ( ) . optional ( ) . describe ( 'Offset results' ) ,
445+ /** Window Functions */
446+ windowFunctions : z . array ( WindowFunctionNodeSchema ) . optional ( ) . describe ( 'Window functions with OVER clause' ) ,
554447
555448 /** Subquery flag */
556449 distinct : z . boolean ( ) . optional ( ) . describe ( 'SELECT DISTINCT flag' ) ,
557450} ) ;
558451
559452export type QueryAST = z . infer < typeof QuerySchema > ;
560453export type QueryInput = z . input < typeof QuerySchema > ;
561- export type FilterNode = z . infer < typeof FilterNodeSchema > ;
562454export type SortNode = z . infer < typeof SortNodeSchema > ;
563455export type AggregationNode = z . infer < typeof AggregationNodeSchema > ;
564456export type JoinNode = z . infer < typeof JoinNodeSchema > ;
0 commit comments