@tanstack/db 0.5.17 → 0.5.19

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.
Files changed (83) hide show
  1. package/dist/cjs/collection/changes.cjs +3 -0
  2. package/dist/cjs/collection/changes.cjs.map +1 -1
  3. package/dist/cjs/collection/sync.cjs +2 -1
  4. package/dist/cjs/collection/sync.cjs.map +1 -1
  5. package/dist/cjs/proxy.cjs +1 -1
  6. package/dist/cjs/proxy.cjs.map +1 -1
  7. package/dist/cjs/query/builder/index.cjs +5 -4
  8. package/dist/cjs/query/builder/index.cjs.map +1 -1
  9. package/dist/cjs/query/builder/index.d.cts +5 -4
  10. package/dist/cjs/query/builder/ref-proxy.cjs +63 -0
  11. package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -1
  12. package/dist/cjs/query/builder/ref-proxy.d.cts +13 -0
  13. package/dist/cjs/query/builder/types.d.cts +26 -1
  14. package/dist/cjs/query/compiler/evaluators.cjs +29 -2
  15. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -1
  16. package/dist/cjs/query/compiler/group-by.cjs +29 -12
  17. package/dist/cjs/query/compiler/group-by.cjs.map +1 -1
  18. package/dist/cjs/query/compiler/group-by.d.cts +18 -2
  19. package/dist/cjs/query/compiler/index.cjs +5 -5
  20. package/dist/cjs/query/compiler/index.cjs.map +1 -1
  21. package/dist/cjs/query/compiler/order-by.cjs +1 -1
  22. package/dist/cjs/query/compiler/order-by.cjs.map +1 -1
  23. package/dist/cjs/query/compiler/order-by.d.cts +1 -1
  24. package/dist/cjs/query/compiler/select.cjs +1 -1
  25. package/dist/cjs/query/compiler/select.cjs.map +1 -1
  26. package/dist/cjs/query/compiler/select.d.cts +1 -1
  27. package/dist/cjs/query/live/collection-config-builder.cjs +26 -10
  28. package/dist/cjs/query/live/collection-config-builder.cjs.map +1 -1
  29. package/dist/cjs/query/live/collection-subscriber.cjs +42 -33
  30. package/dist/cjs/query/live/collection-subscriber.cjs.map +1 -1
  31. package/dist/cjs/query/live/internal.cjs +1 -1
  32. package/dist/cjs/query/live/internal.cjs.map +1 -1
  33. package/dist/cjs/query/live/types.d.cts +2 -1
  34. package/dist/cjs/types.d.cts +6 -0
  35. package/dist/esm/collection/changes.js +3 -0
  36. package/dist/esm/collection/changes.js.map +1 -1
  37. package/dist/esm/collection/sync.js +2 -1
  38. package/dist/esm/collection/sync.js.map +1 -1
  39. package/dist/esm/proxy.js +1 -1
  40. package/dist/esm/proxy.js.map +1 -1
  41. package/dist/esm/query/builder/index.d.ts +5 -4
  42. package/dist/esm/query/builder/index.js +6 -5
  43. package/dist/esm/query/builder/index.js.map +1 -1
  44. package/dist/esm/query/builder/ref-proxy.d.ts +13 -0
  45. package/dist/esm/query/builder/ref-proxy.js +63 -0
  46. package/dist/esm/query/builder/ref-proxy.js.map +1 -1
  47. package/dist/esm/query/builder/types.d.ts +26 -1
  48. package/dist/esm/query/compiler/evaluators.js +29 -2
  49. package/dist/esm/query/compiler/evaluators.js.map +1 -1
  50. package/dist/esm/query/compiler/group-by.d.ts +18 -2
  51. package/dist/esm/query/compiler/group-by.js +30 -13
  52. package/dist/esm/query/compiler/group-by.js.map +1 -1
  53. package/dist/esm/query/compiler/index.js +5 -5
  54. package/dist/esm/query/compiler/index.js.map +1 -1
  55. package/dist/esm/query/compiler/order-by.d.ts +1 -1
  56. package/dist/esm/query/compiler/order-by.js +1 -1
  57. package/dist/esm/query/compiler/order-by.js.map +1 -1
  58. package/dist/esm/query/compiler/select.d.ts +1 -1
  59. package/dist/esm/query/compiler/select.js +1 -1
  60. package/dist/esm/query/compiler/select.js.map +1 -1
  61. package/dist/esm/query/live/collection-config-builder.js +26 -10
  62. package/dist/esm/query/live/collection-config-builder.js.map +1 -1
  63. package/dist/esm/query/live/collection-subscriber.js +42 -33
  64. package/dist/esm/query/live/collection-subscriber.js.map +1 -1
  65. package/dist/esm/query/live/internal.js +1 -1
  66. package/dist/esm/query/live/internal.js.map +1 -1
  67. package/dist/esm/query/live/types.d.ts +2 -1
  68. package/dist/esm/types.d.ts +6 -0
  69. package/package.json +2 -2
  70. package/src/collection/changes.ts +7 -0
  71. package/src/collection/sync.ts +2 -2
  72. package/src/query/builder/index.ts +22 -6
  73. package/src/query/builder/ref-proxy.ts +90 -0
  74. package/src/query/builder/types.ts +26 -1
  75. package/src/query/compiler/evaluators.ts +38 -2
  76. package/src/query/compiler/group-by.ts +76 -22
  77. package/src/query/compiler/index.ts +13 -13
  78. package/src/query/compiler/order-by.ts +7 -6
  79. package/src/query/compiler/select.ts +5 -8
  80. package/src/query/live/collection-config-builder.ts +66 -16
  81. package/src/query/live/collection-subscriber.ts +60 -41
  82. package/src/query/live/types.ts +3 -1
  83. package/src/types.ts +6 -0
@@ -1,6 +1,6 @@
1
1
  import { SingleResult } from '../../types.js';
2
2
  import { OrderByDirection, QueryIR } from '../ir.js';
3
- import { Context, GetResult, GroupByCallback, JoinOnCallback, MergeContextForJoinCallback, MergeContextWithJoinType, OrderByCallback, OrderByOptions, RefsForContext, ResultTypeFromSelect, SchemaFromSource, SelectObject, Source, WhereCallback, WithResult } from './types.js';
3
+ import { Context, FunctionalHavingRow, GetResult, GroupByCallback, JoinOnCallback, MergeContextForJoinCallback, MergeContextWithJoinType, OrderByCallback, OrderByOptions, RefsForContext, ResultTypeFromSelect, SchemaFromSource, SelectObject, Source, WhereCallback, WithResult } from './types.js';
4
4
  export declare class BaseQueryBuilder<TContext extends Context = Context> {
5
5
  private readonly query;
6
6
  constructor(query?: Partial<QueryIR>);
@@ -392,7 +392,7 @@ export declare class BaseQueryBuilder<TContext extends Context = Context> {
392
392
  * Filter grouped rows using a function that operates on each aggregated row
393
393
  * Warning: This cannot be optimized by the query compiler
394
394
  *
395
- * @param callback - A function that receives an aggregated row and returns a boolean
395
+ * @param callback - A function that receives an aggregated row (with $selected when select() was called) and returns a boolean
396
396
  * @returns A QueryBuilder with functional having filter applied
397
397
  *
398
398
  * @example
@@ -401,10 +401,11 @@ export declare class BaseQueryBuilder<TContext extends Context = Context> {
401
401
  * query
402
402
  * .from({ posts: postsCollection })
403
403
  * .groupBy(({posts}) => posts.userId)
404
- * .fn.having(row => row.count > 5)
404
+ * .select(({posts}) => ({ userId: posts.userId, count: count(posts.id) }))
405
+ * .fn.having(({ $selected }) => $selected.count > 5)
405
406
  * ```
406
407
  */
407
- having(callback: (row: TContext[`schema`]) => any): QueryBuilder<TContext>;
408
+ having(callback: (row: FunctionalHavingRow<TContext>) => any): QueryBuilder<TContext>;
408
409
  };
409
410
  _getQuery(): QueryIR;
410
411
  }
@@ -1,7 +1,7 @@
1
1
  import { CollectionImpl } from "../../collection/index.js";
2
2
  import { CollectionRef, QueryRef, isExpressionLike, Aggregate, Func, PropRef, Value } from "../ir.js";
3
3
  import { InvalidSourceTypeError, OnlyOneSourceAllowedError, SubQueryMustHaveFromClauseError, InvalidSourceError, JoinConditionMustBeEqualityError, InvalidWhereExpressionError, QueryMustHaveFromClauseError } from "../../errors.js";
4
- import { createRefProxy, toExpression } from "./ref-proxy.js";
4
+ import { createRefProxy, createRefProxyWithSelected, toExpression } from "./ref-proxy.js";
5
5
  class BaseQueryBuilder {
6
6
  constructor(query = {}) {
7
7
  this.query = {};
@@ -268,7 +268,7 @@ class BaseQueryBuilder {
268
268
  */
269
269
  having(callback) {
270
270
  const aliases = this._getCurrentAliases();
271
- const refProxy = createRefProxy(aliases);
271
+ const refProxy = this.query.select ? createRefProxyWithSelected(aliases) : createRefProxy(aliases);
272
272
  const expression = callback(refProxy);
273
273
  if (!isExpressionLike(expression)) {
274
274
  throw new InvalidWhereExpressionError(getValueTypeName(expression));
@@ -353,7 +353,7 @@ class BaseQueryBuilder {
353
353
  */
354
354
  orderBy(callback, options = `asc`) {
355
355
  const aliases = this._getCurrentAliases();
356
- const refProxy = createRefProxy(aliases);
356
+ const refProxy = this.query.select ? createRefProxyWithSelected(aliases) : createRefProxy(aliases);
357
357
  const result = callback(refProxy);
358
358
  const opts = typeof options === `string` ? { direction: options, nulls: `first` } : {
359
359
  direction: options.direction ?? `asc`,
@@ -583,7 +583,7 @@ class BaseQueryBuilder {
583
583
  * Filter grouped rows using a function that operates on each aggregated row
584
584
  * Warning: This cannot be optimized by the query compiler
585
585
  *
586
- * @param callback - A function that receives an aggregated row and returns a boolean
586
+ * @param callback - A function that receives an aggregated row (with $selected when select() was called) and returns a boolean
587
587
  * @returns A QueryBuilder with functional having filter applied
588
588
  *
589
589
  * @example
@@ -592,7 +592,8 @@ class BaseQueryBuilder {
592
592
  * query
593
593
  * .from({ posts: postsCollection })
594
594
  * .groupBy(({posts}) => posts.userId)
595
- * .fn.having(row => row.count > 5)
595
+ * .select(({posts}) => ({ userId: posts.userId, count: count(posts.id) }))
596
+ * .fn.having(({ $selected }) => $selected.count > 5)
596
597
  * ```
597
598
  */
598
599
  having(callback) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/query/builder/index.ts"],"sourcesContent":["import { CollectionImpl } from '../../collection/index.js'\nimport {\n Aggregate as AggregateExpr,\n CollectionRef,\n Func as FuncExpr,\n PropRef,\n QueryRef,\n Value as ValueExpr,\n isExpressionLike,\n} from '../ir.js'\nimport {\n InvalidSourceError,\n InvalidSourceTypeError,\n InvalidWhereExpressionError,\n JoinConditionMustBeEqualityError,\n OnlyOneSourceAllowedError,\n QueryMustHaveFromClauseError,\n SubQueryMustHaveFromClauseError,\n} from '../../errors.js'\nimport { createRefProxy, toExpression } from './ref-proxy.js'\nimport type { NamespacedRow, SingleResult } from '../../types.js'\nimport type {\n Aggregate,\n BasicExpression,\n JoinClause,\n OrderBy,\n OrderByDirection,\n QueryIR,\n} from '../ir.js'\nimport type {\n CompareOptions,\n Context,\n GetResult,\n GroupByCallback,\n JoinOnCallback,\n MergeContextForJoinCallback,\n MergeContextWithJoinType,\n OrderByCallback,\n OrderByOptions,\n RefsForContext,\n ResultTypeFromSelect,\n SchemaFromSource,\n SelectObject,\n Source,\n WhereCallback,\n WithResult,\n} from './types.js'\n\nexport class BaseQueryBuilder<TContext extends Context = Context> {\n private readonly query: Partial<QueryIR> = {}\n\n constructor(query: Partial<QueryIR> = {}) {\n this.query = { ...query }\n }\n\n /**\n * Creates a CollectionRef or QueryRef from a source object\n * @param source - An object with a single key-value pair\n * @param context - Context string for error messages (e.g., \"from clause\", \"join clause\")\n * @returns A tuple of [alias, ref] where alias is the source key and ref is the created reference\n */\n private _createRefForSource<TSource extends Source>(\n source: TSource,\n context: string,\n ): [string, CollectionRef | QueryRef] {\n // Validate source is a plain object (not null, array, string, etc.)\n // We use try-catch to handle null/undefined gracefully\n let keys: Array<string>\n try {\n keys = Object.keys(source)\n } catch {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const type = source === null ? `null` : `undefined`\n throw new InvalidSourceTypeError(context, type)\n }\n\n // Check if it's an array (arrays pass Object.keys but aren't valid sources)\n if (Array.isArray(source)) {\n throw new InvalidSourceTypeError(context, `array`)\n }\n\n // Validate exactly one key\n if (keys.length !== 1) {\n if (keys.length === 0) {\n throw new InvalidSourceTypeError(context, `empty object`)\n }\n // Check if it looks like a string was passed (has numeric keys)\n if (keys.every((k) => !isNaN(Number(k)))) {\n throw new InvalidSourceTypeError(context, `string`)\n }\n throw new OnlyOneSourceAllowedError(context)\n }\n\n const alias = keys[0]!\n const sourceValue = source[alias]\n\n // Validate the value is a Collection or QueryBuilder\n let ref: CollectionRef | QueryRef\n\n if (sourceValue instanceof CollectionImpl) {\n ref = new CollectionRef(sourceValue, alias)\n } else if (sourceValue instanceof BaseQueryBuilder) {\n const subQuery = sourceValue._getQuery()\n if (!(subQuery as Partial<QueryIR>).from) {\n throw new SubQueryMustHaveFromClauseError(context)\n }\n ref = new QueryRef(subQuery, alias)\n } else {\n throw new InvalidSourceError(alias)\n }\n\n return [alias, ref]\n }\n\n /**\n * Specify the source table or subquery for the query\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @returns A QueryBuilder with the specified source\n *\n * @example\n * ```ts\n * // Query from a collection\n * query.from({ users: usersCollection })\n *\n * // Query from a subquery\n * const activeUsers = query.from({ u: usersCollection }).where(({u}) => u.active)\n * query.from({ activeUsers })\n * ```\n */\n from<TSource extends Source>(\n source: TSource,\n ): QueryBuilder<{\n baseSchema: SchemaFromSource<TSource>\n schema: SchemaFromSource<TSource>\n fromSourceName: keyof TSource & string\n hasJoins: false\n }> {\n const [, from] = this._createRefForSource(source, `from clause`)\n\n return new BaseQueryBuilder({\n ...this.query,\n from,\n }) as any\n }\n\n /**\n * Join another table or subquery to the current query\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @param type - The type of join: 'inner', 'left', 'right', or 'full' (defaults to 'left')\n * @returns A QueryBuilder with the joined table available\n *\n * @example\n * ```ts\n * // Left join users with posts\n * query\n * .from({ users: usersCollection })\n * .join({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n *\n * // Inner join with explicit type\n * query\n * .from({ u: usersCollection })\n * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId), 'inner')\n * ```\n *\n * // Join with a subquery\n * const activeUsers = query.from({ u: usersCollection }).where(({u}) => u.active)\n * query\n * .from({ activeUsers })\n * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId))\n */\n join<\n TSource extends Source,\n TJoinType extends `inner` | `left` | `right` | `full` = `left`,\n >(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n type: TJoinType = `left` as TJoinType,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, TJoinType>\n > {\n const [alias, from] = this._createRefForSource(source, `join clause`)\n\n // Create a temporary context for the callback\n const currentAliases = this._getCurrentAliases()\n const newAliases = [...currentAliases, alias]\n const refProxy = createRefProxy(newAliases) as RefsForContext<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >\n\n // Get the join condition expression\n const onExpression = onCallback(refProxy)\n\n // Extract left and right from the expression\n // For now, we'll assume it's an eq function with two arguments\n let left: BasicExpression\n let right: BasicExpression\n\n if (\n onExpression.type === `func` &&\n onExpression.name === `eq` &&\n onExpression.args.length === 2\n ) {\n left = onExpression.args[0]!\n right = onExpression.args[1]!\n } else {\n throw new JoinConditionMustBeEqualityError()\n }\n\n const joinClause: JoinClause = {\n from,\n type,\n left,\n right,\n }\n\n const existingJoins = this.query.join || []\n\n return new BaseQueryBuilder({\n ...this.query,\n join: [...existingJoins, joinClause],\n }) as any\n }\n\n /**\n * Perform a LEFT JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the left joined table available\n *\n * @example\n * ```ts\n * // Left join users with posts\n * query\n * .from({ users: usersCollection })\n * .leftJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n leftJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `left`>\n > {\n return this.join(source, onCallback, `left`)\n }\n\n /**\n * Perform a RIGHT JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the right joined table available\n *\n * @example\n * ```ts\n * // Right join users with posts\n * query\n * .from({ users: usersCollection })\n * .rightJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n rightJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `right`>\n > {\n return this.join(source, onCallback, `right`)\n }\n\n /**\n * Perform an INNER JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the inner joined table available\n *\n * @example\n * ```ts\n * // Inner join users with posts\n * query\n * .from({ users: usersCollection })\n * .innerJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n innerJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `inner`>\n > {\n return this.join(source, onCallback, `inner`)\n }\n\n /**\n * Perform a FULL JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the full joined table available\n *\n * @example\n * ```ts\n * // Full join users with posts\n * query\n * .from({ users: usersCollection })\n * .fullJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n fullJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `full`>\n > {\n return this.join(source, onCallback, `full`)\n }\n\n /**\n * Filter rows based on a condition\n *\n * @param callback - A function that receives table references and returns an expression\n * @returns A QueryBuilder with the where condition applied\n *\n * @example\n * ```ts\n * // Simple condition\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => gt(users.age, 18))\n *\n * // Multiple conditions\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => and(\n * gt(users.age, 18),\n * eq(users.active, true)\n * ))\n *\n * // Multiple where calls are ANDed together\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => gt(users.age, 18))\n * .where(({users}) => eq(users.active, true))\n * ```\n */\n where(callback: WhereCallback<TContext>): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const expression = callback(refProxy)\n\n // Validate that the callback returned a valid expression\n // This catches common mistakes like using JavaScript comparison operators (===, !==, etc.)\n // which return boolean primitives instead of expression objects\n if (!isExpressionLike(expression)) {\n throw new InvalidWhereExpressionError(getValueTypeName(expression))\n }\n\n const existingWhere = this.query.where || []\n\n return new BaseQueryBuilder({\n ...this.query,\n where: [...existingWhere, expression],\n }) as any\n }\n\n /**\n * Filter grouped rows based on aggregate conditions\n *\n * @param callback - A function that receives table references and returns an expression\n * @returns A QueryBuilder with the having condition applied\n *\n * @example\n * ```ts\n * // Filter groups by count\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .having(({posts}) => gt(count(posts.id), 5))\n *\n * // Filter by average\n * query\n * .from({ orders: ordersCollection })\n * .groupBy(({orders}) => orders.customerId)\n * .having(({orders}) => gt(avg(orders.total), 100))\n *\n * // Multiple having calls are ANDed together\n * query\n * .from({ orders: ordersCollection })\n * .groupBy(({orders}) => orders.customerId)\n * .having(({orders}) => gt(count(orders.id), 5))\n * .having(({orders}) => gt(avg(orders.total), 100))\n * ```\n */\n having(callback: WhereCallback<TContext>): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const expression = callback(refProxy)\n\n // Validate that the callback returned a valid expression\n // This catches common mistakes like using JavaScript comparison operators (===, !==, etc.)\n // which return boolean primitives instead of expression objects\n if (!isExpressionLike(expression)) {\n throw new InvalidWhereExpressionError(getValueTypeName(expression))\n }\n\n const existingHaving = this.query.having || []\n\n return new BaseQueryBuilder({\n ...this.query,\n having: [...existingHaving, expression],\n }) as any\n }\n\n /**\n * Select specific columns or computed values from the query\n *\n * @param callback - A function that receives table references and returns an object with selected fields or expressions\n * @returns A QueryBuilder that returns only the selected fields\n *\n * @example\n * ```ts\n * // Select specific columns\n * query\n * .from({ users: usersCollection })\n * .select(({users}) => ({\n * name: users.name,\n * email: users.email\n * }))\n *\n * // Select with computed values\n * query\n * .from({ users: usersCollection })\n * .select(({users}) => ({\n * fullName: concat(users.firstName, ' ', users.lastName),\n * ageInMonths: mul(users.age, 12)\n * }))\n *\n * // Select with aggregates (requires GROUP BY)\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .select(({posts, count}) => ({\n * userId: posts.userId,\n * postCount: count(posts.id)\n * }))\n * ```\n */\n select<TSelectObject extends SelectObject>(\n callback: (refs: RefsForContext<TContext>) => TSelectObject,\n ): QueryBuilder<WithResult<TContext, ResultTypeFromSelect<TSelectObject>>> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const selectObject = callback(refProxy)\n const select = buildNestedSelect(selectObject)\n\n return new BaseQueryBuilder({\n ...this.query,\n select: select,\n fnSelect: undefined, // remove the fnSelect clause if it exists\n }) as any\n }\n\n /**\n * Sort the query results by one or more columns\n *\n * @param callback - A function that receives table references and returns the field to sort by\n * @param direction - Sort direction: 'asc' for ascending, 'desc' for descending (defaults to 'asc')\n * @returns A QueryBuilder with the ordering applied\n *\n * @example\n * ```ts\n * // Sort by a single column\n * query\n * .from({ users: usersCollection })\n * .orderBy(({users}) => users.name)\n *\n * // Sort descending\n * query\n * .from({ users: usersCollection })\n * .orderBy(({users}) => users.createdAt, 'desc')\n *\n * // Multiple sorts (chain orderBy calls)\n * query\n * .from({ users: usersCollection })\n * .orderBy(({users}) => users.lastName)\n * .orderBy(({users}) => users.firstName)\n * ```\n */\n orderBy(\n callback: OrderByCallback<TContext>,\n options: OrderByDirection | OrderByOptions = `asc`,\n ): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const result = callback(refProxy)\n\n const opts: CompareOptions =\n typeof options === `string`\n ? { direction: options, nulls: `first` }\n : {\n direction: options.direction ?? `asc`,\n nulls: options.nulls ?? `first`,\n stringSort: options.stringSort,\n locale:\n options.stringSort === `locale` ? options.locale : undefined,\n localeOptions:\n options.stringSort === `locale`\n ? options.localeOptions\n : undefined,\n }\n\n const makeOrderByClause = (res: any) => {\n return {\n expression: toExpression(res),\n compareOptions: opts,\n }\n }\n\n // Create the new OrderBy structure with expression and direction\n const orderByClauses = Array.isArray(result)\n ? result.map((r) => makeOrderByClause(r))\n : [makeOrderByClause(result)]\n\n const existingOrderBy: OrderBy = this.query.orderBy || []\n\n return new BaseQueryBuilder({\n ...this.query,\n orderBy: [...existingOrderBy, ...orderByClauses],\n }) as any\n }\n\n /**\n * Group rows by one or more columns for aggregation\n *\n * @param callback - A function that receives table references and returns the field(s) to group by\n * @returns A QueryBuilder with grouping applied (enables aggregate functions in SELECT and HAVING)\n *\n * @example\n * ```ts\n * // Group by a single column\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .select(({posts, count}) => ({\n * userId: posts.userId,\n * postCount: count()\n * }))\n *\n * // Group by multiple columns\n * query\n * .from({ sales: salesCollection })\n * .groupBy(({sales}) => [sales.region, sales.category])\n * .select(({sales, sum}) => ({\n * region: sales.region,\n * category: sales.category,\n * totalSales: sum(sales.amount)\n * }))\n * ```\n */\n groupBy(callback: GroupByCallback<TContext>): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const result = callback(refProxy)\n\n const newExpressions = Array.isArray(result)\n ? result.map((r) => toExpression(r))\n : [toExpression(result)]\n\n // Extend existing groupBy expressions (multiple groupBy calls should accumulate)\n const existingGroupBy = this.query.groupBy || []\n return new BaseQueryBuilder({\n ...this.query,\n groupBy: [...existingGroupBy, ...newExpressions],\n }) as any\n }\n\n /**\n * Limit the number of rows returned by the query\n * `orderBy` is required for `limit`\n *\n * @param count - Maximum number of rows to return\n * @returns A QueryBuilder with the limit applied\n *\n * @example\n * ```ts\n * // Get top 5 posts by likes\n * query\n * .from({ posts: postsCollection })\n * .orderBy(({posts}) => posts.likes, 'desc')\n * .limit(5)\n * ```\n */\n limit(count: number): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...this.query,\n limit: count,\n }) as any\n }\n\n /**\n * Skip a number of rows before returning results\n * `orderBy` is required for `offset`\n *\n * @param count - Number of rows to skip\n * @returns A QueryBuilder with the offset applied\n *\n * @example\n * ```ts\n * // Get second page of results\n * query\n * .from({ posts: postsCollection })\n * .orderBy(({posts}) => posts.createdAt, 'desc')\n * .offset(page * pageSize)\n * .limit(pageSize)\n * ```\n */\n offset(count: number): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...this.query,\n offset: count,\n }) as any\n }\n\n /**\n * Specify that the query should return distinct rows.\n * Deduplicates rows based on the selected columns.\n * @returns A QueryBuilder with distinct enabled\n *\n * @example\n * ```ts\n * // Get countries our users are from\n * query\n * .from({ users: usersCollection })\n * .select(({users}) => users.country)\n * .distinct()\n * ```\n */\n distinct(): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...this.query,\n distinct: true,\n }) as any\n }\n\n /**\n * Specify that the query should return a single result\n * @returns A QueryBuilder that returns the first result\n *\n * @example\n * ```ts\n * // Get the user matching the query\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => eq(users.id, 1))\n * .findOne()\n *```\n */\n findOne(): QueryBuilder<TContext & SingleResult> {\n return new BaseQueryBuilder({\n ...this.query,\n // TODO: enforcing return only one result with also a default orderBy if none is specified\n // limit: 1,\n singleResult: true,\n })\n }\n\n // Helper methods\n private _getCurrentAliases(): Array<string> {\n const aliases: Array<string> = []\n\n // Add the from alias\n if (this.query.from) {\n aliases.push(this.query.from.alias)\n }\n\n // Add join aliases\n if (this.query.join) {\n for (const join of this.query.join) {\n aliases.push(join.from.alias)\n }\n }\n\n return aliases\n }\n\n /**\n * Functional variants of the query builder\n * These are imperative function that are called for ery row.\n * Warning: that these cannot be optimized by the query compiler, and may prevent\n * some type of optimizations being possible.\n * @example\n * ```ts\n * q.fn.select((row) => ({\n * name: row.user.name.toUpperCase(),\n * age: row.user.age + 1,\n * }))\n * ```\n */\n get fn() {\n const builder = this\n return {\n /**\n * Select fields using a function that operates on each row\n * Warning: This cannot be optimized by the query compiler\n *\n * @param callback - A function that receives a row and returns the selected value\n * @returns A QueryBuilder with functional selection applied\n *\n * @example\n * ```ts\n * // Functional select (not optimized)\n * query\n * .from({ users: usersCollection })\n * .fn.select(row => ({\n * name: row.users.name.toUpperCase(),\n * age: row.users.age + 1,\n * }))\n * ```\n */\n select<TFuncSelectResult>(\n callback: (row: TContext[`schema`]) => TFuncSelectResult,\n ): QueryBuilder<WithResult<TContext, TFuncSelectResult>> {\n return new BaseQueryBuilder({\n ...builder.query,\n select: undefined, // remove the select clause if it exists\n fnSelect: callback,\n })\n },\n /**\n * Filter rows using a function that operates on each row\n * Warning: This cannot be optimized by the query compiler\n *\n * @param callback - A function that receives a row and returns a boolean\n * @returns A QueryBuilder with functional filtering applied\n *\n * @example\n * ```ts\n * // Functional where (not optimized)\n * query\n * .from({ users: usersCollection })\n * .fn.where(row => row.users.name.startsWith('A'))\n * ```\n */\n where(\n callback: (row: TContext[`schema`]) => any,\n ): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...builder.query,\n fnWhere: [\n ...(builder.query.fnWhere || []),\n callback as (row: NamespacedRow) => any,\n ],\n })\n },\n /**\n * Filter grouped rows using a function that operates on each aggregated row\n * Warning: This cannot be optimized by the query compiler\n *\n * @param callback - A function that receives an aggregated row and returns a boolean\n * @returns A QueryBuilder with functional having filter applied\n *\n * @example\n * ```ts\n * // Functional having (not optimized)\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .fn.having(row => row.count > 5)\n * ```\n */\n having(\n callback: (row: TContext[`schema`]) => any,\n ): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...builder.query,\n fnHaving: [\n ...(builder.query.fnHaving || []),\n callback as (row: NamespacedRow) => any,\n ],\n })\n },\n }\n }\n\n _getQuery(): QueryIR {\n if (!this.query.from) {\n throw new QueryMustHaveFromClauseError()\n }\n return this.query as QueryIR\n }\n}\n\n// Helper to get a descriptive type name for error messages\nfunction getValueTypeName(value: unknown): string {\n if (value === null) return `null`\n if (value === undefined) return `undefined`\n if (typeof value === `object`) return `object`\n return typeof value\n}\n\n// Helper to ensure we have a BasicExpression/Aggregate for a value\nfunction toExpr(value: any): BasicExpression | Aggregate {\n if (value === undefined) return toExpression(null)\n if (\n value instanceof AggregateExpr ||\n value instanceof FuncExpr ||\n value instanceof PropRef ||\n value instanceof ValueExpr\n ) {\n return value as BasicExpression | Aggregate\n }\n return toExpression(value)\n}\n\nfunction isPlainObject(value: any): value is Record<string, any> {\n return (\n value !== null &&\n typeof value === `object` &&\n !isExpressionLike(value) &&\n !value.__refProxy\n )\n}\n\nfunction buildNestedSelect(obj: any): any {\n if (!isPlainObject(obj)) return toExpr(obj)\n const out: Record<string, any> = {}\n for (const [k, v] of Object.entries(obj)) {\n if (typeof k === `string` && k.startsWith(`__SPREAD_SENTINEL__`)) {\n // Preserve sentinel key and its value (value is unimportant at compile time)\n out[k] = v\n continue\n }\n out[k] = buildNestedSelect(v)\n }\n return out\n}\n\n// Internal function to build a query from a callback\n// used by liveQueryCollectionOptions.query\nexport function buildQuery<TContext extends Context>(\n fn: (builder: InitialQueryBuilder) => QueryBuilder<TContext>,\n): QueryIR {\n const result = fn(new BaseQueryBuilder())\n return getQueryIR(result)\n}\n\n// Internal function to get the QueryIR from a builder\nexport function getQueryIR(\n builder: BaseQueryBuilder | QueryBuilder<any> | InitialQueryBuilder,\n): QueryIR {\n return (builder as unknown as BaseQueryBuilder)._getQuery()\n}\n\n// Type-only exports for the query builder\nexport type InitialQueryBuilder = Pick<BaseQueryBuilder<Context>, `from`>\n\nexport type InitialQueryBuilderConstructor = new () => InitialQueryBuilder\n\nexport type QueryBuilder<TContext extends Context> = Omit<\n BaseQueryBuilder<TContext>,\n `from` | `_getQuery`\n>\n\n// Main query builder class alias with the constructor type modified to hide all\n// but the from method on the initial instance\nexport const Query: InitialQueryBuilderConstructor = BaseQueryBuilder\n\n// Helper type to extract context from a QueryBuilder\nexport type ExtractContext<T> =\n T extends BaseQueryBuilder<infer TContext>\n ? TContext\n : T extends QueryBuilder<infer TContext>\n ? TContext\n : never\n\n// Helper type to extract the result type from a QueryBuilder (similar to Zod's z.infer)\nexport type QueryResult<T> = GetResult<ExtractContext<T>>\n\n// Export the types from types.ts for convenience\nexport type {\n Context,\n Source,\n GetResult,\n RefLeaf as Ref,\n InferResultType,\n} from './types.js'\n"],"names":["AggregateExpr","FuncExpr","ValueExpr"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/query/builder/index.ts"],"sourcesContent":["import { CollectionImpl } from '../../collection/index.js'\nimport {\n Aggregate as AggregateExpr,\n CollectionRef,\n Func as FuncExpr,\n PropRef,\n QueryRef,\n Value as ValueExpr,\n isExpressionLike,\n} from '../ir.js'\nimport {\n InvalidSourceError,\n InvalidSourceTypeError,\n InvalidWhereExpressionError,\n JoinConditionMustBeEqualityError,\n OnlyOneSourceAllowedError,\n QueryMustHaveFromClauseError,\n SubQueryMustHaveFromClauseError,\n} from '../../errors.js'\nimport {\n createRefProxy,\n createRefProxyWithSelected,\n toExpression,\n} from './ref-proxy.js'\nimport type { NamespacedRow, SingleResult } from '../../types.js'\nimport type {\n Aggregate,\n BasicExpression,\n JoinClause,\n OrderBy,\n OrderByDirection,\n QueryIR,\n} from '../ir.js'\nimport type {\n CompareOptions,\n Context,\n FunctionalHavingRow,\n GetResult,\n GroupByCallback,\n JoinOnCallback,\n MergeContextForJoinCallback,\n MergeContextWithJoinType,\n OrderByCallback,\n OrderByOptions,\n RefsForContext,\n ResultTypeFromSelect,\n SchemaFromSource,\n SelectObject,\n Source,\n WhereCallback,\n WithResult,\n} from './types.js'\n\nexport class BaseQueryBuilder<TContext extends Context = Context> {\n private readonly query: Partial<QueryIR> = {}\n\n constructor(query: Partial<QueryIR> = {}) {\n this.query = { ...query }\n }\n\n /**\n * Creates a CollectionRef or QueryRef from a source object\n * @param source - An object with a single key-value pair\n * @param context - Context string for error messages (e.g., \"from clause\", \"join clause\")\n * @returns A tuple of [alias, ref] where alias is the source key and ref is the created reference\n */\n private _createRefForSource<TSource extends Source>(\n source: TSource,\n context: string,\n ): [string, CollectionRef | QueryRef] {\n // Validate source is a plain object (not null, array, string, etc.)\n // We use try-catch to handle null/undefined gracefully\n let keys: Array<string>\n try {\n keys = Object.keys(source)\n } catch {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const type = source === null ? `null` : `undefined`\n throw new InvalidSourceTypeError(context, type)\n }\n\n // Check if it's an array (arrays pass Object.keys but aren't valid sources)\n if (Array.isArray(source)) {\n throw new InvalidSourceTypeError(context, `array`)\n }\n\n // Validate exactly one key\n if (keys.length !== 1) {\n if (keys.length === 0) {\n throw new InvalidSourceTypeError(context, `empty object`)\n }\n // Check if it looks like a string was passed (has numeric keys)\n if (keys.every((k) => !isNaN(Number(k)))) {\n throw new InvalidSourceTypeError(context, `string`)\n }\n throw new OnlyOneSourceAllowedError(context)\n }\n\n const alias = keys[0]!\n const sourceValue = source[alias]\n\n // Validate the value is a Collection or QueryBuilder\n let ref: CollectionRef | QueryRef\n\n if (sourceValue instanceof CollectionImpl) {\n ref = new CollectionRef(sourceValue, alias)\n } else if (sourceValue instanceof BaseQueryBuilder) {\n const subQuery = sourceValue._getQuery()\n if (!(subQuery as Partial<QueryIR>).from) {\n throw new SubQueryMustHaveFromClauseError(context)\n }\n ref = new QueryRef(subQuery, alias)\n } else {\n throw new InvalidSourceError(alias)\n }\n\n return [alias, ref]\n }\n\n /**\n * Specify the source table or subquery for the query\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @returns A QueryBuilder with the specified source\n *\n * @example\n * ```ts\n * // Query from a collection\n * query.from({ users: usersCollection })\n *\n * // Query from a subquery\n * const activeUsers = query.from({ u: usersCollection }).where(({u}) => u.active)\n * query.from({ activeUsers })\n * ```\n */\n from<TSource extends Source>(\n source: TSource,\n ): QueryBuilder<{\n baseSchema: SchemaFromSource<TSource>\n schema: SchemaFromSource<TSource>\n fromSourceName: keyof TSource & string\n hasJoins: false\n }> {\n const [, from] = this._createRefForSource(source, `from clause`)\n\n return new BaseQueryBuilder({\n ...this.query,\n from,\n }) as any\n }\n\n /**\n * Join another table or subquery to the current query\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @param type - The type of join: 'inner', 'left', 'right', or 'full' (defaults to 'left')\n * @returns A QueryBuilder with the joined table available\n *\n * @example\n * ```ts\n * // Left join users with posts\n * query\n * .from({ users: usersCollection })\n * .join({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n *\n * // Inner join with explicit type\n * query\n * .from({ u: usersCollection })\n * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId), 'inner')\n * ```\n *\n * // Join with a subquery\n * const activeUsers = query.from({ u: usersCollection }).where(({u}) => u.active)\n * query\n * .from({ activeUsers })\n * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId))\n */\n join<\n TSource extends Source,\n TJoinType extends `inner` | `left` | `right` | `full` = `left`,\n >(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n type: TJoinType = `left` as TJoinType,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, TJoinType>\n > {\n const [alias, from] = this._createRefForSource(source, `join clause`)\n\n // Create a temporary context for the callback\n const currentAliases = this._getCurrentAliases()\n const newAliases = [...currentAliases, alias]\n const refProxy = createRefProxy(newAliases) as RefsForContext<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >\n\n // Get the join condition expression\n const onExpression = onCallback(refProxy)\n\n // Extract left and right from the expression\n // For now, we'll assume it's an eq function with two arguments\n let left: BasicExpression\n let right: BasicExpression\n\n if (\n onExpression.type === `func` &&\n onExpression.name === `eq` &&\n onExpression.args.length === 2\n ) {\n left = onExpression.args[0]!\n right = onExpression.args[1]!\n } else {\n throw new JoinConditionMustBeEqualityError()\n }\n\n const joinClause: JoinClause = {\n from,\n type,\n left,\n right,\n }\n\n const existingJoins = this.query.join || []\n\n return new BaseQueryBuilder({\n ...this.query,\n join: [...existingJoins, joinClause],\n }) as any\n }\n\n /**\n * Perform a LEFT JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the left joined table available\n *\n * @example\n * ```ts\n * // Left join users with posts\n * query\n * .from({ users: usersCollection })\n * .leftJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n leftJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `left`>\n > {\n return this.join(source, onCallback, `left`)\n }\n\n /**\n * Perform a RIGHT JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the right joined table available\n *\n * @example\n * ```ts\n * // Right join users with posts\n * query\n * .from({ users: usersCollection })\n * .rightJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n rightJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `right`>\n > {\n return this.join(source, onCallback, `right`)\n }\n\n /**\n * Perform an INNER JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the inner joined table available\n *\n * @example\n * ```ts\n * // Inner join users with posts\n * query\n * .from({ users: usersCollection })\n * .innerJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n innerJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `inner`>\n > {\n return this.join(source, onCallback, `inner`)\n }\n\n /**\n * Perform a FULL JOIN with another table or subquery\n *\n * @param source - An object with a single key-value pair where the key is the table alias and the value is a Collection or subquery\n * @param onCallback - A function that receives table references and returns the join condition\n * @returns A QueryBuilder with the full joined table available\n *\n * @example\n * ```ts\n * // Full join users with posts\n * query\n * .from({ users: usersCollection })\n * .fullJoin({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))\n * ```\n */\n fullJoin<TSource extends Source>(\n source: TSource,\n onCallback: JoinOnCallback<\n MergeContextForJoinCallback<TContext, SchemaFromSource<TSource>>\n >,\n ): QueryBuilder<\n MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, `full`>\n > {\n return this.join(source, onCallback, `full`)\n }\n\n /**\n * Filter rows based on a condition\n *\n * @param callback - A function that receives table references and returns an expression\n * @returns A QueryBuilder with the where condition applied\n *\n * @example\n * ```ts\n * // Simple condition\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => gt(users.age, 18))\n *\n * // Multiple conditions\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => and(\n * gt(users.age, 18),\n * eq(users.active, true)\n * ))\n *\n * // Multiple where calls are ANDed together\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => gt(users.age, 18))\n * .where(({users}) => eq(users.active, true))\n * ```\n */\n where(callback: WhereCallback<TContext>): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const expression = callback(refProxy)\n\n // Validate that the callback returned a valid expression\n // This catches common mistakes like using JavaScript comparison operators (===, !==, etc.)\n // which return boolean primitives instead of expression objects\n if (!isExpressionLike(expression)) {\n throw new InvalidWhereExpressionError(getValueTypeName(expression))\n }\n\n const existingWhere = this.query.where || []\n\n return new BaseQueryBuilder({\n ...this.query,\n where: [...existingWhere, expression],\n }) as any\n }\n\n /**\n * Filter grouped rows based on aggregate conditions\n *\n * @param callback - A function that receives table references and returns an expression\n * @returns A QueryBuilder with the having condition applied\n *\n * @example\n * ```ts\n * // Filter groups by count\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .having(({posts}) => gt(count(posts.id), 5))\n *\n * // Filter by average\n * query\n * .from({ orders: ordersCollection })\n * .groupBy(({orders}) => orders.customerId)\n * .having(({orders}) => gt(avg(orders.total), 100))\n *\n * // Multiple having calls are ANDed together\n * query\n * .from({ orders: ordersCollection })\n * .groupBy(({orders}) => orders.customerId)\n * .having(({orders}) => gt(count(orders.id), 5))\n * .having(({orders}) => gt(avg(orders.total), 100))\n * ```\n */\n having(callback: WhereCallback<TContext>): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n // Add $selected namespace if SELECT clause exists\n const refProxy = (\n this.query.select\n ? createRefProxyWithSelected(aliases)\n : createRefProxy(aliases)\n ) as RefsForContext<TContext>\n const expression = callback(refProxy)\n\n // Validate that the callback returned a valid expression\n // This catches common mistakes like using JavaScript comparison operators (===, !==, etc.)\n // which return boolean primitives instead of expression objects\n if (!isExpressionLike(expression)) {\n throw new InvalidWhereExpressionError(getValueTypeName(expression))\n }\n\n const existingHaving = this.query.having || []\n\n return new BaseQueryBuilder({\n ...this.query,\n having: [...existingHaving, expression],\n }) as any\n }\n\n /**\n * Select specific columns or computed values from the query\n *\n * @param callback - A function that receives table references and returns an object with selected fields or expressions\n * @returns A QueryBuilder that returns only the selected fields\n *\n * @example\n * ```ts\n * // Select specific columns\n * query\n * .from({ users: usersCollection })\n * .select(({users}) => ({\n * name: users.name,\n * email: users.email\n * }))\n *\n * // Select with computed values\n * query\n * .from({ users: usersCollection })\n * .select(({users}) => ({\n * fullName: concat(users.firstName, ' ', users.lastName),\n * ageInMonths: mul(users.age, 12)\n * }))\n *\n * // Select with aggregates (requires GROUP BY)\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .select(({posts, count}) => ({\n * userId: posts.userId,\n * postCount: count(posts.id)\n * }))\n * ```\n */\n select<TSelectObject extends SelectObject>(\n callback: (refs: RefsForContext<TContext>) => TSelectObject,\n ): QueryBuilder<WithResult<TContext, ResultTypeFromSelect<TSelectObject>>> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const selectObject = callback(refProxy)\n const select = buildNestedSelect(selectObject)\n\n return new BaseQueryBuilder({\n ...this.query,\n select: select,\n fnSelect: undefined, // remove the fnSelect clause if it exists\n }) as any\n }\n\n /**\n * Sort the query results by one or more columns\n *\n * @param callback - A function that receives table references and returns the field to sort by\n * @param direction - Sort direction: 'asc' for ascending, 'desc' for descending (defaults to 'asc')\n * @returns A QueryBuilder with the ordering applied\n *\n * @example\n * ```ts\n * // Sort by a single column\n * query\n * .from({ users: usersCollection })\n * .orderBy(({users}) => users.name)\n *\n * // Sort descending\n * query\n * .from({ users: usersCollection })\n * .orderBy(({users}) => users.createdAt, 'desc')\n *\n * // Multiple sorts (chain orderBy calls)\n * query\n * .from({ users: usersCollection })\n * .orderBy(({users}) => users.lastName)\n * .orderBy(({users}) => users.firstName)\n * ```\n */\n orderBy(\n callback: OrderByCallback<TContext>,\n options: OrderByDirection | OrderByOptions = `asc`,\n ): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n // Add $selected namespace if SELECT clause exists\n const refProxy = (\n this.query.select\n ? createRefProxyWithSelected(aliases)\n : createRefProxy(aliases)\n ) as RefsForContext<TContext>\n const result = callback(refProxy)\n\n const opts: CompareOptions =\n typeof options === `string`\n ? { direction: options, nulls: `first` }\n : {\n direction: options.direction ?? `asc`,\n nulls: options.nulls ?? `first`,\n stringSort: options.stringSort,\n locale:\n options.stringSort === `locale` ? options.locale : undefined,\n localeOptions:\n options.stringSort === `locale`\n ? options.localeOptions\n : undefined,\n }\n\n const makeOrderByClause = (res: any) => {\n return {\n expression: toExpression(res),\n compareOptions: opts,\n }\n }\n\n // Create the new OrderBy structure with expression and direction\n const orderByClauses = Array.isArray(result)\n ? result.map((r) => makeOrderByClause(r))\n : [makeOrderByClause(result)]\n\n const existingOrderBy: OrderBy = this.query.orderBy || []\n\n return new BaseQueryBuilder({\n ...this.query,\n orderBy: [...existingOrderBy, ...orderByClauses],\n }) as any\n }\n\n /**\n * Group rows by one or more columns for aggregation\n *\n * @param callback - A function that receives table references and returns the field(s) to group by\n * @returns A QueryBuilder with grouping applied (enables aggregate functions in SELECT and HAVING)\n *\n * @example\n * ```ts\n * // Group by a single column\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .select(({posts, count}) => ({\n * userId: posts.userId,\n * postCount: count()\n * }))\n *\n * // Group by multiple columns\n * query\n * .from({ sales: salesCollection })\n * .groupBy(({sales}) => [sales.region, sales.category])\n * .select(({sales, sum}) => ({\n * region: sales.region,\n * category: sales.category,\n * totalSales: sum(sales.amount)\n * }))\n * ```\n */\n groupBy(callback: GroupByCallback<TContext>): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n const result = callback(refProxy)\n\n const newExpressions = Array.isArray(result)\n ? result.map((r) => toExpression(r))\n : [toExpression(result)]\n\n // Extend existing groupBy expressions (multiple groupBy calls should accumulate)\n const existingGroupBy = this.query.groupBy || []\n return new BaseQueryBuilder({\n ...this.query,\n groupBy: [...existingGroupBy, ...newExpressions],\n }) as any\n }\n\n /**\n * Limit the number of rows returned by the query\n * `orderBy` is required for `limit`\n *\n * @param count - Maximum number of rows to return\n * @returns A QueryBuilder with the limit applied\n *\n * @example\n * ```ts\n * // Get top 5 posts by likes\n * query\n * .from({ posts: postsCollection })\n * .orderBy(({posts}) => posts.likes, 'desc')\n * .limit(5)\n * ```\n */\n limit(count: number): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...this.query,\n limit: count,\n }) as any\n }\n\n /**\n * Skip a number of rows before returning results\n * `orderBy` is required for `offset`\n *\n * @param count - Number of rows to skip\n * @returns A QueryBuilder with the offset applied\n *\n * @example\n * ```ts\n * // Get second page of results\n * query\n * .from({ posts: postsCollection })\n * .orderBy(({posts}) => posts.createdAt, 'desc')\n * .offset(page * pageSize)\n * .limit(pageSize)\n * ```\n */\n offset(count: number): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...this.query,\n offset: count,\n }) as any\n }\n\n /**\n * Specify that the query should return distinct rows.\n * Deduplicates rows based on the selected columns.\n * @returns A QueryBuilder with distinct enabled\n *\n * @example\n * ```ts\n * // Get countries our users are from\n * query\n * .from({ users: usersCollection })\n * .select(({users}) => users.country)\n * .distinct()\n * ```\n */\n distinct(): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...this.query,\n distinct: true,\n }) as any\n }\n\n /**\n * Specify that the query should return a single result\n * @returns A QueryBuilder that returns the first result\n *\n * @example\n * ```ts\n * // Get the user matching the query\n * query\n * .from({ users: usersCollection })\n * .where(({users}) => eq(users.id, 1))\n * .findOne()\n *```\n */\n findOne(): QueryBuilder<TContext & SingleResult> {\n return new BaseQueryBuilder({\n ...this.query,\n // TODO: enforcing return only one result with also a default orderBy if none is specified\n // limit: 1,\n singleResult: true,\n })\n }\n\n // Helper methods\n private _getCurrentAliases(): Array<string> {\n const aliases: Array<string> = []\n\n // Add the from alias\n if (this.query.from) {\n aliases.push(this.query.from.alias)\n }\n\n // Add join aliases\n if (this.query.join) {\n for (const join of this.query.join) {\n aliases.push(join.from.alias)\n }\n }\n\n return aliases\n }\n\n /**\n * Functional variants of the query builder\n * These are imperative function that are called for ery row.\n * Warning: that these cannot be optimized by the query compiler, and may prevent\n * some type of optimizations being possible.\n * @example\n * ```ts\n * q.fn.select((row) => ({\n * name: row.user.name.toUpperCase(),\n * age: row.user.age + 1,\n * }))\n * ```\n */\n get fn() {\n const builder = this\n return {\n /**\n * Select fields using a function that operates on each row\n * Warning: This cannot be optimized by the query compiler\n *\n * @param callback - A function that receives a row and returns the selected value\n * @returns A QueryBuilder with functional selection applied\n *\n * @example\n * ```ts\n * // Functional select (not optimized)\n * query\n * .from({ users: usersCollection })\n * .fn.select(row => ({\n * name: row.users.name.toUpperCase(),\n * age: row.users.age + 1,\n * }))\n * ```\n */\n select<TFuncSelectResult>(\n callback: (row: TContext[`schema`]) => TFuncSelectResult,\n ): QueryBuilder<WithResult<TContext, TFuncSelectResult>> {\n return new BaseQueryBuilder({\n ...builder.query,\n select: undefined, // remove the select clause if it exists\n fnSelect: callback,\n })\n },\n /**\n * Filter rows using a function that operates on each row\n * Warning: This cannot be optimized by the query compiler\n *\n * @param callback - A function that receives a row and returns a boolean\n * @returns A QueryBuilder with functional filtering applied\n *\n * @example\n * ```ts\n * // Functional where (not optimized)\n * query\n * .from({ users: usersCollection })\n * .fn.where(row => row.users.name.startsWith('A'))\n * ```\n */\n where(\n callback: (row: TContext[`schema`]) => any,\n ): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...builder.query,\n fnWhere: [\n ...(builder.query.fnWhere || []),\n callback as (row: NamespacedRow) => any,\n ],\n })\n },\n /**\n * Filter grouped rows using a function that operates on each aggregated row\n * Warning: This cannot be optimized by the query compiler\n *\n * @param callback - A function that receives an aggregated row (with $selected when select() was called) and returns a boolean\n * @returns A QueryBuilder with functional having filter applied\n *\n * @example\n * ```ts\n * // Functional having (not optimized)\n * query\n * .from({ posts: postsCollection })\n * .groupBy(({posts}) => posts.userId)\n * .select(({posts}) => ({ userId: posts.userId, count: count(posts.id) }))\n * .fn.having(({ $selected }) => $selected.count > 5)\n * ```\n */\n having(\n callback: (row: FunctionalHavingRow<TContext>) => any,\n ): QueryBuilder<TContext> {\n return new BaseQueryBuilder({\n ...builder.query,\n fnHaving: [\n ...(builder.query.fnHaving || []),\n callback as (row: NamespacedRow) => any,\n ],\n })\n },\n }\n }\n\n _getQuery(): QueryIR {\n if (!this.query.from) {\n throw new QueryMustHaveFromClauseError()\n }\n return this.query as QueryIR\n }\n}\n\n// Helper to get a descriptive type name for error messages\nfunction getValueTypeName(value: unknown): string {\n if (value === null) return `null`\n if (value === undefined) return `undefined`\n if (typeof value === `object`) return `object`\n return typeof value\n}\n\n// Helper to ensure we have a BasicExpression/Aggregate for a value\nfunction toExpr(value: any): BasicExpression | Aggregate {\n if (value === undefined) return toExpression(null)\n if (\n value instanceof AggregateExpr ||\n value instanceof FuncExpr ||\n value instanceof PropRef ||\n value instanceof ValueExpr\n ) {\n return value as BasicExpression | Aggregate\n }\n return toExpression(value)\n}\n\nfunction isPlainObject(value: any): value is Record<string, any> {\n return (\n value !== null &&\n typeof value === `object` &&\n !isExpressionLike(value) &&\n !value.__refProxy\n )\n}\n\nfunction buildNestedSelect(obj: any): any {\n if (!isPlainObject(obj)) return toExpr(obj)\n const out: Record<string, any> = {}\n for (const [k, v] of Object.entries(obj)) {\n if (typeof k === `string` && k.startsWith(`__SPREAD_SENTINEL__`)) {\n // Preserve sentinel key and its value (value is unimportant at compile time)\n out[k] = v\n continue\n }\n out[k] = buildNestedSelect(v)\n }\n return out\n}\n\n// Internal function to build a query from a callback\n// used by liveQueryCollectionOptions.query\nexport function buildQuery<TContext extends Context>(\n fn: (builder: InitialQueryBuilder) => QueryBuilder<TContext>,\n): QueryIR {\n const result = fn(new BaseQueryBuilder())\n return getQueryIR(result)\n}\n\n// Internal function to get the QueryIR from a builder\nexport function getQueryIR(\n builder: BaseQueryBuilder | QueryBuilder<any> | InitialQueryBuilder,\n): QueryIR {\n return (builder as unknown as BaseQueryBuilder)._getQuery()\n}\n\n// Type-only exports for the query builder\nexport type InitialQueryBuilder = Pick<BaseQueryBuilder<Context>, `from`>\n\nexport type InitialQueryBuilderConstructor = new () => InitialQueryBuilder\n\nexport type QueryBuilder<TContext extends Context> = Omit<\n BaseQueryBuilder<TContext>,\n `from` | `_getQuery`\n>\n\n// Main query builder class alias with the constructor type modified to hide all\n// but the from method on the initial instance\nexport const Query: InitialQueryBuilderConstructor = BaseQueryBuilder\n\n// Helper type to extract context from a QueryBuilder\nexport type ExtractContext<T> =\n T extends BaseQueryBuilder<infer TContext>\n ? TContext\n : T extends QueryBuilder<infer TContext>\n ? TContext\n : never\n\n// Helper type to extract the result type from a QueryBuilder (similar to Zod's z.infer)\nexport type QueryResult<T> = GetResult<ExtractContext<T>>\n\n// Export the types from types.ts for convenience\nexport type {\n Context,\n Source,\n GetResult,\n RefLeaf as Ref,\n InferResultType,\n} from './types.js'\n"],"names":["AggregateExpr","FuncExpr","ValueExpr"],"mappings":";;;;AAqDO,MAAM,iBAAqD;AAAA,EAGhE,YAAY,QAA0B,IAAI;AAF1C,SAAiB,QAA0B,CAAA;AAGzC,SAAK,QAAQ,EAAE,GAAG,MAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,oBACN,QACA,SACoC;AAGpC,QAAI;AACJ,QAAI;AACF,aAAO,OAAO,KAAK,MAAM;AAAA,IAC3B,QAAQ;AAEN,YAAM,OAAO,WAAW,OAAO,SAAS;AACxC,YAAM,IAAI,uBAAuB,SAAS,IAAI;AAAA,IAChD;AAGA,QAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,YAAM,IAAI,uBAAuB,SAAS,OAAO;AAAA,IACnD;AAGA,QAAI,KAAK,WAAW,GAAG;AACrB,UAAI,KAAK,WAAW,GAAG;AACrB,cAAM,IAAI,uBAAuB,SAAS,cAAc;AAAA,MAC1D;AAEA,UAAI,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG;AACxC,cAAM,IAAI,uBAAuB,SAAS,QAAQ;AAAA,MACpD;AACA,YAAM,IAAI,0BAA0B,OAAO;AAAA,IAC7C;AAEA,UAAM,QAAQ,KAAK,CAAC;AACpB,UAAM,cAAc,OAAO,KAAK;AAGhC,QAAI;AAEJ,QAAI,uBAAuB,gBAAgB;AACzC,YAAM,IAAI,cAAc,aAAa,KAAK;AAAA,IAC5C,WAAW,uBAAuB,kBAAkB;AAClD,YAAM,WAAW,YAAY,UAAA;AAC7B,UAAI,CAAE,SAA8B,MAAM;AACxC,cAAM,IAAI,gCAAgC,OAAO;AAAA,MACnD;AACA,YAAM,IAAI,SAAS,UAAU,KAAK;AAAA,IACpC,OAAO;AACL,YAAM,IAAI,mBAAmB,KAAK;AAAA,IACpC;AAEA,WAAO,CAAC,OAAO,GAAG;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,KACE,QAMC;AACD,UAAM,CAAA,EAAG,IAAI,IAAI,KAAK,oBAAoB,QAAQ,aAAa;AAE/D,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR;AAAA,IAAA,CACD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA6BA,KAIE,QACA,YAGA,OAAkB,QAGlB;AACA,UAAM,CAAC,OAAO,IAAI,IAAI,KAAK,oBAAoB,QAAQ,aAAa;AAGpE,UAAM,iBAAiB,KAAK,mBAAA;AAC5B,UAAM,aAAa,CAAC,GAAG,gBAAgB,KAAK;AAC5C,UAAM,WAAW,eAAe,UAAU;AAK1C,UAAM,eAAe,WAAW,QAAQ;AAIxC,QAAI;AACJ,QAAI;AAEJ,QACE,aAAa,SAAS,UACtB,aAAa,SAAS,QACtB,aAAa,KAAK,WAAW,GAC7B;AACA,aAAO,aAAa,KAAK,CAAC;AAC1B,cAAQ,aAAa,KAAK,CAAC;AAAA,IAC7B,OAAO;AACL,YAAM,IAAI,iCAAA;AAAA,IACZ;AAEA,UAAM,aAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAGF,UAAM,gBAAgB,KAAK,MAAM,QAAQ,CAAA;AAEzC,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,MAAM,CAAC,GAAG,eAAe,UAAU;AAAA,IAAA,CACpC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,SACE,QACA,YAKA;AACA,WAAO,KAAK,KAAK,QAAQ,YAAY,MAAM;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,UACE,QACA,YAKA;AACA,WAAO,KAAK,KAAK,QAAQ,YAAY,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,UACE,QACA,YAKA;AACA,WAAO,KAAK,KAAK,QAAQ,YAAY,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,SACE,QACA,YAKA;AACA,WAAO,KAAK,KAAK,QAAQ,YAAY,MAAM;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BA,MAAM,UAA2D;AAC/D,UAAM,UAAU,KAAK,mBAAA;AACrB,UAAM,WAAW,eAAe,OAAO;AACvC,UAAM,aAAa,SAAS,QAAQ;AAKpC,QAAI,CAAC,iBAAiB,UAAU,GAAG;AACjC,YAAM,IAAI,4BAA4B,iBAAiB,UAAU,CAAC;AAAA,IACpE;AAEA,UAAM,gBAAgB,KAAK,MAAM,SAAS,CAAA;AAE1C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,OAAO,CAAC,GAAG,eAAe,UAAU;AAAA,IAAA,CACrC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BA,OAAO,UAA2D;AAChE,UAAM,UAAU,KAAK,mBAAA;AAErB,UAAM,WACJ,KAAK,MAAM,SACP,2BAA2B,OAAO,IAClC,eAAe,OAAO;AAE5B,UAAM,aAAa,SAAS,QAAQ;AAKpC,QAAI,CAAC,iBAAiB,UAAU,GAAG;AACjC,YAAM,IAAI,4BAA4B,iBAAiB,UAAU,CAAC;AAAA,IACpE;AAEA,UAAM,iBAAiB,KAAK,MAAM,UAAU,CAAA;AAE5C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,QAAQ,CAAC,GAAG,gBAAgB,UAAU;AAAA,IAAA,CACvC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoCA,OACE,UACyE;AACzE,UAAM,UAAU,KAAK,mBAAA;AACrB,UAAM,WAAW,eAAe,OAAO;AACvC,UAAM,eAAe,SAAS,QAAQ;AACtC,UAAM,SAAS,kBAAkB,YAAY;AAE7C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR;AAAA,MACA,UAAU;AAAA;AAAA,IAAA,CACX;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BA,QACE,UACA,UAA6C,OACrB;AACxB,UAAM,UAAU,KAAK,mBAAA;AAErB,UAAM,WACJ,KAAK,MAAM,SACP,2BAA2B,OAAO,IAClC,eAAe,OAAO;AAE5B,UAAM,SAAS,SAAS,QAAQ;AAEhC,UAAM,OACJ,OAAO,YAAY,WACf,EAAE,WAAW,SAAS,OAAO,QAAA,IAC7B;AAAA,MACE,WAAW,QAAQ,aAAa;AAAA,MAChC,OAAO,QAAQ,SAAS;AAAA,MACxB,YAAY,QAAQ;AAAA,MACpB,QACE,QAAQ,eAAe,WAAW,QAAQ,SAAS;AAAA,MACrD,eACE,QAAQ,eAAe,WACnB,QAAQ,gBACR;AAAA,IAAA;AAGd,UAAM,oBAAoB,CAAC,QAAa;AACtC,aAAO;AAAA,QACL,YAAY,aAAa,GAAG;AAAA,QAC5B,gBAAgB;AAAA,MAAA;AAAA,IAEpB;AAGA,UAAM,iBAAiB,MAAM,QAAQ,MAAM,IACvC,OAAO,IAAI,CAAC,MAAM,kBAAkB,CAAC,CAAC,IACtC,CAAC,kBAAkB,MAAM,CAAC;AAE9B,UAAM,kBAA2B,KAAK,MAAM,WAAW,CAAA;AAEvD,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,SAAS,CAAC,GAAG,iBAAiB,GAAG,cAAc;AAAA,IAAA,CAChD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BA,QAAQ,UAA6D;AACnE,UAAM,UAAU,KAAK,mBAAA;AACrB,UAAM,WAAW,eAAe,OAAO;AACvC,UAAM,SAAS,SAAS,QAAQ;AAEhC,UAAM,iBAAiB,MAAM,QAAQ,MAAM,IACvC,OAAO,IAAI,CAAC,MAAM,aAAa,CAAC,CAAC,IACjC,CAAC,aAAa,MAAM,CAAC;AAGzB,UAAM,kBAAkB,KAAK,MAAM,WAAW,CAAA;AAC9C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,SAAS,CAAC,GAAG,iBAAiB,GAAG,cAAc;AAAA,IAAA,CAChD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,OAAuC;AAC3C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,OAAO;AAAA,IAAA,CACR;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,OAAO,OAAuC;AAC5C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,QAAQ;AAAA,IAAA,CACT;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,WAAmC;AACjC,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA,MACR,UAAU;AAAA,IAAA,CACX;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,UAAiD;AAC/C,WAAO,IAAI,iBAAiB;AAAA,MAC1B,GAAG,KAAK;AAAA;AAAA;AAAA,MAGR,cAAc;AAAA,IAAA,CACf;AAAA,EACH;AAAA;AAAA,EAGQ,qBAAoC;AAC1C,UAAM,UAAyB,CAAA;AAG/B,QAAI,KAAK,MAAM,MAAM;AACnB,cAAQ,KAAK,KAAK,MAAM,KAAK,KAAK;AAAA,IACpC;AAGA,QAAI,KAAK,MAAM,MAAM;AACnB,iBAAW,QAAQ,KAAK,MAAM,MAAM;AAClC,gBAAQ,KAAK,KAAK,KAAK,KAAK;AAAA,MAC9B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,IAAI,KAAK;AACP,UAAM,UAAU;AAChB,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBL,OACE,UACuD;AACvD,eAAO,IAAI,iBAAiB;AAAA,UAC1B,GAAG,QAAQ;AAAA,UACX,QAAQ;AAAA;AAAA,UACR,UAAU;AAAA,QAAA,CACX;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,MACE,UACwB;AACxB,eAAO,IAAI,iBAAiB;AAAA,UAC1B,GAAG,QAAQ;AAAA,UACX,SAAS;AAAA,YACP,GAAI,QAAQ,MAAM,WAAW,CAAA;AAAA,YAC7B;AAAA,UAAA;AAAA,QACF,CACD;AAAA,MACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBA,OACE,UACwB;AACxB,eAAO,IAAI,iBAAiB;AAAA,UAC1B,GAAG,QAAQ;AAAA,UACX,UAAU;AAAA,YACR,GAAI,QAAQ,MAAM,YAAY,CAAA;AAAA,YAC9B;AAAA,UAAA;AAAA,QACF,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEA,YAAqB;AACnB,QAAI,CAAC,KAAK,MAAM,MAAM;AACpB,YAAM,IAAI,6BAAA;AAAA,IACZ;AACA,WAAO,KAAK;AAAA,EACd;AACF;AAGA,SAAS,iBAAiB,OAAwB;AAChD,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,UAAU,OAAW,QAAO;AAChC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,SAAO,OAAO;AAChB;AAGA,SAAS,OAAO,OAAyC;AACvD,MAAI,UAAU,OAAW,QAAO,aAAa,IAAI;AACjD,MACE,iBAAiBA,aACjB,iBAAiBC,QACjB,iBAAiB,WACjB,iBAAiBC,OACjB;AACA,WAAO;AAAA,EACT;AACA,SAAO,aAAa,KAAK;AAC3B;AAEA,SAAS,cAAc,OAA0C;AAC/D,SACE,UAAU,QACV,OAAO,UAAU,YACjB,CAAC,iBAAiB,KAAK,KACvB,CAAC,MAAM;AAEX;AAEA,SAAS,kBAAkB,KAAe;AACxC,MAAI,CAAC,cAAc,GAAG,EAAG,QAAO,OAAO,GAAG;AAC1C,QAAM,MAA2B,CAAA;AACjC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,GAAG,GAAG;AACxC,QAAI,OAAO,MAAM,YAAY,EAAE,WAAW,qBAAqB,GAAG;AAEhE,UAAI,CAAC,IAAI;AACT;AAAA,IACF;AACA,QAAI,CAAC,IAAI,kBAAkB,CAAC;AAAA,EAC9B;AACA,SAAO;AACT;AAIO,SAAS,WACd,IACS;AACT,QAAM,SAAS,GAAG,IAAI,kBAAkB;AACxC,SAAO,WAAW,MAAM;AAC1B;AAGO,SAAS,WACd,SACS;AACT,SAAQ,QAAwC,UAAA;AAClD;AAcO,MAAM,QAAwC;"}
@@ -25,6 +25,19 @@ export declare function createSingleRowRefProxy<T extends Record<string, any>>()
25
25
  * Used in callbacks like where, select, etc. to create type-safe references
26
26
  */
27
27
  export declare function createRefProxy<T extends Record<string, any>>(aliases: Array<string>): RefProxy<T> & T;
28
+ /**
29
+ * Creates a ref proxy with $selected namespace for SELECT fields
30
+ *
31
+ * Adds a $selected property that allows accessing SELECT fields via $selected.fieldName syntax.
32
+ * The $selected proxy creates paths like ['$selected', 'fieldName'] which directly reference
33
+ * the $selected property on the namespaced row.
34
+ *
35
+ * @param aliases - Array of table aliases to create proxies for
36
+ * @returns A ref proxy with table aliases and $selected namespace
37
+ */
38
+ export declare function createRefProxyWithSelected<T extends Record<string, any>>(aliases: Array<string>): RefProxy<T> & T & {
39
+ $selected: SingleRowRefProxy<any>;
40
+ };
28
41
  /**
29
42
  * Converts a value to an Expression
30
43
  * If it's a RefProxy, creates a Ref, otherwise creates a Value
@@ -112,6 +112,68 @@ function createRefProxy(aliases) {
112
112
  });
113
113
  return rootProxy;
114
114
  }
115
+ function createRefProxyWithSelected(aliases) {
116
+ const baseProxy = createRefProxy(aliases);
117
+ const cache = /* @__PURE__ */ new Map();
118
+ function createSelectedProxy(path) {
119
+ const pathKey = path.join(`.`);
120
+ if (cache.has(pathKey)) {
121
+ return cache.get(pathKey);
122
+ }
123
+ const proxy = new Proxy({}, {
124
+ get(target, prop, receiver) {
125
+ if (prop === `__refProxy`) return true;
126
+ if (prop === `__path`) return [`$selected`, ...path];
127
+ if (prop === `__type`) return void 0;
128
+ if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver);
129
+ const newPath = [...path, String(prop)];
130
+ return createSelectedProxy(newPath);
131
+ },
132
+ has(target, prop) {
133
+ if (prop === `__refProxy` || prop === `__path` || prop === `__type`)
134
+ return true;
135
+ return Reflect.has(target, prop);
136
+ },
137
+ ownKeys(target) {
138
+ return Reflect.ownKeys(target);
139
+ },
140
+ getOwnPropertyDescriptor(target, prop) {
141
+ if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {
142
+ return { enumerable: false, configurable: true };
143
+ }
144
+ return Reflect.getOwnPropertyDescriptor(target, prop);
145
+ }
146
+ });
147
+ cache.set(pathKey, proxy);
148
+ return proxy;
149
+ }
150
+ const wrappedSelectedProxy = createSelectedProxy([]);
151
+ return new Proxy(baseProxy, {
152
+ get(target, prop, receiver) {
153
+ if (prop === `$selected`) {
154
+ return wrappedSelectedProxy;
155
+ }
156
+ return Reflect.get(target, prop, receiver);
157
+ },
158
+ has(target, prop) {
159
+ if (prop === `$selected`) return true;
160
+ return Reflect.has(target, prop);
161
+ },
162
+ ownKeys(target) {
163
+ return [...Reflect.ownKeys(target), `$selected`];
164
+ },
165
+ getOwnPropertyDescriptor(target, prop) {
166
+ if (prop === `$selected`) {
167
+ return {
168
+ enumerable: true,
169
+ configurable: true,
170
+ value: wrappedSelectedProxy
171
+ };
172
+ }
173
+ return Reflect.getOwnPropertyDescriptor(target, prop);
174
+ }
175
+ });
176
+ }
115
177
  function toExpression(value) {
116
178
  if (isRefProxy(value)) {
117
179
  return new PropRef(value.__path);
@@ -126,6 +188,7 @@ function isRefProxy(value) {
126
188
  }
127
189
  export {
128
190
  createRefProxy,
191
+ createRefProxyWithSelected,
129
192
  createSingleRowRefProxy,
130
193
  isRefProxy,
131
194
  toExpression
@@ -1 +1 @@
1
- {"version":3,"file":"ref-proxy.js","sources":["../../../../src/query/builder/ref-proxy.ts"],"sourcesContent":["import { PropRef, Value } from '../ir.js'\nimport type { BasicExpression } from '../ir.js'\nimport type { RefLeaf } from './types.js'\n\nexport interface RefProxy<T = any> {\n /** @internal */\n readonly __refProxy: true\n /** @internal */\n readonly __path: Array<string>\n /** @internal */\n readonly __type: T\n}\n\n/**\n * Type for creating a RefProxy for a single row/type without namespacing\n * Used in collection indexes and where clauses\n */\nexport type SingleRowRefProxy<T> =\n T extends Record<string, any>\n ? {\n [K in keyof T]: T[K] extends Record<string, any>\n ? SingleRowRefProxy<T[K]> & RefProxy<T[K]>\n : RefLeaf<T[K]>\n } & RefProxy<T>\n : RefProxy<T>\n\n/**\n * Creates a proxy object that records property access paths for a single row\n * Used in collection indexes and where clauses\n */\nexport function createSingleRowRefProxy<\n T extends Record<string, any>,\n>(): SingleRowRefProxy<T> {\n const cache = new Map<string, any>()\n\n function createProxy(path: Array<string>): any {\n const pathKey = path.join(`.`)\n if (cache.has(pathKey)) {\n return cache.get(pathKey)\n }\n\n const proxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return path\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const newPath = [...path, String(prop)]\n return createProxy(newPath)\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n })\n\n cache.set(pathKey, proxy)\n return proxy\n }\n\n // Return the root proxy that starts with an empty path\n return createProxy([]) as SingleRowRefProxy<T>\n}\n\n/**\n * Creates a proxy object that records property access paths\n * Used in callbacks like where, select, etc. to create type-safe references\n */\nexport function createRefProxy<T extends Record<string, any>>(\n aliases: Array<string>,\n): RefProxy<T> & T {\n const cache = new Map<string, any>()\n let accessId = 0 // Monotonic counter to record evaluation order\n\n function createProxy(path: Array<string>): any {\n const pathKey = path.join(`.`)\n if (cache.has(pathKey)) {\n return cache.get(pathKey)\n }\n\n const proxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return path\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const newPath = [...path, String(prop)]\n return createProxy(newPath)\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n const id = ++accessId\n const sentinelKey = `__SPREAD_SENTINEL__${path.join(`.`)}__${id}`\n if (!Object.prototype.hasOwnProperty.call(target, sentinelKey)) {\n Object.defineProperty(target, sentinelKey, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n }\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n })\n\n cache.set(pathKey, proxy)\n return proxy\n }\n\n // Create the root proxy with all aliases as top-level properties\n const rootProxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return []\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const propStr = String(prop)\n if (aliases.includes(propStr)) {\n return createProxy([propStr])\n }\n\n return undefined\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n if (typeof prop === `string` && aliases.includes(prop)) return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(_target) {\n return [...aliases, `__refProxy`, `__path`, `__type`]\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n if (typeof prop === `string` && aliases.includes(prop)) {\n return { enumerable: true, configurable: true }\n }\n return undefined\n },\n })\n\n return rootProxy\n}\n\n/**\n * Converts a value to an Expression\n * If it's a RefProxy, creates a Ref, otherwise creates a Value\n */\nexport function toExpression<T = any>(value: T): BasicExpression<T>\nexport function toExpression(value: RefProxy<any>): BasicExpression<any>\nexport function toExpression(value: any): BasicExpression<any> {\n if (isRefProxy(value)) {\n return new PropRef(value.__path)\n }\n // If it's already an Expression (Func, Ref, Value) or Agg, return it directly\n if (\n value &&\n typeof value === `object` &&\n `type` in value &&\n (value.type === `func` ||\n value.type === `ref` ||\n value.type === `val` ||\n value.type === `agg`)\n ) {\n return value\n }\n return new Value(value)\n}\n\n/**\n * Type guard to check if a value is a RefProxy\n */\nexport function isRefProxy(value: any): value is RefProxy {\n return value && typeof value === `object` && value.__refProxy === true\n}\n\n/**\n * Helper to create a Value expression from a literal\n */\nexport function val<T>(value: T): BasicExpression<T> {\n return new Value(value)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ref-proxy.js","sources":["../../../../src/query/builder/ref-proxy.ts"],"sourcesContent":["import { PropRef, Value } from '../ir.js'\nimport type { BasicExpression } from '../ir.js'\nimport type { RefLeaf } from './types.js'\n\nexport interface RefProxy<T = any> {\n /** @internal */\n readonly __refProxy: true\n /** @internal */\n readonly __path: Array<string>\n /** @internal */\n readonly __type: T\n}\n\n/**\n * Type for creating a RefProxy for a single row/type without namespacing\n * Used in collection indexes and where clauses\n */\nexport type SingleRowRefProxy<T> =\n T extends Record<string, any>\n ? {\n [K in keyof T]: T[K] extends Record<string, any>\n ? SingleRowRefProxy<T[K]> & RefProxy<T[K]>\n : RefLeaf<T[K]>\n } & RefProxy<T>\n : RefProxy<T>\n\n/**\n * Creates a proxy object that records property access paths for a single row\n * Used in collection indexes and where clauses\n */\nexport function createSingleRowRefProxy<\n T extends Record<string, any>,\n>(): SingleRowRefProxy<T> {\n const cache = new Map<string, any>()\n\n function createProxy(path: Array<string>): any {\n const pathKey = path.join(`.`)\n if (cache.has(pathKey)) {\n return cache.get(pathKey)\n }\n\n const proxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return path\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const newPath = [...path, String(prop)]\n return createProxy(newPath)\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n })\n\n cache.set(pathKey, proxy)\n return proxy\n }\n\n // Return the root proxy that starts with an empty path\n return createProxy([]) as SingleRowRefProxy<T>\n}\n\n/**\n * Creates a proxy object that records property access paths\n * Used in callbacks like where, select, etc. to create type-safe references\n */\nexport function createRefProxy<T extends Record<string, any>>(\n aliases: Array<string>,\n): RefProxy<T> & T {\n const cache = new Map<string, any>()\n let accessId = 0 // Monotonic counter to record evaluation order\n\n function createProxy(path: Array<string>): any {\n const pathKey = path.join(`.`)\n if (cache.has(pathKey)) {\n return cache.get(pathKey)\n }\n\n const proxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return path\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const newPath = [...path, String(prop)]\n return createProxy(newPath)\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n const id = ++accessId\n const sentinelKey = `__SPREAD_SENTINEL__${path.join(`.`)}__${id}`\n if (!Object.prototype.hasOwnProperty.call(target, sentinelKey)) {\n Object.defineProperty(target, sentinelKey, {\n enumerable: true,\n configurable: true,\n value: true,\n })\n }\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n })\n\n cache.set(pathKey, proxy)\n return proxy\n }\n\n // Create the root proxy with all aliases as top-level properties\n const rootProxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return []\n if (prop === `__type`) return undefined // Type is only for TypeScript inference\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const propStr = String(prop)\n if (aliases.includes(propStr)) {\n return createProxy([propStr])\n }\n\n return undefined\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n if (typeof prop === `string` && aliases.includes(prop)) return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(_target) {\n return [...aliases, `__refProxy`, `__path`, `__type`]\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n if (typeof prop === `string` && aliases.includes(prop)) {\n return { enumerable: true, configurable: true }\n }\n return undefined\n },\n })\n\n return rootProxy\n}\n\n/**\n * Creates a ref proxy with $selected namespace for SELECT fields\n *\n * Adds a $selected property that allows accessing SELECT fields via $selected.fieldName syntax.\n * The $selected proxy creates paths like ['$selected', 'fieldName'] which directly reference\n * the $selected property on the namespaced row.\n *\n * @param aliases - Array of table aliases to create proxies for\n * @returns A ref proxy with table aliases and $selected namespace\n */\nexport function createRefProxyWithSelected<T extends Record<string, any>>(\n aliases: Array<string>,\n): RefProxy<T> & T & { $selected: SingleRowRefProxy<any> } {\n const baseProxy = createRefProxy(aliases)\n\n // Create a proxy for $selected that prefixes all paths with '$selected'\n const cache = new Map<string, any>()\n\n function createSelectedProxy(path: Array<string>): any {\n const pathKey = path.join(`.`)\n if (cache.has(pathKey)) {\n return cache.get(pathKey)\n }\n\n const proxy = new Proxy({} as any, {\n get(target, prop, receiver) {\n if (prop === `__refProxy`) return true\n if (prop === `__path`) return [`$selected`, ...path]\n if (prop === `__type`) return undefined\n if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver)\n\n const newPath = [...path, String(prop)]\n return createSelectedProxy(newPath)\n },\n\n has(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`)\n return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n return Reflect.ownKeys(target)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {\n return { enumerable: false, configurable: true }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n })\n\n cache.set(pathKey, proxy)\n return proxy\n }\n\n const wrappedSelectedProxy = createSelectedProxy([])\n\n // Wrap the base proxy to also handle $selected access\n return new Proxy(baseProxy, {\n get(target, prop, receiver) {\n if (prop === `$selected`) {\n return wrappedSelectedProxy\n }\n return Reflect.get(target, prop, receiver)\n },\n\n has(target, prop) {\n if (prop === `$selected`) return true\n return Reflect.has(target, prop)\n },\n\n ownKeys(target) {\n return [...Reflect.ownKeys(target), `$selected`]\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === `$selected`) {\n return {\n enumerable: true,\n configurable: true,\n value: wrappedSelectedProxy,\n }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n }) as RefProxy<T> & T & { $selected: SingleRowRefProxy<any> }\n}\n\n/**\n * Converts a value to an Expression\n * If it's a RefProxy, creates a Ref, otherwise creates a Value\n */\nexport function toExpression<T = any>(value: T): BasicExpression<T>\nexport function toExpression(value: RefProxy<any>): BasicExpression<any>\nexport function toExpression(value: any): BasicExpression<any> {\n if (isRefProxy(value)) {\n return new PropRef(value.__path)\n }\n // If it's already an Expression (Func, Ref, Value) or Agg, return it directly\n if (\n value &&\n typeof value === `object` &&\n `type` in value &&\n (value.type === `func` ||\n value.type === `ref` ||\n value.type === `val` ||\n value.type === `agg`)\n ) {\n return value\n }\n return new Value(value)\n}\n\n/**\n * Type guard to check if a value is a RefProxy\n */\nexport function isRefProxy(value: any): value is RefProxy {\n return value && typeof value === `object` && value.__refProxy === true\n}\n\n/**\n * Helper to create a Value expression from a literal\n */\nexport function val<T>(value: T): BasicExpression<T> {\n return new Value(value)\n}\n"],"names":[],"mappings":"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"}
@@ -239,6 +239,26 @@ export type GroupByCallback<TContext extends Context> = (refs: RefsForContext<TC
239
239
  * Example: `(refs) => eq(refs.users.id, refs.orders.userId)`
240
240
  */
241
241
  export type JoinOnCallback<TContext extends Context> = (refs: RefsForContext<TContext>) => any;
242
+ /**
243
+ * FunctionalHavingRow - Type for the row parameter in functional having callbacks
244
+ *
245
+ * Functional having callbacks receive a namespaced row that includes:
246
+ * - Table data from the schema (when available)
247
+ * - $selected: The SELECT result fields (when select() has been called)
248
+ *
249
+ * After `select()` is called, this type includes `$selected` which provides access
250
+ * to the SELECT result fields via `$selected.fieldName` syntax.
251
+ *
252
+ * Note: When used with GROUP BY, functional having receives `{ $selected: ... }` with the
253
+ * aggregated SELECT results. When used without GROUP BY, it receives the full namespaced row
254
+ * which includes both table data and `$selected`.
255
+ *
256
+ * Example: `({ $selected }) => $selected.sessionCount > 2`
257
+ * Example (no GROUP BY): `(row) => row.user.salary > 70000 && row.$selected.user_count > 2`
258
+ */
259
+ export type FunctionalHavingRow<TContext extends Context> = TContext[`schema`] & (TContext[`result`] extends object ? {
260
+ $selected: TContext[`result`];
261
+ } : {});
242
262
  /**
243
263
  * RefProxyForContext - Creates ref proxies for all tables/collections in a query context
244
264
  *
@@ -258,13 +278,18 @@ export type JoinOnCallback<TContext extends Context> = (refs: RefsForContext<TCo
258
278
  *
259
279
  * The logic prioritizes optional chaining by always placing `undefined` outside when
260
280
  * a type is both optional and nullable (e.g., `string | null | undefined`).
281
+ *
282
+ * After `select()` is called, this type also includes `$selected` which provides access
283
+ * to the SELECT result fields via `$selected.fieldName` syntax.
261
284
  */
262
285
  export type RefsForContext<TContext extends Context> = {
263
286
  [K in keyof TContext[`schema`]]: IsNonExactOptional<TContext[`schema`][K]> extends true ? IsNonExactNullable<TContext[`schema`][K]> extends true ? // T is both non-exact optional and non-exact nullable (e.g., string | null | undefined)
264
287
  Ref<NonNullable<TContext[`schema`][K]>> | undefined : // T is optional (T | undefined) but not exactly undefined, and not nullable
265
288
  Ref<NonUndefined<TContext[`schema`][K]>> | undefined : IsNonExactNullable<TContext[`schema`][K]> extends true ? // T is nullable (T | null) but not exactly null, and not optional
266
289
  Ref<NonNull<TContext[`schema`][K]>> | null : Ref<TContext[`schema`][K]>;
267
- };
290
+ } & (TContext[`result`] extends object ? {
291
+ $selected: Ref<TContext[`result`]>;
292
+ } : {});
268
293
  /**
269
294
  * Type Detection Helpers
270
295
  *
@@ -31,10 +31,37 @@ function compileExpressionInternal(expr, isSingleRow) {
31
31
  }
32
32
  }
33
33
  function compileRef(ref) {
34
- const [tableAlias, ...propertyPath] = ref.path;
35
- if (!tableAlias) {
34
+ const [namespace, ...propertyPath] = ref.path;
35
+ if (!namespace) {
36
36
  throw new EmptyReferencePathError();
37
37
  }
38
+ if (namespace === `$selected`) {
39
+ if (propertyPath.length === 0) {
40
+ return (namespacedRow) => namespacedRow.$selected;
41
+ } else if (propertyPath.length === 1) {
42
+ const prop = propertyPath[0];
43
+ return (namespacedRow) => {
44
+ const selectResults = namespacedRow.$selected;
45
+ return selectResults?.[prop];
46
+ };
47
+ } else {
48
+ return (namespacedRow) => {
49
+ const selectResults = namespacedRow.$selected;
50
+ if (selectResults === void 0) {
51
+ return void 0;
52
+ }
53
+ let value = selectResults;
54
+ for (const prop of propertyPath) {
55
+ if (value == null) {
56
+ return value;
57
+ }
58
+ value = value[prop];
59
+ }
60
+ return value;
61
+ };
62
+ }
63
+ }
64
+ const tableAlias = namespace;
38
65
  if (propertyPath.length === 0) {
39
66
  return (namespacedRow) => namespacedRow[tableAlias];
40
67
  } else if (propertyPath.length === 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"evaluators.js","sources":["../../../../src/query/compiler/evaluators.ts"],"sourcesContent":["import {\n EmptyReferencePathError,\n UnknownExpressionTypeError,\n UnknownFunctionError,\n} from '../../errors.js'\nimport { areValuesEqual, normalizeValue } from '../../utils/comparison.js'\nimport type { BasicExpression, Func, PropRef } from '../ir.js'\nimport type { NamespacedRow } from '../../types.js'\n\n/**\n * Helper function to check if a value is null or undefined (represents UNKNOWN in 3-valued logic)\n */\nfunction isUnknown(value: any): boolean {\n return value === null || value === undefined\n}\n\n/**\n * Converts a 3-valued logic result to a boolean for use in WHERE/HAVING filters.\n * In SQL, UNKNOWN (null) values in WHERE clauses exclude rows, matching false behavior.\n *\n * @param result - The 3-valued logic result: true, false, or null (UNKNOWN)\n * @returns true only if result is explicitly true, false otherwise\n *\n * Truth table:\n * - true → true (include row)\n * - false → false (exclude row)\n * - null (UNKNOWN) → false (exclude row, matching SQL behavior)\n */\nexport function toBooleanPredicate(result: boolean | null): boolean {\n return result === true\n}\n\n/**\n * Compiled expression evaluator function type\n */\nexport type CompiledExpression = (namespacedRow: NamespacedRow) => any\n\n/**\n * Compiled single-row expression evaluator function type\n */\nexport type CompiledSingleRowExpression = (item: Record<string, unknown>) => any\n\n/**\n * Compiles an expression into an optimized evaluator function.\n * This eliminates branching during evaluation by pre-compiling the expression structure.\n */\nexport function compileExpression(\n expr: BasicExpression,\n isSingleRow: boolean = false,\n): CompiledExpression | CompiledSingleRowExpression {\n const compiledFn = compileExpressionInternal(expr, isSingleRow)\n return compiledFn\n}\n\n/**\n * Compiles a single-row expression into an optimized evaluator function.\n */\nexport function compileSingleRowExpression(\n expr: BasicExpression,\n): CompiledSingleRowExpression {\n const compiledFn = compileExpressionInternal(expr, true)\n return compiledFn as CompiledSingleRowExpression\n}\n\n/**\n * Internal unified expression compiler that handles both namespaced and single-row evaluation\n */\nfunction compileExpressionInternal(\n expr: BasicExpression,\n isSingleRow: boolean,\n): (data: any) => any {\n switch (expr.type) {\n case `val`: {\n // For constant values, return a function that just returns the value\n const value = expr.value\n return () => value\n }\n\n case `ref`: {\n // For references, compile based on evaluation mode\n return isSingleRow ? compileSingleRowRef(expr) : compileRef(expr)\n }\n\n case `func`: {\n // For functions, use the unified compiler\n return compileFunction(expr, isSingleRow)\n }\n\n default:\n throw new UnknownExpressionTypeError((expr as any).type)\n }\n}\n\n/**\n * Compiles a reference expression into an optimized evaluator\n */\nfunction compileRef(ref: PropRef): CompiledExpression {\n const [tableAlias, ...propertyPath] = ref.path\n\n if (!tableAlias) {\n throw new EmptyReferencePathError()\n }\n\n // Pre-compile the property path navigation\n if (propertyPath.length === 0) {\n // Simple table reference\n return (namespacedRow) => namespacedRow[tableAlias]\n } else if (propertyPath.length === 1) {\n // Single property access - most common case\n const prop = propertyPath[0]!\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n return tableData?.[prop]\n }\n } else {\n // Multiple property navigation\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n if (tableData === undefined) {\n return undefined\n }\n\n let value: any = tableData\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n }\n}\n\n/**\n * Compiles a reference expression for single-row evaluation\n */\nfunction compileSingleRowRef(ref: PropRef): CompiledSingleRowExpression {\n const propertyPath = ref.path\n\n // This function works for all path lengths including empty path\n return (item) => {\n let value: any = item\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n}\n\n/**\n * Compiles a function expression for both namespaced and single-row evaluation\n */\nfunction compileFunction(func: Func, isSingleRow: boolean): (data: any) => any {\n // Pre-compile all arguments using the appropriate compiler\n const compiledArgs = func.args.map((arg) =>\n compileExpressionInternal(arg, isSingleRow),\n )\n\n switch (func.name) {\n // Comparison operators\n case `eq`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = normalizeValue(argA(data))\n const b = normalizeValue(argB(data))\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n // Use areValuesEqual for proper Uint8Array/Buffer comparison\n return areValuesEqual(a, b)\n }\n }\n case `gt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a > b\n }\n }\n case `gte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a >= b\n }\n }\n case `lt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a < b\n }\n }\n case `lte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a <= b\n }\n }\n\n // Boolean operators\n case `and`:\n return (data) => {\n // 3-valued logic for AND:\n // - false AND anything = false (short-circuit)\n // - null AND false = false\n // - null AND anything (except false) = null\n // - anything (except false) AND null = null\n // - true AND true = true\n let hasUnknown = false\n for (const compiledArg of compiledArgs) {\n const result = compiledArg(data)\n if (result === false) {\n return false\n }\n if (isUnknown(result)) {\n hasUnknown = true\n }\n }\n // If we got here, no operand was false\n // If any operand was null, return null (UNKNOWN)\n if (hasUnknown) {\n return null\n }\n\n return true\n }\n case `or`:\n return (data) => {\n // 3-valued logic for OR:\n // - true OR anything = true (short-circuit)\n // - null OR anything (except true) = null\n // - false OR false = false\n let hasUnknown = false\n for (const compiledArg of compiledArgs) {\n const result = compiledArg(data)\n if (result === true) {\n return true\n }\n if (isUnknown(result)) {\n hasUnknown = true\n }\n }\n // If we got here, no operand was true\n // If any operand was null, return null (UNKNOWN)\n if (hasUnknown) {\n return null\n }\n\n return false\n }\n case `not`: {\n const arg = compiledArgs[0]!\n return (data) => {\n // 3-valued logic for NOT:\n // - NOT null = null\n // - NOT true = false\n // - NOT false = true\n const result = arg(data)\n if (isUnknown(result)) {\n return null\n }\n return !result\n }\n }\n\n // Array operators\n case `in`: {\n const valueEvaluator = compiledArgs[0]!\n const arrayEvaluator = compiledArgs[1]!\n return (data) => {\n const value = valueEvaluator(data)\n const array = arrayEvaluator(data)\n // In 3-valued logic, if the value is null/undefined, return UNKNOWN\n if (isUnknown(value)) {\n return null\n }\n if (!Array.isArray(array)) {\n return false\n }\n return array.includes(value)\n }\n }\n\n // String operators\n case `like`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (data) => {\n const value = valueEvaluator(data)\n const pattern = patternEvaluator(data)\n // In 3-valued logic, if value or pattern is null/undefined, return UNKNOWN\n if (isUnknown(value) || isUnknown(pattern)) {\n return null\n }\n return evaluateLike(value, pattern, false)\n }\n }\n case `ilike`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (data) => {\n const value = valueEvaluator(data)\n const pattern = patternEvaluator(data)\n // In 3-valued logic, if value or pattern is null/undefined, return UNKNOWN\n if (isUnknown(value) || isUnknown(pattern)) {\n return null\n }\n return evaluateLike(value, pattern, true)\n }\n }\n\n // String functions\n case `upper`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return typeof value === `string` ? value.toUpperCase() : value\n }\n }\n case `lower`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return typeof value === `string` ? value.toLowerCase() : value\n }\n }\n case `length`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n if (typeof value === `string`) {\n return value.length\n }\n if (Array.isArray(value)) {\n return value.length\n }\n return 0\n }\n }\n case `concat`:\n return (data) => {\n return compiledArgs\n .map((evaluator) => {\n const arg = evaluator(data)\n try {\n return String(arg ?? ``)\n } catch {\n try {\n return JSON.stringify(arg) || ``\n } catch {\n return `[object]`\n }\n }\n })\n .join(``)\n }\n case `coalesce`:\n return (data) => {\n for (const evaluator of compiledArgs) {\n const value = evaluator(data)\n if (value !== null && value !== undefined) {\n return value\n }\n }\n return null\n }\n\n // Math functions\n case `add`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n return (a ?? 0) + (b ?? 0)\n }\n }\n case `subtract`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n return (a ?? 0) - (b ?? 0)\n }\n }\n case `multiply`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n return (a ?? 0) * (b ?? 0)\n }\n }\n case `divide`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n const divisor = b ?? 0\n return divisor !== 0 ? (a ?? 0) / divisor : null\n }\n }\n\n // Null/undefined checking functions\n case `isUndefined`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return value === undefined\n }\n }\n case `isNull`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return value === null\n }\n }\n\n default:\n throw new UnknownFunctionError(func.name)\n }\n}\n\n/**\n * Evaluates LIKE/ILIKE patterns\n */\nfunction evaluateLike(\n value: any,\n pattern: any,\n caseInsensitive: boolean,\n): boolean {\n if (typeof value !== `string` || typeof pattern !== `string`) {\n return false\n }\n\n const searchValue = caseInsensitive ? value.toLowerCase() : value\n const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern\n\n // Convert SQL LIKE pattern to regex\n // First escape all regex special chars except % and _\n let regexPattern = searchPattern.replace(/[.*+?^${}()|[\\]\\\\]/g, `\\\\$&`)\n\n // Then convert SQL wildcards to regex\n regexPattern = regexPattern.replace(/%/g, `.*`) // % matches any sequence\n regexPattern = regexPattern.replace(/_/g, `.`) // _ matches any single char\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(searchValue)\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluators.js","sources":["../../../../src/query/compiler/evaluators.ts"],"sourcesContent":["import {\n EmptyReferencePathError,\n UnknownExpressionTypeError,\n UnknownFunctionError,\n} from '../../errors.js'\nimport { areValuesEqual, normalizeValue } from '../../utils/comparison.js'\nimport type { BasicExpression, Func, PropRef } from '../ir.js'\nimport type { NamespacedRow } from '../../types.js'\n\n/**\n * Helper function to check if a value is null or undefined (represents UNKNOWN in 3-valued logic)\n */\nfunction isUnknown(value: any): boolean {\n return value === null || value === undefined\n}\n\n/**\n * Converts a 3-valued logic result to a boolean for use in WHERE/HAVING filters.\n * In SQL, UNKNOWN (null) values in WHERE clauses exclude rows, matching false behavior.\n *\n * @param result - The 3-valued logic result: true, false, or null (UNKNOWN)\n * @returns true only if result is explicitly true, false otherwise\n *\n * Truth table:\n * - true → true (include row)\n * - false → false (exclude row)\n * - null (UNKNOWN) → false (exclude row, matching SQL behavior)\n */\nexport function toBooleanPredicate(result: boolean | null): boolean {\n return result === true\n}\n\n/**\n * Compiled expression evaluator function type\n */\nexport type CompiledExpression = (namespacedRow: NamespacedRow) => any\n\n/**\n * Compiled single-row expression evaluator function type\n */\nexport type CompiledSingleRowExpression = (item: Record<string, unknown>) => any\n\n/**\n * Compiles an expression into an optimized evaluator function.\n * This eliminates branching during evaluation by pre-compiling the expression structure.\n */\nexport function compileExpression(\n expr: BasicExpression,\n isSingleRow: boolean = false,\n): CompiledExpression | CompiledSingleRowExpression {\n const compiledFn = compileExpressionInternal(expr, isSingleRow)\n return compiledFn\n}\n\n/**\n * Compiles a single-row expression into an optimized evaluator function.\n */\nexport function compileSingleRowExpression(\n expr: BasicExpression,\n): CompiledSingleRowExpression {\n const compiledFn = compileExpressionInternal(expr, true)\n return compiledFn as CompiledSingleRowExpression\n}\n\n/**\n * Internal unified expression compiler that handles both namespaced and single-row evaluation\n */\nfunction compileExpressionInternal(\n expr: BasicExpression,\n isSingleRow: boolean,\n): (data: any) => any {\n switch (expr.type) {\n case `val`: {\n // For constant values, return a function that just returns the value\n const value = expr.value\n return () => value\n }\n\n case `ref`: {\n // For references, compile based on evaluation mode\n return isSingleRow ? compileSingleRowRef(expr) : compileRef(expr)\n }\n\n case `func`: {\n // For functions, use the unified compiler\n return compileFunction(expr, isSingleRow)\n }\n\n default:\n throw new UnknownExpressionTypeError((expr as any).type)\n }\n}\n\n/**\n * Compiles a reference expression into an optimized evaluator\n */\nfunction compileRef(ref: PropRef): CompiledExpression {\n const [namespace, ...propertyPath] = ref.path\n\n if (!namespace) {\n throw new EmptyReferencePathError()\n }\n\n // Handle $selected namespace - references SELECT result fields\n if (namespace === `$selected`) {\n // Access $selected directly\n if (propertyPath.length === 0) {\n // Just $selected - return entire $selected object\n return (namespacedRow) => (namespacedRow as any).$selected\n } else if (propertyPath.length === 1) {\n // Single property access - most common case\n const prop = propertyPath[0]!\n return (namespacedRow) => {\n const selectResults = (namespacedRow as any).$selected\n return selectResults?.[prop]\n }\n } else {\n // Multiple property navigation (nested SELECT fields)\n return (namespacedRow) => {\n const selectResults = (namespacedRow as any).$selected\n if (selectResults === undefined) {\n return undefined\n }\n\n let value: any = selectResults\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n }\n }\n\n // Handle table alias namespace (existing logic)\n const tableAlias = namespace\n\n // Pre-compile the property path navigation\n if (propertyPath.length === 0) {\n // Simple table reference\n return (namespacedRow) => namespacedRow[tableAlias]\n } else if (propertyPath.length === 1) {\n // Single property access - most common case\n const prop = propertyPath[0]!\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n return tableData?.[prop]\n }\n } else {\n // Multiple property navigation\n return (namespacedRow) => {\n const tableData = namespacedRow[tableAlias]\n if (tableData === undefined) {\n return undefined\n }\n\n let value: any = tableData\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n }\n}\n\n/**\n * Compiles a reference expression for single-row evaluation\n */\nfunction compileSingleRowRef(ref: PropRef): CompiledSingleRowExpression {\n const propertyPath = ref.path\n\n // This function works for all path lengths including empty path\n return (item) => {\n let value: any = item\n for (const prop of propertyPath) {\n if (value == null) {\n return value\n }\n value = value[prop]\n }\n return value\n }\n}\n\n/**\n * Compiles a function expression for both namespaced and single-row evaluation\n */\nfunction compileFunction(func: Func, isSingleRow: boolean): (data: any) => any {\n // Pre-compile all arguments using the appropriate compiler\n const compiledArgs = func.args.map((arg) =>\n compileExpressionInternal(arg, isSingleRow),\n )\n\n switch (func.name) {\n // Comparison operators\n case `eq`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = normalizeValue(argA(data))\n const b = normalizeValue(argB(data))\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n // Use areValuesEqual for proper Uint8Array/Buffer comparison\n return areValuesEqual(a, b)\n }\n }\n case `gt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a > b\n }\n }\n case `gte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a >= b\n }\n }\n case `lt`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a < b\n }\n }\n case `lte`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n // In 3-valued logic, any comparison with null/undefined returns UNKNOWN\n if (isUnknown(a) || isUnknown(b)) {\n return null\n }\n return a <= b\n }\n }\n\n // Boolean operators\n case `and`:\n return (data) => {\n // 3-valued logic for AND:\n // - false AND anything = false (short-circuit)\n // - null AND false = false\n // - null AND anything (except false) = null\n // - anything (except false) AND null = null\n // - true AND true = true\n let hasUnknown = false\n for (const compiledArg of compiledArgs) {\n const result = compiledArg(data)\n if (result === false) {\n return false\n }\n if (isUnknown(result)) {\n hasUnknown = true\n }\n }\n // If we got here, no operand was false\n // If any operand was null, return null (UNKNOWN)\n if (hasUnknown) {\n return null\n }\n\n return true\n }\n case `or`:\n return (data) => {\n // 3-valued logic for OR:\n // - true OR anything = true (short-circuit)\n // - null OR anything (except true) = null\n // - false OR false = false\n let hasUnknown = false\n for (const compiledArg of compiledArgs) {\n const result = compiledArg(data)\n if (result === true) {\n return true\n }\n if (isUnknown(result)) {\n hasUnknown = true\n }\n }\n // If we got here, no operand was true\n // If any operand was null, return null (UNKNOWN)\n if (hasUnknown) {\n return null\n }\n\n return false\n }\n case `not`: {\n const arg = compiledArgs[0]!\n return (data) => {\n // 3-valued logic for NOT:\n // - NOT null = null\n // - NOT true = false\n // - NOT false = true\n const result = arg(data)\n if (isUnknown(result)) {\n return null\n }\n return !result\n }\n }\n\n // Array operators\n case `in`: {\n const valueEvaluator = compiledArgs[0]!\n const arrayEvaluator = compiledArgs[1]!\n return (data) => {\n const value = valueEvaluator(data)\n const array = arrayEvaluator(data)\n // In 3-valued logic, if the value is null/undefined, return UNKNOWN\n if (isUnknown(value)) {\n return null\n }\n if (!Array.isArray(array)) {\n return false\n }\n return array.includes(value)\n }\n }\n\n // String operators\n case `like`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (data) => {\n const value = valueEvaluator(data)\n const pattern = patternEvaluator(data)\n // In 3-valued logic, if value or pattern is null/undefined, return UNKNOWN\n if (isUnknown(value) || isUnknown(pattern)) {\n return null\n }\n return evaluateLike(value, pattern, false)\n }\n }\n case `ilike`: {\n const valueEvaluator = compiledArgs[0]!\n const patternEvaluator = compiledArgs[1]!\n return (data) => {\n const value = valueEvaluator(data)\n const pattern = patternEvaluator(data)\n // In 3-valued logic, if value or pattern is null/undefined, return UNKNOWN\n if (isUnknown(value) || isUnknown(pattern)) {\n return null\n }\n return evaluateLike(value, pattern, true)\n }\n }\n\n // String functions\n case `upper`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return typeof value === `string` ? value.toUpperCase() : value\n }\n }\n case `lower`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return typeof value === `string` ? value.toLowerCase() : value\n }\n }\n case `length`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n if (typeof value === `string`) {\n return value.length\n }\n if (Array.isArray(value)) {\n return value.length\n }\n return 0\n }\n }\n case `concat`:\n return (data) => {\n return compiledArgs\n .map((evaluator) => {\n const arg = evaluator(data)\n try {\n return String(arg ?? ``)\n } catch {\n try {\n return JSON.stringify(arg) || ``\n } catch {\n return `[object]`\n }\n }\n })\n .join(``)\n }\n case `coalesce`:\n return (data) => {\n for (const evaluator of compiledArgs) {\n const value = evaluator(data)\n if (value !== null && value !== undefined) {\n return value\n }\n }\n return null\n }\n\n // Math functions\n case `add`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n return (a ?? 0) + (b ?? 0)\n }\n }\n case `subtract`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n return (a ?? 0) - (b ?? 0)\n }\n }\n case `multiply`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n return (a ?? 0) * (b ?? 0)\n }\n }\n case `divide`: {\n const argA = compiledArgs[0]!\n const argB = compiledArgs[1]!\n return (data) => {\n const a = argA(data)\n const b = argB(data)\n const divisor = b ?? 0\n return divisor !== 0 ? (a ?? 0) / divisor : null\n }\n }\n\n // Null/undefined checking functions\n case `isUndefined`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return value === undefined\n }\n }\n case `isNull`: {\n const arg = compiledArgs[0]!\n return (data) => {\n const value = arg(data)\n return value === null\n }\n }\n\n default:\n throw new UnknownFunctionError(func.name)\n }\n}\n\n/**\n * Evaluates LIKE/ILIKE patterns\n */\nfunction evaluateLike(\n value: any,\n pattern: any,\n caseInsensitive: boolean,\n): boolean {\n if (typeof value !== `string` || typeof pattern !== `string`) {\n return false\n }\n\n const searchValue = caseInsensitive ? value.toLowerCase() : value\n const searchPattern = caseInsensitive ? pattern.toLowerCase() : pattern\n\n // Convert SQL LIKE pattern to regex\n // First escape all regex special chars except % and _\n let regexPattern = searchPattern.replace(/[.*+?^${}()|[\\]\\\\]/g, `\\\\$&`)\n\n // Then convert SQL wildcards to regex\n regexPattern = regexPattern.replace(/%/g, `.*`) // % matches any sequence\n regexPattern = regexPattern.replace(/_/g, `.`) // _ matches any single char\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(searchValue)\n}\n"],"names":[],"mappings":"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"}