UNPKG

@tanstack/db

Version:

A reactive client store for building super fast apps on sync

1 lines 62 kB
{"version":3,"file":"index.cjs","sources":["../../../../src/query/builder/index.ts"],"sourcesContent":["import { CollectionImpl } from '../../collection/index.js'\nimport {\n Aggregate as AggregateExpr,\n CollectionRef,\n ConditionalSelect,\n Func as FuncExpr,\n INCLUDES_SCALAR_FIELD,\n IncludesSubquery,\n PropRef,\n QueryRef,\n UnionAll,\n UnionFrom,\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 isRefProxy,\n toExpression,\n} from './ref-proxy.js'\nimport {\n CaseWhenWrapper,\n ConcatToArrayWrapper,\n MaterializeWrapper,\n ToArrayWrapper,\n} from './functions.js'\nimport type { SourceClauseContext } from '../../errors.js'\nimport type { NamespacedRow, SingleResult } from '../../types.js'\nimport type {\n Aggregate,\n BasicExpression,\n IncludesMaterialization,\n JoinClause,\n OrderBy,\n OrderByDirection,\n QueryIR,\n Where,\n} from '../ir.js'\nimport type {\n CompareOptions,\n Context,\n ContextFromSource,\n ContextFromUnionBranches,\n ContextFromUnionSource,\n FunctionalHavingRow,\n GetResult,\n GroupByCallback,\n JoinOnCallback,\n MergeContextForJoinCallback,\n MergeContextWithJoinType,\n NonScalarSelectObject,\n OrderByCallback,\n OrderByOptions,\n RefsForContext,\n ResultTypeFromSelect,\n ResultTypeFromSelectValue,\n ScalarSelectValue,\n SchemaFromSource,\n SelectObject,\n SingleSource,\n Source,\n WhereCallback,\n WithResult,\n} from './types.js'\n\nconst UNION_ALL_SOURCE_CONTEXT = `unionAll clause` satisfies SourceClauseContext\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: SourceClauseContext,\n ): [string, CollectionRef | QueryRef] {\n const refs = this._createRefsForSource(source, context)\n if (refs.length !== 1) {\n throw new OnlyOneSourceAllowedError(context)\n }\n return refs[0]!\n }\n\n private _createRefsForSource<TSource extends Source>(\n source: TSource,\n context: SourceClauseContext,\n ): Array<[string, CollectionRef | QueryRef]> {\n if (typeof source === `string`) {\n throw new InvalidSourceTypeError(context, `string`)\n }\n\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 if (keys.length === 0) {\n throw new InvalidSourceTypeError(context, `empty object`)\n }\n\n if (context !== UNION_ALL_SOURCE_CONTEXT && keys.length !== 1) {\n throw new OnlyOneSourceAllowedError(context)\n }\n\n const refs: Array<[string, CollectionRef | QueryRef]> = []\n for (const alias of keys) {\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 refs.push([alias, ref])\n }\n\n return refs\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: SingleSource<TSource>,\n ): QueryBuilder<ContextFromSource<TSource>> {\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 * Union multiple independent source streams in one query.\n *\n * @param source - An object with one or more aliases mapped to collections or subqueries\n * @returns A QueryBuilder with the unioned sources available\n *\n * @example\n * ```ts\n * query\n * .unionAll({ message: messagesCollection, toolCall: toolCallsCollection })\n * .orderBy(({ message, toolCall }) =>\n * coalesce(message.timestamp, toolCall.timestamp)\n * )\n * ```\n */\n unionAll<TSource extends Source>(\n source: TSource,\n ): QueryBuilder<ContextFromUnionSource<TSource>>\n unionAll<\n TBranches extends readonly [QueryBuilder<any>, ...Array<QueryBuilder<any>>],\n >(...branches: TBranches): QueryBuilder<ContextFromUnionBranches<TBranches>>\n unionAll(\n sourceOrBranch: Source | QueryBuilder<any>,\n ...branches: Array<QueryBuilder<any>>\n ): QueryBuilder<any> {\n if (sourceOrBranch instanceof BaseQueryBuilder) {\n return new BaseQueryBuilder({\n ...this.query,\n from: new UnionAll(\n [sourceOrBranch, ...branches].map((branch) =>\n (branch as unknown as BaseQueryBuilder)._getQuery(),\n ),\n ),\n }) as any\n }\n\n const refs = this._createRefsForSource(\n sourceOrBranch as Source,\n UNION_ALL_SOURCE_CONTEXT,\n )\n const from =\n refs.length === 1 ? refs[0]![1] : new UnionFrom(refs.map((r) => r[1]))\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 rawExpression = callback(refProxy)\n\n // Allow bare boolean column references like `.where(({ u }) => u.active)`\n // by converting ref proxies to PropRef expressions, the same way helper\n // functions like `not()` and `eq()` do via `toExpression()`.\n const expression = isRefProxy(rawExpression)\n ? toExpression(rawExpression)\n : rawExpression\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 (either regular or functional)\n const refProxy = (\n this.query.select || this.query.fnSelect\n ? createRefProxyWithSelected(aliases)\n : createRefProxy(aliases)\n ) as RefsForContext<TContext>\n const rawExpression = callback(refProxy)\n\n // Allow bare boolean column references like `.having(({ $selected }) => $selected.isActive)`\n // by converting ref proxies to PropRef expressions, the same way helper\n // functions like `not()` and `eq()` do via `toExpression()`.\n const expression = isRefProxy(rawExpression)\n ? toExpression(rawExpression)\n : rawExpression\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: (\n refs: RefsForContext<TContext>,\n ) => NonScalarSelectObject<TSelectObject>,\n ): QueryBuilder<WithResult<TContext, ResultTypeFromSelect<TSelectObject>>>\n select<TSelectValue extends ScalarSelectValue>(\n callback: (refs: RefsForContext<TContext>) => TSelectValue,\n ): QueryBuilder<WithResult<TContext, ResultTypeFromSelectValue<TSelectValue>>>\n select(\n callback: (\n refs: RefsForContext<TContext>,\n ) => SelectObject | ScalarSelectValue,\n ) {\n const aliases = this._getCurrentAliases()\n const refProxy = createRefProxy(aliases) as RefsForContext<TContext>\n let selectObject = callback(refProxy)\n\n // Returning a top-level alias directly is equivalent to spreading it.\n // Leaf refs like `row.name` must remain scalar selections.\n if (isRefProxy(selectObject) && selectObject.__path.length === 1) {\n const sentinelKey = `__SPREAD_SENTINEL__${selectObject.__path[0]}__0`\n selectObject = { [sentinelKey]: true }\n }\n\n const select = buildNestedSelect(selectObject, aliases)\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 (either regular or functional)\n const refProxy = (\n this.query.select || this.query.fnSelect\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}) => ({ country: 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 }) 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 if (this.query.from.type === `unionFrom`) {\n aliases.push(...this.query.from.sources.map((source) => source.alias))\n } else if (this.query.from.type === `unionAll`) {\n aliases.push(`*`)\n } else {\n aliases.push(this.query.from.alias)\n }\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 }) as any\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(\n obj: any,\n parentAliases: Array<string> = [],\n fieldName?: string,\n): any {\n if (obj instanceof BaseQueryBuilder) {\n if (!fieldName) {\n throw new Error(`Conditional include branch is missing a field name`)\n }\n return buildIncludesSubquery(obj, fieldName, parentAliases, `collection`)\n }\n if (obj instanceof ToArrayWrapper) {\n if (!(obj.query instanceof BaseQueryBuilder)) {\n throw new Error(`toArray() must wrap a subquery builder`)\n }\n if (!fieldName) {\n throw new Error(`Conditional toArray() branch is missing a field name`)\n }\n return buildIncludesSubquery(obj.query, fieldName, parentAliases, `array`)\n }\n if (obj instanceof ConcatToArrayWrapper) {\n if (!(obj.query instanceof BaseQueryBuilder)) {\n throw new Error(`concat(toArray(...)) must wrap a subquery builder`)\n }\n if (!fieldName) {\n throw new Error(\n `Conditional concat(toArray(...)) branch is missing a field name`,\n )\n }\n return buildIncludesSubquery(obj.query, fieldName, parentAliases, `concat`)\n }\n if (obj instanceof CaseWhenWrapper) {\n return buildConditionalSelect(obj, parentAliases, fieldName)\n }\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 if (v instanceof BaseQueryBuilder) {\n out[k] = buildIncludesSubquery(v, k, parentAliases, `collection`)\n continue\n }\n if (v instanceof ToArrayWrapper) {\n if (!(v.query instanceof BaseQueryBuilder)) {\n throw new Error(`toArray() must wrap a subquery builder`)\n }\n out[k] = buildIncludesSubquery(v.query, k, parentAliases, `array`)\n continue\n }\n if (v instanceof ConcatToArrayWrapper) {\n if (!(v.query instanceof BaseQueryBuilder)) {\n throw new Error(`concat(toArray(...)) must wrap a subquery builder`)\n }\n out[k] = buildIncludesSubquery(v.query, k, parentAliases, `concat`)\n continue\n }\n if (v instanceof MaterializeWrapper) {\n if (!(v.query instanceof BaseQueryBuilder)) {\n throw new Error(`materialize() must wrap a subquery builder`)\n }\n const childQuery = v.query._getQuery()\n const materialization: IncludesMaterialization = childQuery.singleResult\n ? `singleton`\n : `array`\n out[k] = buildIncludesSubquery(v.query, k, parentAliases, materialization)\n continue\n }\n if (v instanceof CaseWhenWrapper) {\n out[k] = buildConditionalSelect(v, parentAliases, k)\n continue\n }\n out[k] = buildNestedSelect(v, parentAliases, k)\n }\n return out\n}\n\nfunction buildConditionalSelect(\n wrapper: CaseWhenWrapper,\n parentAliases: Array<string>,\n fieldName?: string,\n): ConditionalSelect {\n const args = wrapper.args\n if (args.length < 2) {\n throw new Error(`caseWhen() requires at least two arguments`)\n }\n\n const hasDefaultValue = args.length % 2 === 1\n const pairCount = Math.floor(args.length / 2)\n const branches = []\n\n for (let i = 0; i < pairCount; i++) {\n branches.push({\n condition: toExpression(args[i * 2]),\n value: buildNestedSelect(args[i * 2 + 1], parentAliases, fieldName),\n })\n }\n\n const defaultValue = hasDefaultValue\n ? buildNestedSelect(args[args.length - 1], parentAliases, fieldName)\n : undefined\n\n return new ConditionalSelect(branches, defaultValue)\n}\n\n/**\n * Recursively collects all PropRef nodes from an expression tree.\n */\nfunction collectRefsFromExpression(expr: BasicExpression): Array<PropRef> {\n const refs: Array<PropRef> = []\n switch (expr.type) {\n case `ref`:\n refs.push(expr)\n break\n case `func`:\n for (const arg of (expr as any).args ?? []) {\n refs.push(...collectRefsFromExpression(arg))\n }\n break\n default:\n break\n }\n return refs\n}\n\n/**\n * Checks whether a WHERE clause references any parent alias.\n */\nfunction referencesParent(where: Where, parentAliases: Array<string>): boolean {\n const expr =\n typeof where === `object` && `expression` in where\n ? where.expression\n : where\n return collectRefsFromExpression(expr).some(\n (ref) => ref.path[0] != null && parentAliases.includes(ref.path[0]),\n )\n}\n\n/**\n * Builds an IncludesSubquery IR node from a child query builder.\n * Extracts the correlation condition from the child's WHERE clauses by finding\n * an eq() predicate that references both a parent alias and a child alias.\n */\nfunction buildIncludesSubquery(\n childBuilder: BaseQueryBuilder,\n fieldName: string,\n parentAliases: Array<string>,\n materialization: IncludesMaterialization,\n): IncludesSubquery {\n const childQuery = childBuilder._getQuery()\n\n // Collect child's own aliases\n const childAliases = collectQueryAliases(childQuery)\n\n // Walk child's WHERE clauses to find the correlation condition.\n // The correlation eq() may be a standalone WHERE or nested inside a top-level and().\n let parentRef: PropRef | undefined\n let childRef: PropRef | undefined\n let correlationWhereIndex = -1\n let correlationAndArgIndex = -1 // >= 0 when found inside an and()\n\n if (childQuery.where) {\n for (let i = 0; i < childQuery.where.length; i++) {\n const where = childQuery.where[i]!\n const expr =\n typeof where === `object` && `expression` in where\n ? where.expression\n : where\n\n // Try standalone eq()\n if (\n expr.type === `func` &&\n expr.name === `eq` &&\n expr.args.length === 2\n ) {\n const result = extractCorrelation(\n expr.args[0]!,\n expr.args[1]!,\n parentAliases,\n childAliases,\n )\n if (result) {\n parentRef = result.parentRef\n childRef = result.childRef\n correlationWhereIndex = i\n break\n }\n }\n\n // Try inside top-level and()\n if (\n expr.type === `func` &&\n expr.name === `and` &&\n expr.args.length >= 2\n ) {\n for (let j = 0; j < expr.args.length; j++) {\n const arg = expr.args[j]!\n if (\n arg.type === `func` &&\n arg.name === `eq` &&\n arg.args.length === 2\n ) {\n const result = extractCorrelation(\n arg.args[0]!,\n arg.args[1]!,\n parentAliases,\n childAliases,\n )\n if (result) {\n parentRef = result.parentRef\n childRef = result.childRef\n correlationWhereIndex = i\n correlationAndArgIndex = j\n break\n }\n }\n }\n if (parentRef) break\n }\n }\n }\n\n if (!parentRef || !childRef || correlationWhereIndex === -1) {\n throw new Error(\n `Includes subquery for \"${fieldName}\" must have a WHERE clause with an eq() condition ` +\n `that correlates a parent field with a child field. ` +\n `Example: .where(({child}) => eq(child.parentId, parent.id))`,\n )\n }\n\n // Remove the correlation eq() from the child query's WHERE clauses.\n // If it was inside an and(), remove just that arg (collapsing the and() if needed).\n const modifiedWhere = [...childQuery.where!]\n if (correlationAndArgIndex >= 0) {\n const where = modifiedWhere[correlationWhereIndex]!\n const expr =\n typeof where === `object` && `expression` in where\n ? where.expression\n : where\n const remainingArgs = (expr as any).args.filter(\n (_: any, idx: number) => idx !== correlationAndArgIndex,\n )\n if (remainingArgs.length === 1) {\n // Collapse and() with single remaining arg to just that expression\n const isResidual =\n typeof where === `object` && `expression` in where && where.residual\n modifiedWhere[correlationWhereIndex] = isResidual\n ? { expression: remainingArgs[0], residual: true }\n : remainingArgs[0]\n } else {\n // Rebuild and() without the extracted arg\n const newAnd = new FuncExpr(`and`, remainingArgs)\n const isResidual =\n typeof where === `object` && `expression` in where && where.residual\n modifiedWhere[correlationWhereIndex] = isResidual\n ? { expression: newAnd, residual: true }\n : newAnd\n }\n } else {\n modifiedWhere.splice(correlationWhereIndex, 1)\n }\n\n // Separate remaining WHEREs into pure-child vs parent-referencing\n const pureChildWhere: Array<Where> = []\n const parentFilters: Array<Where> = []\n for (const w of modifiedWhere) {\n if (referencesParent(w, parentAliases)) {\n parentFilters.push(w)\n } else {\n pureChildWhere.push(w)\n }\n }\n\n // Collect distinct parent PropRefs from parent-referencing filters\n let parentProjection: Array<PropRef> | undefined\n if (parentFilters.length > 0) {\n const seen = new Set<string>()\n parentProjection = []\n for (const w of parentFilters) {\n const expr = typeof w === `object` && `expression` in w ? w.expression : w\n for (const ref of collectRefsFromExpression(expr)) {\n if (\n ref.path[0] != null &&\n parentAliases.includes(ref.path[0]) &&\n !seen.has(ref.path.join(`.`))\n ) {\n seen.add(ref.path.join(`.`))\n parentProjection.push(ref)\n }\n }\n }\n }\n\n const modifiedQuery: QueryIR = {\n ...childQuery,\n where: pureChildWhere.length > 0 ? pureChildWhere : undefined,\n }\n\n const rawChildSelect = modifiedQuery.select as any\n const hasObjectSelect =\n rawChildSelect === undefined || isPlainObject(rawChildSelect)\n let includesQuery = modifiedQuery\n let scalarField: string | undefined\n\n if (materialization === `concat`) {\n if (rawChildSelect === undefined || hasObjectSelect) {\n throw new Error(\n `concat(toArray(...)) for \"${fieldName}\" requires the subquery to select a scalar value`,\n )\n }\n }\n\n if (!hasObjectSelect) {\n if (materialization === `collection`) {\n throw new Error(\n `Includes subquery for \"${fieldName}\" must select an object when materializing as a Collection`,\n )\n }\n\n scalarField = INCLUDES_SCALAR_FIELD\n includesQuery = {\n ...modifiedQuery,\n select: {\n [scalarField]: rawChildSelect,\n },\n }\n }\n\n return new IncludesSubquery(\n includesQuery,\n parentRef,\n childRef,\n fieldName,\n parentFilters.length > 0 ? parentFilters : undefined,\n parentProjection,\n materialization,\n scalarField,\n )\n}\n\nfunction collectQueryAliases(query: QueryIR): Array<string> {\n const aliases = new Set<string>(collectFromAliases(query.from))\n if (query.join) {\n for (const join of query.join) {\n aliases.add(join.from.alias)\n }\n }\n return [...aliases]\n}\n\nfunction collectFromAliases(from: QueryIR[`from`]): Array<string> {\n if (from.type === `unionFrom`) {\n return from.sources.map((source) => source.alias)\n }\n\n if (from.type === `unionAll`) {\n return from.queries.flatMap((branch) => collectQueryAliases(branch))\n }\n\n return [from.alias]\n}\n\n/**\n * Checks if two eq() arguments form a parent-child correlation.\n * Returns the parent and child PropRefs if found, undefined otherwise.\n */\nfunction extractCorrelation(\n argA: BasicExpression,\n argB: BasicExpression,\n parentAliases: Array<string>,\n childAliases: Array<string>,\n): { parentRef: PropRef; childRef: PropRef } | undefined {\n if (argA.type === `ref` && argB.type === `ref`) {\n const aAlias = argA.path[0]\n const bAlias = argB.path[0]\n\n if (\n aAlias &&\n bAlias &&\n parentAliases.includes(aAlias) &&\n childAliases.includes(bAlias)\n ) {\n return { parentRef: argA, childRef: argB }\n }\n\n if (\n aAlias &&\n bAlias &&\n parentAliases.includes(bAlias) &&\n childAliases.includes(aAlias)\n ) {\n return { parentRef: argB, childRef: argA }\n }\n }\n\n return undefined\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<\n BaseQueryBuilder<Context>,\n `from` | `unionAll`\n>\n\nexport type InitialQueryBuilderConstructor = new () => InitialQueryBuilder\n\nexport type QueryBuilder<TContext extends Context> = Omit<\n BaseQueryBuilder<TContext>,\n `from` | `unionAll` | `_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 ContextSchema,\n ContextFromSource,\n ContextFromUnionBranches,\n ContextFromUnionSource,\n Source,\n GetResult,\n RefLeaf as Ref,\n InferResultType,\n // Types used in public method signatures that must be exported\n // for declaration emit to work (see https://github.com/TanStack/db/issues/1012)\n SchemaFromSource,\n SingleSource,\n InferCollectionType,\n MergeContextWithJoinType,\n MergeContextForJoinCallback,\n ApplyJoinOptionalityToMergedSchema,\n ResultTypeFromSelect,\n WithResult,\n JoinOnCallback,\n RefsForContext,\n WhereCallback,\n OrderByCallback,\n GroupByCallback,\n SelectObject,\n FunctionalHavingRow,\n Prettify,\n} from './types.js'\n"],"names":["OnlyOneSourceAllowedError","InvalidSourceTypeError","CollectionImpl","CollectionRef","SubQueryMustHaveFromClauseError","QueryRef","InvalidSourceError","UnionAll","UnionFrom","refProxy","createRefProxy","JoinConditionMustBeEqualityError","isRefProxy","toExpression","isExpressionLike","InvalidWhereExpressionError","createRefProxyWithSelected","QueryMustHaveFromClauseError","AggregateExpr","FuncExpr","PropRef","ValueExpr","ToArrayWrapper","ConcatToArrayWrapper","CaseWhenWrapper","MaterializeWrapper","ConditionalSelect","INCLUDES_SCALAR_FIELD","IncludesSubquery"],"mappings":"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