@tanstack/db 0.0.14 → 0.0.16

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 (197) hide show
  1. package/dist/cjs/collection.cjs +117 -104
  2. package/dist/cjs/collection.cjs.map +1 -1
  3. package/dist/cjs/collection.d.cts +18 -21
  4. package/dist/cjs/index.cjs +31 -13
  5. package/dist/cjs/index.cjs.map +1 -1
  6. package/dist/cjs/index.d.cts +0 -1
  7. package/dist/cjs/query/builder/functions.cjs +107 -0
  8. package/dist/cjs/query/builder/functions.cjs.map +1 -0
  9. package/dist/cjs/query/builder/functions.d.cts +38 -0
  10. package/dist/cjs/query/builder/index.cjs +499 -0
  11. package/dist/cjs/query/builder/index.cjs.map +1 -0
  12. package/dist/cjs/query/builder/index.d.cts +324 -0
  13. package/dist/cjs/query/builder/ref-proxy.cjs +92 -0
  14. package/dist/cjs/query/builder/ref-proxy.cjs.map +1 -0
  15. package/dist/cjs/query/builder/ref-proxy.d.cts +28 -0
  16. package/dist/cjs/query/builder/types.d.cts +81 -0
  17. package/dist/cjs/query/compiler/evaluators.cjs +261 -0
  18. package/dist/cjs/query/compiler/evaluators.cjs.map +1 -0
  19. package/dist/cjs/query/compiler/evaluators.d.cts +11 -0
  20. package/dist/cjs/query/compiler/group-by.cjs +271 -0
  21. package/dist/cjs/query/compiler/group-by.cjs.map +1 -0
  22. package/dist/cjs/query/compiler/group-by.d.cts +7 -0
  23. package/dist/cjs/query/compiler/index.cjs +181 -0
  24. package/dist/cjs/query/compiler/index.cjs.map +1 -0
  25. package/dist/cjs/query/compiler/index.d.cts +15 -0
  26. package/dist/cjs/query/compiler/joins.cjs +116 -0
  27. package/dist/cjs/query/compiler/joins.cjs.map +1 -0
  28. package/dist/cjs/query/compiler/joins.d.cts +11 -0
  29. package/dist/cjs/query/compiler/order-by.cjs +89 -0
  30. package/dist/cjs/query/compiler/order-by.cjs.map +1 -0
  31. package/dist/cjs/query/compiler/order-by.d.cts +9 -0
  32. package/dist/cjs/query/compiler/select.cjs +57 -0
  33. package/dist/cjs/query/compiler/select.cjs.map +1 -0
  34. package/dist/cjs/query/compiler/select.d.cts +15 -0
  35. package/dist/cjs/query/index.d.cts +5 -5
  36. package/dist/cjs/query/ir.cjs +57 -0
  37. package/dist/cjs/query/ir.cjs.map +1 -0
  38. package/dist/cjs/query/ir.d.cts +81 -0
  39. package/dist/cjs/query/live-query-collection.cjs +224 -0
  40. package/dist/cjs/query/live-query-collection.cjs.map +1 -0
  41. package/dist/cjs/query/live-query-collection.d.cts +124 -0
  42. package/dist/cjs/transactions.cjs +20 -13
  43. package/dist/cjs/transactions.cjs.map +1 -1
  44. package/dist/cjs/transactions.d.cts +10 -1
  45. package/dist/cjs/types.d.cts +13 -0
  46. package/dist/esm/collection.d.ts +18 -21
  47. package/dist/esm/collection.js +118 -105
  48. package/dist/esm/collection.js.map +1 -1
  49. package/dist/esm/index.d.ts +0 -1
  50. package/dist/esm/index.js +30 -12
  51. package/dist/esm/query/builder/functions.d.ts +38 -0
  52. package/dist/esm/query/builder/functions.js +107 -0
  53. package/dist/esm/query/builder/functions.js.map +1 -0
  54. package/dist/esm/query/builder/index.d.ts +324 -0
  55. package/dist/esm/query/builder/index.js +499 -0
  56. package/dist/esm/query/builder/index.js.map +1 -0
  57. package/dist/esm/query/builder/ref-proxy.d.ts +28 -0
  58. package/dist/esm/query/builder/ref-proxy.js +92 -0
  59. package/dist/esm/query/builder/ref-proxy.js.map +1 -0
  60. package/dist/esm/query/builder/types.d.ts +81 -0
  61. package/dist/esm/query/compiler/evaluators.d.ts +11 -0
  62. package/dist/esm/query/compiler/evaluators.js +261 -0
  63. package/dist/esm/query/compiler/evaluators.js.map +1 -0
  64. package/dist/esm/query/compiler/group-by.d.ts +7 -0
  65. package/dist/esm/query/compiler/group-by.js +271 -0
  66. package/dist/esm/query/compiler/group-by.js.map +1 -0
  67. package/dist/esm/query/compiler/index.d.ts +15 -0
  68. package/dist/esm/query/compiler/index.js +181 -0
  69. package/dist/esm/query/compiler/index.js.map +1 -0
  70. package/dist/esm/query/compiler/joins.d.ts +11 -0
  71. package/dist/esm/query/compiler/joins.js +116 -0
  72. package/dist/esm/query/compiler/joins.js.map +1 -0
  73. package/dist/esm/query/compiler/order-by.d.ts +9 -0
  74. package/dist/esm/query/compiler/order-by.js +89 -0
  75. package/dist/esm/query/compiler/order-by.js.map +1 -0
  76. package/dist/esm/query/compiler/select.d.ts +15 -0
  77. package/dist/esm/query/compiler/select.js +57 -0
  78. package/dist/esm/query/compiler/select.js.map +1 -0
  79. package/dist/esm/query/index.d.ts +5 -5
  80. package/dist/esm/query/ir.d.ts +81 -0
  81. package/dist/esm/query/ir.js +57 -0
  82. package/dist/esm/query/ir.js.map +1 -0
  83. package/dist/esm/query/live-query-collection.d.ts +124 -0
  84. package/dist/esm/query/live-query-collection.js +224 -0
  85. package/dist/esm/query/live-query-collection.js.map +1 -0
  86. package/dist/esm/transactions.d.ts +10 -1
  87. package/dist/esm/transactions.js +20 -13
  88. package/dist/esm/transactions.js.map +1 -1
  89. package/dist/esm/types.d.ts +13 -0
  90. package/package.json +3 -4
  91. package/src/collection.ts +152 -129
  92. package/src/index.ts +0 -1
  93. package/src/query/builder/functions.ts +267 -0
  94. package/src/query/builder/index.ts +648 -0
  95. package/src/query/builder/ref-proxy.ts +156 -0
  96. package/src/query/builder/types.ts +282 -0
  97. package/src/query/compiler/evaluators.ts +315 -0
  98. package/src/query/compiler/group-by.ts +428 -0
  99. package/src/query/compiler/index.ts +276 -0
  100. package/src/query/compiler/joins.ts +228 -0
  101. package/src/query/compiler/order-by.ts +139 -0
  102. package/src/query/compiler/select.ts +173 -0
  103. package/src/query/index.ts +54 -5
  104. package/src/query/ir.ts +128 -0
  105. package/src/query/live-query-collection.ts +512 -0
  106. package/src/transactions.ts +27 -16
  107. package/src/types.ts +15 -0
  108. package/dist/cjs/query/compiled-query.cjs +0 -160
  109. package/dist/cjs/query/compiled-query.cjs.map +0 -1
  110. package/dist/cjs/query/compiled-query.d.cts +0 -20
  111. package/dist/cjs/query/evaluators.cjs +0 -161
  112. package/dist/cjs/query/evaluators.cjs.map +0 -1
  113. package/dist/cjs/query/evaluators.d.cts +0 -14
  114. package/dist/cjs/query/extractors.cjs +0 -122
  115. package/dist/cjs/query/extractors.cjs.map +0 -1
  116. package/dist/cjs/query/extractors.d.cts +0 -22
  117. package/dist/cjs/query/functions.cjs +0 -152
  118. package/dist/cjs/query/functions.cjs.map +0 -1
  119. package/dist/cjs/query/functions.d.cts +0 -21
  120. package/dist/cjs/query/group-by.cjs +0 -88
  121. package/dist/cjs/query/group-by.cjs.map +0 -1
  122. package/dist/cjs/query/group-by.d.cts +0 -40
  123. package/dist/cjs/query/joins.cjs +0 -141
  124. package/dist/cjs/query/joins.cjs.map +0 -1
  125. package/dist/cjs/query/joins.d.cts +0 -14
  126. package/dist/cjs/query/order-by.cjs +0 -185
  127. package/dist/cjs/query/order-by.cjs.map +0 -1
  128. package/dist/cjs/query/order-by.d.cts +0 -3
  129. package/dist/cjs/query/pipeline-compiler.cjs +0 -89
  130. package/dist/cjs/query/pipeline-compiler.cjs.map +0 -1
  131. package/dist/cjs/query/pipeline-compiler.d.cts +0 -10
  132. package/dist/cjs/query/query-builder.cjs +0 -307
  133. package/dist/cjs/query/query-builder.cjs.map +0 -1
  134. package/dist/cjs/query/query-builder.d.cts +0 -225
  135. package/dist/cjs/query/schema.d.cts +0 -100
  136. package/dist/cjs/query/select.cjs +0 -130
  137. package/dist/cjs/query/select.cjs.map +0 -1
  138. package/dist/cjs/query/select.d.cts +0 -3
  139. package/dist/cjs/query/types.d.cts +0 -189
  140. package/dist/cjs/query/utils.cjs +0 -154
  141. package/dist/cjs/query/utils.cjs.map +0 -1
  142. package/dist/cjs/query/utils.d.cts +0 -37
  143. package/dist/cjs/utils.cjs +0 -17
  144. package/dist/cjs/utils.cjs.map +0 -1
  145. package/dist/cjs/utils.d.cts +0 -3
  146. package/dist/esm/query/compiled-query.d.ts +0 -20
  147. package/dist/esm/query/compiled-query.js +0 -160
  148. package/dist/esm/query/compiled-query.js.map +0 -1
  149. package/dist/esm/query/evaluators.d.ts +0 -14
  150. package/dist/esm/query/evaluators.js +0 -161
  151. package/dist/esm/query/evaluators.js.map +0 -1
  152. package/dist/esm/query/extractors.d.ts +0 -22
  153. package/dist/esm/query/extractors.js +0 -122
  154. package/dist/esm/query/extractors.js.map +0 -1
  155. package/dist/esm/query/functions.d.ts +0 -21
  156. package/dist/esm/query/functions.js +0 -152
  157. package/dist/esm/query/functions.js.map +0 -1
  158. package/dist/esm/query/group-by.d.ts +0 -40
  159. package/dist/esm/query/group-by.js +0 -88
  160. package/dist/esm/query/group-by.js.map +0 -1
  161. package/dist/esm/query/joins.d.ts +0 -14
  162. package/dist/esm/query/joins.js +0 -141
  163. package/dist/esm/query/joins.js.map +0 -1
  164. package/dist/esm/query/order-by.d.ts +0 -3
  165. package/dist/esm/query/order-by.js +0 -185
  166. package/dist/esm/query/order-by.js.map +0 -1
  167. package/dist/esm/query/pipeline-compiler.d.ts +0 -10
  168. package/dist/esm/query/pipeline-compiler.js +0 -89
  169. package/dist/esm/query/pipeline-compiler.js.map +0 -1
  170. package/dist/esm/query/query-builder.d.ts +0 -225
  171. package/dist/esm/query/query-builder.js +0 -307
  172. package/dist/esm/query/query-builder.js.map +0 -1
  173. package/dist/esm/query/schema.d.ts +0 -100
  174. package/dist/esm/query/select.d.ts +0 -3
  175. package/dist/esm/query/select.js +0 -130
  176. package/dist/esm/query/select.js.map +0 -1
  177. package/dist/esm/query/types.d.ts +0 -189
  178. package/dist/esm/query/utils.d.ts +0 -37
  179. package/dist/esm/query/utils.js +0 -154
  180. package/dist/esm/query/utils.js.map +0 -1
  181. package/dist/esm/utils.d.ts +0 -3
  182. package/dist/esm/utils.js +0 -17
  183. package/dist/esm/utils.js.map +0 -1
  184. package/src/query/compiled-query.ts +0 -234
  185. package/src/query/evaluators.ts +0 -250
  186. package/src/query/extractors.ts +0 -214
  187. package/src/query/functions.ts +0 -297
  188. package/src/query/group-by.ts +0 -139
  189. package/src/query/joins.ts +0 -260
  190. package/src/query/order-by.ts +0 -264
  191. package/src/query/pipeline-compiler.ts +0 -149
  192. package/src/query/query-builder.ts +0 -902
  193. package/src/query/schema.ts +0 -268
  194. package/src/query/select.ts +0 -208
  195. package/src/query/types.ts +0 -418
  196. package/src/query/utils.ts +0 -245
  197. package/src/utils.ts +0 -15
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../../../src/query/builder/index.ts"],"sourcesContent":["import { CollectionImpl } from \"../../collection.js\"\nimport { CollectionRef, QueryRef } from \"../ir.js\"\nimport { createRefProxy, isRefProxy, toExpression } from \"./ref-proxy.js\"\nimport type { NamespacedRow } from \"../../types.js\"\nimport type {\n Aggregate,\n BasicExpression,\n JoinClause,\n OrderBy,\n OrderByClause,\n OrderByDirection,\n QueryIR,\n} from \"../ir.js\"\nimport type {\n Context,\n GroupByCallback,\n JoinOnCallback,\n MergeContext,\n MergeContextWithJoinType,\n OrderByCallback,\n RefProxyForContext,\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 if (Object.keys(source).length !== 1) {\n throw new Error(`Only one source is allowed in the ${context}`)\n }\n\n const alias = Object.keys(source)[0]!\n const sourceValue = source[alias]\n\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 Error(\n `A sub query passed to a ${context} must have a from clause itself`\n )\n }\n ref = new QueryRef(subQuery, alias)\n } else {\n throw new Error(`Invalid source`)\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 MergeContext<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 RefProxyForContext<\n MergeContext<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 Error(`Join condition must be an equality expression`)\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 * 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 RefProxyForContext<TContext>\n const expression = callback(refProxy)\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 RefProxyForContext<TContext>\n const expression = callback(refProxy)\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: RefProxyForContext<TContext>) => TSelectObject\n ): QueryBuilder<WithResult<TContext, ResultTypeFromSelect<TSelectObject>>> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefProxyForContext<TContext>\n const selectObject = callback(refProxy)\n\n // Check if any tables were spread during the callback\n const spreadSentinels = (refProxy as any).__spreadSentinels as Set<string>\n\n // Convert the select object to use expressions, including spread sentinels\n const select: Record<string, BasicExpression | Aggregate> = {}\n\n // First, add spread sentinels for any tables that were spread\n for (const spreadAlias of spreadSentinels) {\n const sentinelKey = `__SPREAD_SENTINEL__${spreadAlias}`\n select[sentinelKey] = toExpression(spreadAlias) // Use alias as a simple reference\n }\n\n // Then add the explicit select fields\n for (const [key, value] of Object.entries(selectObject)) {\n if (isRefProxy(value)) {\n select[key] = toExpression(value)\n } else if (\n typeof value === `object` &&\n `type` in value &&\n (value.type === `agg` || value.type === `func`)\n ) {\n select[key] = value as BasicExpression | Aggregate\n } else {\n select[key] = toExpression(value)\n }\n }\n\n return new BaseQueryBuilder({\n ...this.query,\n 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 direction: OrderByDirection = `asc`\n ): QueryBuilder<TContext> {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefProxyForContext<TContext>\n const result = callback(refProxy)\n\n // Create the new OrderBy structure with expression and direction\n const orderByClause: OrderByClause = {\n expression: toExpression(result),\n direction,\n }\n\n const existingOrderBy: OrderBy = this.query.orderBy || []\n\n return new BaseQueryBuilder({\n ...this.query,\n orderBy: [...existingOrderBy, orderByClause],\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 RefProxyForContext<TContext>\n const result = callback(refProxy)\n\n const newExpressions = Array.isArray(result)\n ? result.map((r) => toExpression(r))\n : [toExpression(result)]\n\n // Replace existing groupBy expressions instead of extending them\n return new BaseQueryBuilder({\n ...this.query,\n groupBy: 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 // 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 Error(`Query must have a from clause`)\n }\n return this.query as QueryIR\n }\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// Export the types from types.ts for convenience\nexport type { Context, Source, GetResult } from \"./types.js\"\n"],"names":["CollectionImpl","CollectionRef","QueryRef","refProxy","createRefProxy","toExpression","isRefProxy"],"mappings":"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"}
@@ -0,0 +1,324 @@
1
+ import { OrderByDirection, QueryIR } from '../ir.js';
2
+ import { Context, GroupByCallback, JoinOnCallback, MergeContext, MergeContextWithJoinType, OrderByCallback, RefProxyForContext, ResultTypeFromSelect, SchemaFromSource, SelectObject, Source, WhereCallback, WithResult } from './types.js';
3
+ export declare class BaseQueryBuilder<TContext extends Context = Context> {
4
+ private readonly query;
5
+ constructor(query?: Partial<QueryIR>);
6
+ /**
7
+ * Creates a CollectionRef or QueryRef from a source object
8
+ * @param source - An object with a single key-value pair
9
+ * @param context - Context string for error messages (e.g., "from clause", "join clause")
10
+ * @returns A tuple of [alias, ref] where alias is the source key and ref is the created reference
11
+ */
12
+ private _createRefForSource;
13
+ /**
14
+ * Specify the source table or subquery for the query
15
+ *
16
+ * @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
17
+ * @returns A QueryBuilder with the specified source
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * // Query from a collection
22
+ * query.from({ users: usersCollection })
23
+ *
24
+ * // Query from a subquery
25
+ * const activeUsers = query.from({ u: usersCollection }).where(({u}) => u.active)
26
+ * query.from({ activeUsers })
27
+ * ```
28
+ */
29
+ from<TSource extends Source>(source: TSource): QueryBuilder<{
30
+ baseSchema: SchemaFromSource<TSource>;
31
+ schema: SchemaFromSource<TSource>;
32
+ fromSourceName: keyof TSource & string;
33
+ hasJoins: false;
34
+ }>;
35
+ /**
36
+ * Join another table or subquery to the current query
37
+ *
38
+ * @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
39
+ * @param onCallback - A function that receives table references and returns the join condition
40
+ * @param type - The type of join: 'inner', 'left', 'right', or 'full' (defaults to 'left')
41
+ * @returns A QueryBuilder with the joined table available
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * // Left join users with posts
46
+ * query
47
+ * .from({ users: usersCollection })
48
+ * .join({ posts: postsCollection }, ({users, posts}) => eq(users.id, posts.userId))
49
+ *
50
+ * // Inner join with explicit type
51
+ * query
52
+ * .from({ u: usersCollection })
53
+ * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId), 'inner')
54
+ * ```
55
+ *
56
+ * // Join with a subquery
57
+ * const activeUsers = query.from({ u: usersCollection }).where(({u}) => u.active)
58
+ * query
59
+ * .from({ activeUsers })
60
+ * .join({ p: postsCollection }, ({u, p}) => eq(u.id, p.userId))
61
+ */
62
+ join<TSource extends Source, TJoinType extends `inner` | `left` | `right` | `full` = `left`>(source: TSource, onCallback: JoinOnCallback<MergeContext<TContext, SchemaFromSource<TSource>>>, type?: TJoinType): QueryBuilder<MergeContextWithJoinType<TContext, SchemaFromSource<TSource>, TJoinType>>;
63
+ /**
64
+ * Filter rows based on a condition
65
+ *
66
+ * @param callback - A function that receives table references and returns an expression
67
+ * @returns A QueryBuilder with the where condition applied
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * // Simple condition
72
+ * query
73
+ * .from({ users: usersCollection })
74
+ * .where(({users}) => gt(users.age, 18))
75
+ *
76
+ * // Multiple conditions
77
+ * query
78
+ * .from({ users: usersCollection })
79
+ * .where(({users}) => and(
80
+ * gt(users.age, 18),
81
+ * eq(users.active, true)
82
+ * ))
83
+ *
84
+ * // Multiple where calls are ANDed together
85
+ * query
86
+ * .from({ users: usersCollection })
87
+ * .where(({users}) => gt(users.age, 18))
88
+ * .where(({users}) => eq(users.active, true))
89
+ * ```
90
+ */
91
+ where(callback: WhereCallback<TContext>): QueryBuilder<TContext>;
92
+ /**
93
+ * Filter grouped rows based on aggregate conditions
94
+ *
95
+ * @param callback - A function that receives table references and returns an expression
96
+ * @returns A QueryBuilder with the having condition applied
97
+ *
98
+ * @example
99
+ * ```ts
100
+ * // Filter groups by count
101
+ * query
102
+ * .from({ posts: postsCollection })
103
+ * .groupBy(({posts}) => posts.userId)
104
+ * .having(({posts}) => gt(count(posts.id), 5))
105
+ *
106
+ * // Filter by average
107
+ * query
108
+ * .from({ orders: ordersCollection })
109
+ * .groupBy(({orders}) => orders.customerId)
110
+ * .having(({orders}) => gt(avg(orders.total), 100))
111
+ *
112
+ * // Multiple having calls are ANDed together
113
+ * query
114
+ * .from({ orders: ordersCollection })
115
+ * .groupBy(({orders}) => orders.customerId)
116
+ * .having(({orders}) => gt(count(orders.id), 5))
117
+ * .having(({orders}) => gt(avg(orders.total), 100))
118
+ * ```
119
+ */
120
+ having(callback: WhereCallback<TContext>): QueryBuilder<TContext>;
121
+ /**
122
+ * Select specific columns or computed values from the query
123
+ *
124
+ * @param callback - A function that receives table references and returns an object with selected fields or expressions
125
+ * @returns A QueryBuilder that returns only the selected fields
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * // Select specific columns
130
+ * query
131
+ * .from({ users: usersCollection })
132
+ * .select(({users}) => ({
133
+ * name: users.name,
134
+ * email: users.email
135
+ * }))
136
+ *
137
+ * // Select with computed values
138
+ * query
139
+ * .from({ users: usersCollection })
140
+ * .select(({users}) => ({
141
+ * fullName: concat(users.firstName, ' ', users.lastName),
142
+ * ageInMonths: mul(users.age, 12)
143
+ * }))
144
+ *
145
+ * // Select with aggregates (requires GROUP BY)
146
+ * query
147
+ * .from({ posts: postsCollection })
148
+ * .groupBy(({posts}) => posts.userId)
149
+ * .select(({posts, count}) => ({
150
+ * userId: posts.userId,
151
+ * postCount: count(posts.id)
152
+ * }))
153
+ * ```
154
+ */
155
+ select<TSelectObject extends SelectObject>(callback: (refs: RefProxyForContext<TContext>) => TSelectObject): QueryBuilder<WithResult<TContext, ResultTypeFromSelect<TSelectObject>>>;
156
+ /**
157
+ * Sort the query results by one or more columns
158
+ *
159
+ * @param callback - A function that receives table references and returns the field to sort by
160
+ * @param direction - Sort direction: 'asc' for ascending, 'desc' for descending (defaults to 'asc')
161
+ * @returns A QueryBuilder with the ordering applied
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * // Sort by a single column
166
+ * query
167
+ * .from({ users: usersCollection })
168
+ * .orderBy(({users}) => users.name)
169
+ *
170
+ * // Sort descending
171
+ * query
172
+ * .from({ users: usersCollection })
173
+ * .orderBy(({users}) => users.createdAt, 'desc')
174
+ *
175
+ * // Multiple sorts (chain orderBy calls)
176
+ * query
177
+ * .from({ users: usersCollection })
178
+ * .orderBy(({users}) => users.lastName)
179
+ * .orderBy(({users}) => users.firstName)
180
+ * ```
181
+ */
182
+ orderBy(callback: OrderByCallback<TContext>, direction?: OrderByDirection): QueryBuilder<TContext>;
183
+ /**
184
+ * Group rows by one or more columns for aggregation
185
+ *
186
+ * @param callback - A function that receives table references and returns the field(s) to group by
187
+ * @returns A QueryBuilder with grouping applied (enables aggregate functions in SELECT and HAVING)
188
+ *
189
+ * @example
190
+ * ```ts
191
+ * // Group by a single column
192
+ * query
193
+ * .from({ posts: postsCollection })
194
+ * .groupBy(({posts}) => posts.userId)
195
+ * .select(({posts, count}) => ({
196
+ * userId: posts.userId,
197
+ * postCount: count()
198
+ * }))
199
+ *
200
+ * // Group by multiple columns
201
+ * query
202
+ * .from({ sales: salesCollection })
203
+ * .groupBy(({sales}) => [sales.region, sales.category])
204
+ * .select(({sales, sum}) => ({
205
+ * region: sales.region,
206
+ * category: sales.category,
207
+ * totalSales: sum(sales.amount)
208
+ * }))
209
+ * ```
210
+ */
211
+ groupBy(callback: GroupByCallback<TContext>): QueryBuilder<TContext>;
212
+ /**
213
+ * Limit the number of rows returned by the query
214
+ * `orderBy` is required for `limit`
215
+ *
216
+ * @param count - Maximum number of rows to return
217
+ * @returns A QueryBuilder with the limit applied
218
+ *
219
+ * @example
220
+ * ```ts
221
+ * // Get top 5 posts by likes
222
+ * query
223
+ * .from({ posts: postsCollection })
224
+ * .orderBy(({posts}) => posts.likes, 'desc')
225
+ * .limit(5)
226
+ * ```
227
+ */
228
+ limit(count: number): QueryBuilder<TContext>;
229
+ /**
230
+ * Skip a number of rows before returning results
231
+ * `orderBy` is required for `offset`
232
+ *
233
+ * @param count - Number of rows to skip
234
+ * @returns A QueryBuilder with the offset applied
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * // Get second page of results
239
+ * query
240
+ * .from({ posts: postsCollection })
241
+ * .orderBy(({posts}) => posts.createdAt, 'desc')
242
+ * .offset(page * pageSize)
243
+ * .limit(pageSize)
244
+ * ```
245
+ */
246
+ offset(count: number): QueryBuilder<TContext>;
247
+ private _getCurrentAliases;
248
+ /**
249
+ * Functional variants of the query builder
250
+ * These are imperative function that are called for ery row.
251
+ * Warning: that these cannot be optimized by the query compiler, and may prevent
252
+ * some type of optimizations being possible.
253
+ * @example
254
+ * ```ts
255
+ * q.fn.select((row) => ({
256
+ * name: row.user.name.toUpperCase(),
257
+ * age: row.user.age + 1,
258
+ * }))
259
+ * ```
260
+ */
261
+ get fn(): {
262
+ /**
263
+ * Select fields using a function that operates on each row
264
+ * Warning: This cannot be optimized by the query compiler
265
+ *
266
+ * @param callback - A function that receives a row and returns the selected value
267
+ * @returns A QueryBuilder with functional selection applied
268
+ *
269
+ * @example
270
+ * ```ts
271
+ * // Functional select (not optimized)
272
+ * query
273
+ * .from({ users: usersCollection })
274
+ * .fn.select(row => ({
275
+ * name: row.users.name.toUpperCase(),
276
+ * age: row.users.age + 1,
277
+ * }))
278
+ * ```
279
+ */
280
+ select<TFuncSelectResult>(callback: (row: TContext[`schema`]) => TFuncSelectResult): QueryBuilder<WithResult<TContext, TFuncSelectResult>>;
281
+ /**
282
+ * Filter rows using a function that operates on each row
283
+ * Warning: This cannot be optimized by the query compiler
284
+ *
285
+ * @param callback - A function that receives a row and returns a boolean
286
+ * @returns A QueryBuilder with functional filtering applied
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * // Functional where (not optimized)
291
+ * query
292
+ * .from({ users: usersCollection })
293
+ * .fn.where(row => row.users.name.startsWith('A'))
294
+ * ```
295
+ */
296
+ where(callback: (row: TContext[`schema`]) => any): QueryBuilder<TContext>;
297
+ /**
298
+ * Filter grouped rows using a function that operates on each aggregated row
299
+ * Warning: This cannot be optimized by the query compiler
300
+ *
301
+ * @param callback - A function that receives an aggregated row and returns a boolean
302
+ * @returns A QueryBuilder with functional having filter applied
303
+ *
304
+ * @example
305
+ * ```ts
306
+ * // Functional having (not optimized)
307
+ * query
308
+ * .from({ posts: postsCollection })
309
+ * .groupBy(({posts}) => posts.userId)
310
+ * .fn.having(row => row.count > 5)
311
+ * ```
312
+ */
313
+ having(callback: (row: TContext[`schema`]) => any): QueryBuilder<TContext>;
314
+ };
315
+ _getQuery(): QueryIR;
316
+ }
317
+ export declare function buildQuery<TContext extends Context>(fn: (builder: InitialQueryBuilder) => QueryBuilder<TContext>): QueryIR;
318
+ export declare function getQueryIR(builder: BaseQueryBuilder | QueryBuilder<any> | InitialQueryBuilder): QueryIR;
319
+ export type InitialQueryBuilder = Pick<BaseQueryBuilder<Context>, `from`>;
320
+ export type InitialQueryBuilderConstructor = new () => InitialQueryBuilder;
321
+ export type QueryBuilder<TContext extends Context> = Omit<BaseQueryBuilder<TContext>, `from` | `_getQuery`>;
322
+ export declare const Query: InitialQueryBuilderConstructor;
323
+ export type ExtractContext<T> = T extends BaseQueryBuilder<infer TContext> ? TContext : T extends QueryBuilder<infer TContext> ? TContext : never;
324
+ export type { Context, Source, GetResult } from './types.js';
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const ir = require("../ir.cjs");
4
+ function createRefProxy(aliases) {
5
+ const cache = /* @__PURE__ */ new Map();
6
+ const spreadSentinels = /* @__PURE__ */ new Set();
7
+ function createProxy(path) {
8
+ const pathKey = path.join(`.`);
9
+ if (cache.has(pathKey)) {
10
+ return cache.get(pathKey);
11
+ }
12
+ const proxy = new Proxy({}, {
13
+ get(target, prop, receiver) {
14
+ if (prop === `__refProxy`) return true;
15
+ if (prop === `__path`) return path;
16
+ if (prop === `__type`) return void 0;
17
+ if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver);
18
+ const newPath = [...path, String(prop)];
19
+ return createProxy(newPath);
20
+ },
21
+ has(target, prop) {
22
+ if (prop === `__refProxy` || prop === `__path` || prop === `__type`)
23
+ return true;
24
+ return Reflect.has(target, prop);
25
+ },
26
+ ownKeys(target) {
27
+ if (path.length === 1) {
28
+ const aliasName = path[0];
29
+ spreadSentinels.add(aliasName);
30
+ }
31
+ return Reflect.ownKeys(target);
32
+ },
33
+ getOwnPropertyDescriptor(target, prop) {
34
+ if (prop === `__refProxy` || prop === `__path` || prop === `__type`) {
35
+ return { enumerable: false, configurable: true };
36
+ }
37
+ return Reflect.getOwnPropertyDescriptor(target, prop);
38
+ }
39
+ });
40
+ cache.set(pathKey, proxy);
41
+ return proxy;
42
+ }
43
+ const rootProxy = new Proxy({}, {
44
+ get(target, prop, receiver) {
45
+ if (prop === `__refProxy`) return true;
46
+ if (prop === `__path`) return [];
47
+ if (prop === `__type`) return void 0;
48
+ if (prop === `__spreadSentinels`) return spreadSentinels;
49
+ if (typeof prop === `symbol`) return Reflect.get(target, prop, receiver);
50
+ const propStr = String(prop);
51
+ if (aliases.includes(propStr)) {
52
+ return createProxy([propStr]);
53
+ }
54
+ return void 0;
55
+ },
56
+ has(target, prop) {
57
+ if (prop === `__refProxy` || prop === `__path` || prop === `__type` || prop === `__spreadSentinels`)
58
+ return true;
59
+ if (typeof prop === `string` && aliases.includes(prop)) return true;
60
+ return Reflect.has(target, prop);
61
+ },
62
+ ownKeys(_target) {
63
+ return [...aliases, `__refProxy`, `__path`, `__type`, `__spreadSentinels`];
64
+ },
65
+ getOwnPropertyDescriptor(target, prop) {
66
+ if (prop === `__refProxy` || prop === `__path` || prop === `__type` || prop === `__spreadSentinels`) {
67
+ return { enumerable: false, configurable: true };
68
+ }
69
+ if (typeof prop === `string` && aliases.includes(prop)) {
70
+ return { enumerable: true, configurable: true };
71
+ }
72
+ return void 0;
73
+ }
74
+ });
75
+ return rootProxy;
76
+ }
77
+ function toExpression(value) {
78
+ if (isRefProxy(value)) {
79
+ return new ir.PropRef(value.__path);
80
+ }
81
+ if (value && typeof value === `object` && `type` in value && (value.type === `func` || value.type === `ref` || value.type === `val` || value.type === `agg`)) {
82
+ return value;
83
+ }
84
+ return new ir.Value(value);
85
+ }
86
+ function isRefProxy(value) {
87
+ return value && typeof value === `object` && value.__refProxy === true;
88
+ }
89
+ exports.createRefProxy = createRefProxy;
90
+ exports.isRefProxy = isRefProxy;
91
+ exports.toExpression = toExpression;
92
+ //# sourceMappingURL=ref-proxy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ref-proxy.cjs","sources":["../../../../src/query/builder/ref-proxy.ts"],"sourcesContent":["import { PropRef, Value } from \"../ir.js\"\nimport type { BasicExpression } from \"../ir.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 * 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 const spreadSentinels = new Set<string>() // Track which aliases have been spread\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 // If this is a table-level proxy (path length 1), mark it as spread\n if (path.length === 1) {\n const aliasName = path[0]!\n spreadSentinels.add(aliasName)\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 (prop === `__spreadSentinels`) return spreadSentinels // Expose spread sentinels\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 (\n prop === `__refProxy` ||\n prop === `__path` ||\n prop === `__type` ||\n prop === `__spreadSentinels`\n )\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`, `__spreadSentinels`]\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (\n prop === `__refProxy` ||\n prop === `__path` ||\n prop === `__type` ||\n prop === `__spreadSentinels`\n ) {\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":["PropRef","Value"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { BasicExpression } from '../ir.js';
2
+ export interface RefProxy<T = any> {
3
+ /** @internal */
4
+ readonly __refProxy: true;
5
+ /** @internal */
6
+ readonly __path: Array<string>;
7
+ /** @internal */
8
+ readonly __type: T;
9
+ }
10
+ /**
11
+ * Creates a proxy object that records property access paths
12
+ * Used in callbacks like where, select, etc. to create type-safe references
13
+ */
14
+ export declare function createRefProxy<T extends Record<string, any>>(aliases: Array<string>): RefProxy<T> & T;
15
+ /**
16
+ * Converts a value to an Expression
17
+ * If it's a RefProxy, creates a Ref, otherwise creates a Value
18
+ */
19
+ export declare function toExpression<T = any>(value: T): BasicExpression<T>;
20
+ export declare function toExpression(value: RefProxy<any>): BasicExpression<any>;
21
+ /**
22
+ * Type guard to check if a value is a RefProxy
23
+ */
24
+ export declare function isRefProxy(value: any): value is RefProxy;
25
+ /**
26
+ * Helper to create a Value expression from a literal
27
+ */
28
+ export declare function val<T>(value: T): BasicExpression<T>;
@@ -0,0 +1,81 @@
1
+ import { CollectionImpl } from '../../collection.js';
2
+ import { Aggregate, BasicExpression } from '../ir.js';
3
+ import { QueryBuilder } from './index.js';
4
+ export interface Context {
5
+ baseSchema: ContextSchema;
6
+ schema: ContextSchema;
7
+ fromSourceName: string;
8
+ hasJoins?: boolean;
9
+ joinTypes?: Record<string, `inner` | `left` | `right` | `full` | `outer` | `cross`>;
10
+ result?: any;
11
+ }
12
+ export type ContextSchema = Record<string, unknown>;
13
+ export type Source = {
14
+ [alias: string]: CollectionImpl<any, any> | QueryBuilder<Context>;
15
+ };
16
+ export type InferCollectionType<T> = T extends CollectionImpl<infer U> ? U : never;
17
+ export type SchemaFromSource<T extends Source> = Prettify<{
18
+ [K in keyof T]: T[K] extends CollectionImpl<infer U> ? U : T[K] extends QueryBuilder<infer TContext> ? GetResult<TContext> : never;
19
+ }>;
20
+ export type GetAliases<TContext extends Context> = keyof TContext[`schema`];
21
+ export type WhereCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
22
+ export type SelectObject<T extends Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>> = Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>>> = T;
23
+ export type ResultTypeFromSelect<TSelectObject> = {
24
+ [K in keyof TSelectObject]: TSelectObject[K] extends RefProxy<infer T> ? T : TSelectObject[K] extends BasicExpression<infer T> ? T : TSelectObject[K] extends Aggregate<infer T> ? T : TSelectObject[K] extends RefProxyFor<infer T> ? T : never;
25
+ };
26
+ export type OrderByCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
27
+ export type GroupByCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
28
+ export type JoinOnCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
29
+ export type RefProxyForContext<TContext extends Context> = {
30
+ [K in keyof TContext[`schema`]]: RefProxyFor<TContext[`schema`][K]>;
31
+ };
32
+ type IsExactlyUndefined<T> = [T] extends [undefined] ? true : false;
33
+ type IsOptional<T> = undefined extends T ? true : false;
34
+ type NonUndefined<T> = T extends undefined ? never : T;
35
+ export type RefProxyFor<T> = OmitRefProxy<IsExactlyUndefined<T> extends true ? RefProxy<T> : IsOptional<T> extends true ? NonUndefined<T> extends Record<string, any> ? {
36
+ [K in keyof NonUndefined<T>]: NonUndefined<T>[K] extends Record<string, any> ? RefProxyFor<NonUndefined<T>[K] | undefined> & RefProxy<NonUndefined<T>[K] | undefined> : RefProxy<NonUndefined<T>[K] | undefined>;
37
+ } & RefProxy<T> : RefProxy<T> : T extends Record<string, any> ? {
38
+ [K in keyof T]: T[K] extends Record<string, any> ? RefProxyFor<T[K]> & RefProxy<T[K]> : RefProxy<T[K]>;
39
+ } & RefProxy<T> : RefProxy<T>>;
40
+ export type Ref<T> = RefProxyFor<T>;
41
+ type OmitRefProxy<T> = Omit<T, `__refProxy` | `__path` | `__type`>;
42
+ export interface RefProxy<T = any> {
43
+ /** @internal */
44
+ readonly __refProxy: true;
45
+ /** @internal */
46
+ readonly __path: Array<string>;
47
+ /** @internal */
48
+ readonly __type: T;
49
+ }
50
+ export type MergeContextWithJoinType<TContext extends Context, TNewSchema extends ContextSchema, TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`> = {
51
+ baseSchema: TContext[`baseSchema`];
52
+ schema: ApplyJoinOptionalityToMergedSchema<TContext[`schema`], TNewSchema, TJoinType, TContext[`fromSourceName`]>;
53
+ fromSourceName: TContext[`fromSourceName`];
54
+ hasJoins: true;
55
+ joinTypes: (TContext[`joinTypes`] extends Record<string, any> ? TContext[`joinTypes`] : {}) & {
56
+ [K in keyof TNewSchema & string]: TJoinType;
57
+ };
58
+ result: TContext[`result`];
59
+ };
60
+ export type ApplyJoinOptionalityToMergedSchema<TExistingSchema extends ContextSchema, TNewSchema extends ContextSchema, TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`, TFromSourceName extends string> = {
61
+ [K in keyof TExistingSchema]: K extends TFromSourceName ? TJoinType extends `right` | `full` ? TExistingSchema[K] | undefined : TExistingSchema[K] : TExistingSchema[K];
62
+ } & {
63
+ [K in keyof TNewSchema]: TJoinType extends `left` | `full` ? // New table becomes optional for left and full joins
64
+ TNewSchema[K] | undefined : TNewSchema[K];
65
+ };
66
+ export type GetResult<TContext extends Context> = Prettify<TContext[`result`] extends object ? TContext[`result`] : TContext[`hasJoins`] extends true ? TContext[`schema`] : TContext[`schema`][TContext[`fromSourceName`]]>;
67
+ export type ApplyJoinOptionalityToSchema<TSchema extends ContextSchema, TJoinTypes extends Record<string, string>, TFromSourceName extends string> = {
68
+ [K in keyof TSchema]: K extends TFromSourceName ? HasJoinType<TJoinTypes, `right` | `full`> extends true ? TSchema[K] | undefined : TSchema[K] : K extends keyof TJoinTypes ? TJoinTypes[K] extends `left` | `full` ? TSchema[K] | undefined : IsTableMadeOptionalBySubsequentJoins<K, TJoinTypes, TFromSourceName> extends true ? TSchema[K] | undefined : TSchema[K] : TSchema[K];
69
+ };
70
+ type IsTableMadeOptionalBySubsequentJoins<TTableAlias extends string | number | symbol, TJoinTypes extends Record<string, string>, TFromSourceName extends string> = TTableAlias extends TFromSourceName ? HasJoinType<TJoinTypes, `right` | `full`> : false;
71
+ export type HasJoinType<TJoinTypes extends Record<string, string>, TTargetTypes extends string> = true extends {
72
+ [K in keyof TJoinTypes]: TJoinTypes[K] extends TTargetTypes ? true : false;
73
+ }[keyof TJoinTypes] ? true : false;
74
+ export type MergeContext<TContext extends Context, TNewSchema extends ContextSchema> = MergeContextWithJoinType<TContext, TNewSchema, `left`>;
75
+ export type WithResult<TContext extends Context, TResult> = Prettify<Omit<TContext, `result`> & {
76
+ result: Prettify<TResult>;
77
+ }>;
78
+ export type Prettify<T> = {
79
+ [K in keyof T]: T[K];
80
+ } & {};
81
+ export {};