@tanstack/db
Version:
A reactive client store for building super fast apps on sync
189 lines (188 loc) • 15.7 kB
TypeScript
import { Aggregate, BasicExpression } from '../ir.js';
import { RefProxy } from './ref-proxy.js';
import { SingleResult } from '../../types.js';
import { Context, GetRawResult, RefLeaf, StringifiableScalar } from './types.js';
import { QueryBuilder } from './index.js';
type StringRef = RefLeaf<string> | RefLeaf<string | null> | RefLeaf<string | undefined>;
type StringRefProxy = RefProxy<string> | RefProxy<string | null> | RefProxy<string | undefined>;
type StringBasicExpression = BasicExpression<string> | BasicExpression<string | null> | BasicExpression<string | undefined>;
type StringLike = StringRef | StringRefProxy | StringBasicExpression | string | null | undefined;
type ComparisonOperand<T> = RefProxy<T> | RefLeaf<T> | T | BasicExpression<T> | undefined | null;
type ComparisonOperandPrimitive<T extends string | number | boolean> = T | BasicExpression<T> | undefined | null;
type ExpressionLike = Aggregate | BasicExpression | RefProxy<any> | RefLeaf<any> | string | number | boolean | bigint | Date | null | undefined | Array<unknown>;
type CaseWhenValue = ExpressionLike | QueryBuilder<any> | ToArrayWrapper<any> | ConcatToArrayWrapper<any> | Record<string, any>;
type ExtractCaseWhenValue<T> = T extends CaseWhenWrapper<infer TResult> ? TResult : T;
type CaseWhenResult<TValues extends Array<CaseWhenValue>, THasDefault extends boolean> = TValues[number] extends ExpressionLike ? BasicExpression<ExtractType<TValues[number]> | (THasDefault extends true ? never : null)> : CaseWhenWrapper<ExtractCaseWhenValue<TValues[number]> | (THasDefault extends true ? never : undefined)>;
type ExtractType<T> = T extends RefProxy<infer U> ? U : T extends RefLeaf<infer U> ? U : T extends BasicExpression<infer U> ? U : T;
type AggregateReturnType<T> = ExtractType<T> extends infer U ? U extends number | undefined | null | Date | bigint | string ? Aggregate<U> : Aggregate<number | undefined | null | Date | bigint | string> : Aggregate<number | undefined | null | Date | bigint | string>;
type StringFunctionReturnType<T> = ExtractType<T> extends infer U ? U extends string | undefined | null ? BasicExpression<U> : BasicExpression<string | undefined | null> : BasicExpression<string | undefined | null>;
type NumericFunctionReturnType<T> = ExtractType<T> extends infer U ? U extends string | Array<any> | undefined | null | number ? BasicExpression<MapToNumber<U>> : BasicExpression<number | undefined | null> : BasicExpression<number | undefined | null>;
type MapToNumber<T> = T extends string | Array<any> ? number : T extends undefined ? undefined : T extends null ? null : T;
type BinaryNumericReturnType<T1, T2> = ExtractType<T1> extends infer U1 ? ExtractType<T2> extends infer U2 ? U1 extends number ? U2 extends number ? BasicExpression<number> : U2 extends number | undefined ? BasicExpression<number | undefined> : U2 extends number | null ? BasicExpression<number | null> : BasicExpression<number | undefined | null> : U1 extends number | undefined ? U2 extends number ? BasicExpression<number | undefined> : U2 extends number | undefined ? BasicExpression<number | undefined> : BasicExpression<number | undefined | null> : U1 extends number | null ? U2 extends number ? BasicExpression<number | null> : BasicExpression<number | undefined | null> : BasicExpression<number | undefined | null> : BasicExpression<number | undefined | null> : BasicExpression<number | undefined | null>;
export declare function eq<T>(left: ComparisonOperand<T>, right: ComparisonOperand<T>): BasicExpression<boolean>;
export declare function eq<T extends string | number | boolean>(left: ComparisonOperandPrimitive<T>, right: ComparisonOperandPrimitive<T>): BasicExpression<boolean>;
export declare function eq<T>(left: Aggregate<T>, right: any): BasicExpression<boolean>;
export declare function gt<T>(left: ComparisonOperand<T>, right: ComparisonOperand<T>): BasicExpression<boolean>;
export declare function gt<T extends string | number>(left: ComparisonOperandPrimitive<T>, right: ComparisonOperandPrimitive<T>): BasicExpression<boolean>;
export declare function gt<T>(left: Aggregate<T>, right: any): BasicExpression<boolean>;
export declare function gte<T>(left: ComparisonOperand<T>, right: ComparisonOperand<T>): BasicExpression<boolean>;
export declare function gte<T extends string | number>(left: ComparisonOperandPrimitive<T>, right: ComparisonOperandPrimitive<T>): BasicExpression<boolean>;
export declare function gte<T>(left: Aggregate<T>, right: any): BasicExpression<boolean>;
export declare function lt<T>(left: ComparisonOperand<T>, right: ComparisonOperand<T>): BasicExpression<boolean>;
export declare function lt<T extends string | number>(left: ComparisonOperandPrimitive<T>, right: ComparisonOperandPrimitive<T>): BasicExpression<boolean>;
export declare function lt<T>(left: Aggregate<T>, right: any): BasicExpression<boolean>;
export declare function lte<T>(left: ComparisonOperand<T>, right: ComparisonOperand<T>): BasicExpression<boolean>;
export declare function lte<T extends string | number>(left: ComparisonOperandPrimitive<T>, right: ComparisonOperandPrimitive<T>): BasicExpression<boolean>;
export declare function lte<T>(left: Aggregate<T>, right: any): BasicExpression<boolean>;
export declare function and(left: ExpressionLike, right: ExpressionLike): BasicExpression<boolean>;
export declare function and(left: ExpressionLike, right: ExpressionLike, ...rest: Array<ExpressionLike>): BasicExpression<boolean>;
export declare function or(left: ExpressionLike, right: ExpressionLike): BasicExpression<boolean>;
export declare function or(left: ExpressionLike, right: ExpressionLike, ...rest: Array<ExpressionLike>): BasicExpression<boolean>;
export declare function not(value: ExpressionLike): BasicExpression<boolean>;
export declare function isUndefined(value: ExpressionLike): BasicExpression<boolean>;
export declare function isNull(value: ExpressionLike): BasicExpression<boolean>;
export declare function inArray(value: ExpressionLike, array: ExpressionLike): BasicExpression<boolean>;
export declare function like(left: StringLike, right: StringLike): BasicExpression<boolean>;
export declare function ilike(left: StringLike, right: StringLike): BasicExpression<boolean>;
export declare function upper<T extends ExpressionLike>(arg: T): StringFunctionReturnType<T>;
export declare function lower<T extends ExpressionLike>(arg: T): StringFunctionReturnType<T>;
export declare function length<T extends ExpressionLike>(arg: T): NumericFunctionReturnType<T>;
export declare function concat<T extends StringifiableScalar>(arg: ToArrayWrapper<T>): ConcatToArrayWrapper<T>;
export declare function concat(...args: Array<ExpressionLike>): BasicExpression<string>;
type CoalesceArgTypes<T extends Array<ExpressionLike>> = {
[K in keyof T]: NonNullable<ExtractType<T[K]>>;
}[number];
type HasGuaranteedNonNull<T extends Array<ExpressionLike>> = {
[K in keyof T]: null extends ExtractType<T[K]> ? false : undefined extends ExtractType<T[K]> ? false : true;
}[number] extends false ? false : true;
type CoalesceReturnType<T extends Array<ExpressionLike>> = HasGuaranteedNonNull<T> extends true ? BasicExpression<CoalesceArgTypes<T>> : BasicExpression<CoalesceArgTypes<T> | null>;
export declare function coalesce<T extends [ExpressionLike, ...Array<ExpressionLike>]>(...args: T): CoalesceReturnType<T>;
/**
* Returns the value for the first matching condition, similar to SQL
* `CASE WHEN`.
*
* Arguments are evaluated as condition/value pairs followed by an optional
* default value. Scalar branch values return a query expression and can be used
* in expression contexts like `select`, `where`, `orderBy`, `groupBy`,
* `having`, and equality join operands. If no scalar branch matches and no
* default is provided, the result is `null`.
*
* When a branch value is a projection object, `caseWhen` becomes a select-only
* projection value. Projection branches can include nested fields, ref spreads,
* and includes. If no projection branch matches and no default is provided, the
* result is `undefined`.
*
* @example
* ```ts
* caseWhen(gt(user.age, 18), `adult`, `minor`)
* ```
*
* @example
* ```ts
* caseWhen(
* gt(user.age, 65),
* `senior`,
* gt(user.age, 18),
* `adult`,
* `minor`,
* )
* ```
*
* @example
* ```ts
* caseWhen(gt(user.age, 18), {
* ...user,
* posts: q
* .from({ post: postsCollection })
* .where(({ post }) => eq(post.userId, user.id)),
* })
* ```
*/
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue>(condition1: C1, value1: V1): CaseWhenResult<[V1], false>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, D extends CaseWhenValue>(condition1: C1, value1: V1, defaultValue: D): CaseWhenResult<[V1, D], true>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2): CaseWhenResult<[V1, V2], false>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, D extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, defaultValue: D): CaseWhenResult<[V1, V2, D], true>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3): CaseWhenResult<[V1, V2, V3], false>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue, D extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3, defaultValue: D): CaseWhenResult<[V1, V2, V3, D], true>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue, C4 extends ExpressionLike, V4 extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3, condition4: C4, value4: V4): CaseWhenResult<[V1, V2, V3, V4], false>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue, C4 extends ExpressionLike, V4 extends CaseWhenValue, D extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3, condition4: C4, value4: V4, defaultValue: D): CaseWhenResult<[V1, V2, V3, V4, D], true>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue, C4 extends ExpressionLike, V4 extends CaseWhenValue, C5 extends ExpressionLike, V5 extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3, condition4: C4, value4: V4, condition5: C5, value5: V5): CaseWhenResult<[V1, V2, V3, V4, V5], false>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue, C4 extends ExpressionLike, V4 extends CaseWhenValue, C5 extends ExpressionLike, V5 extends CaseWhenValue, D extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3, condition4: C4, value4: V4, condition5: C5, value5: V5, defaultValue: D): CaseWhenResult<[V1, V2, V3, V4, V5, D], true>;
export declare function caseWhen<C1 extends ExpressionLike, V1 extends CaseWhenValue, C2 extends ExpressionLike, V2 extends CaseWhenValue, C3 extends ExpressionLike, V3 extends CaseWhenValue, C4 extends ExpressionLike, V4 extends CaseWhenValue, C5 extends ExpressionLike, V5 extends CaseWhenValue>(condition1: C1, value1: V1, condition2: C2, value2: V2, condition3: C3, value3: V3, condition4: C4, value4: V4, condition5: C5, value5: V5, condition6: ExpressionLike, value6: CaseWhenValue, ...rest: Array<CaseWhenValue>): any;
export declare function add<T1 extends ExpressionLike, T2 extends ExpressionLike>(left: T1, right: T2): BinaryNumericReturnType<T1, T2>;
export declare function count(arg: ExpressionLike): Aggregate<number>;
export declare function avg<T extends ExpressionLike>(arg: T): AggregateReturnType<T>;
export declare function sum<T extends ExpressionLike>(arg: T): AggregateReturnType<T>;
export declare function min<T extends ExpressionLike>(arg: T): AggregateReturnType<T>;
export declare function max<T extends ExpressionLike>(arg: T): AggregateReturnType<T>;
/**
* List of comparison function names that can be used with indexes
*/
export declare const comparisonFunctions: readonly ["eq", "gt", "gte", "lt", "lte", "in", "like", "ilike"];
/**
* All supported operator names in TanStack DB expressions
*/
export declare const operators: readonly ["eq", "gt", "gte", "lt", "lte", "in", "like", "ilike", "and", "or", "not", "isNull", "isUndefined", "upper", "lower", "length", "concat", "add", "coalesce", "caseWhen", "count", "avg", "sum", "min", "max"];
export type OperatorName = (typeof operators)[number];
export declare class ToArrayWrapper<_T = unknown> {
readonly query: QueryBuilder<any>;
readonly __brand: "ToArrayWrapper";
readonly _type: `toArray`;
readonly _result: _T;
constructor(query: QueryBuilder<any>);
}
export declare class ConcatToArrayWrapper<_T = unknown> {
readonly query: QueryBuilder<any>;
readonly __brand: "ConcatToArrayWrapper";
readonly _type: `concatToArray`;
readonly _result: _T;
constructor(query: QueryBuilder<any>);
}
export declare class CaseWhenWrapper<_T = any> {
readonly args: Array<CaseWhenValue>;
readonly __brand: "CaseWhenWrapper";
readonly _type: `caseWhen`;
readonly _result?: _T;
constructor(args: Array<CaseWhenValue>);
}
export declare class MaterializeWrapper<_T = unknown, _IsSingle extends boolean = boolean> {
readonly query: QueryBuilder<any>;
readonly __brand: "MaterializeWrapper";
readonly _type: `materialize`;
readonly _result: _T;
readonly _isSingle: _IsSingle;
constructor(query: QueryBuilder<any>);
}
export declare function toArray<TContext extends Context>(query: QueryBuilder<TContext>): ToArrayWrapper<GetRawResult<TContext>>;
/**
* Materialize an includes subquery into a plain value on the parent row.
*
* - For multi-row subqueries, the parent receives an `Array<T>` snapshot
* (equivalent to `toArray()`).
* - For `findOne()` subqueries, the parent receives a single `T | undefined`
* value — `undefined` when no child matches.
*
* The snapshot updates reactively: parent rows re-emit when the underlying
* children change.
*
* @example
* ```ts
* // Multi-row: produces Array<Issue> on each project
* select(({ p }) => ({
* ...p,
* issues: materialize(
* q.from({ i: issues }).where(({ i }) => eq(i.projectId, p.id)),
* ),
* }))
*
* // Singleton: produces Author | undefined on each post
* select(({ p }) => ({
* ...p,
* author: materialize(
* q.from({ a: authors }).where(({ a }) => eq(a.id, p.authorId)).findOne(),
* ),
* }))
* ```
*/
export declare function materialize<TContext extends Context>(query: QueryBuilder<TContext>): MaterializeWrapper<GetRawResult<TContext>, TContext extends SingleResult ? true : false>;
export {};