@tanstack/db
Version:
A reactive client store for building super fast apps on sync
82 lines (81 loc) • 5.77 kB
text/typescript
import { CollectionImpl } from '../../collection.js';
import { Aggregate, BasicExpression } from '../ir.js';
import { QueryBuilder } from './index.js';
export interface Context {
baseSchema: ContextSchema;
schema: ContextSchema;
fromSourceName: string;
hasJoins?: boolean;
joinTypes?: Record<string, `inner` | `left` | `right` | `full` | `outer` | `cross`>;
result?: any;
}
export type ContextSchema = Record<string, unknown>;
export type Source = {
[alias: string]: CollectionImpl<any, any> | QueryBuilder<Context>;
};
export type InferCollectionType<T> = T extends CollectionImpl<infer U> ? U : never;
export type SchemaFromSource<T extends Source> = Prettify<{
[K in keyof T]: T[K] extends CollectionImpl<infer U> ? U : T[K] extends QueryBuilder<infer TContext> ? GetResult<TContext> : never;
}>;
export type GetAliases<TContext extends Context> = keyof TContext[`schema`];
export type WhereCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
export type SelectObject<T extends Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>> = Record<string, BasicExpression | Aggregate | RefProxy | RefProxyFor<any>>> = T;
export type ResultTypeFromSelect<TSelectObject> = {
[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;
};
export type OrderByCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
export type GroupByCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
export type JoinOnCallback<TContext extends Context> = (refs: RefProxyForContext<TContext>) => any;
export type RefProxyForContext<TContext extends Context> = {
[K in keyof TContext[`schema`]]: RefProxyFor<TContext[`schema`][K]>;
};
type IsExactlyUndefined<T> = [T] extends [undefined] ? true : false;
type IsOptional<T> = undefined extends T ? true : false;
type NonUndefined<T> = T extends undefined ? never : T;
export type RefProxyFor<T> = OmitRefProxy<IsExactlyUndefined<T> extends true ? RefProxy<T> : IsOptional<T> extends true ? NonUndefined<T> extends Record<string, any> ? {
[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>;
} & RefProxy<T> : RefProxy<T> : T extends Record<string, any> ? {
[K in keyof T]: T[K] extends Record<string, any> ? RefProxyFor<T[K]> & RefProxy<T[K]> : RefProxy<T[K]>;
} & RefProxy<T> : RefProxy<T>>;
export type Ref<T> = RefProxyFor<T>;
type OmitRefProxy<T> = Omit<T, `__refProxy` | `__path` | `__type`>;
export interface RefProxy<T = any> {
/** @internal */
readonly __refProxy: true;
/** @internal */
readonly __path: Array<string>;
/** @internal */
readonly __type: T;
}
export type MergeContextWithJoinType<TContext extends Context, TNewSchema extends ContextSchema, TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`> = {
baseSchema: TContext[`baseSchema`];
schema: ApplyJoinOptionalityToMergedSchema<TContext[`schema`], TNewSchema, TJoinType, TContext[`fromSourceName`]>;
fromSourceName: TContext[`fromSourceName`];
hasJoins: true;
joinTypes: (TContext[`joinTypes`] extends Record<string, any> ? TContext[`joinTypes`] : {}) & {
[K in keyof TNewSchema & string]: TJoinType;
};
result: TContext[`result`];
};
export type ApplyJoinOptionalityToMergedSchema<TExistingSchema extends ContextSchema, TNewSchema extends ContextSchema, TJoinType extends `inner` | `left` | `right` | `full` | `outer` | `cross`, TFromSourceName extends string> = {
[K in keyof TExistingSchema]: K extends TFromSourceName ? TJoinType extends `right` | `full` ? TExistingSchema[K] | undefined : TExistingSchema[K] : TExistingSchema[K];
} & {
[K in keyof TNewSchema]: TJoinType extends `left` | `full` ? // New table becomes optional for left and full joins
TNewSchema[K] | undefined : TNewSchema[K];
};
export type GetResult<TContext extends Context> = Prettify<TContext[`result`] extends object ? TContext[`result`] : TContext[`hasJoins`] extends true ? TContext[`schema`] : TContext[`schema`][TContext[`fromSourceName`]]>;
export type ApplyJoinOptionalityToSchema<TSchema extends ContextSchema, TJoinTypes extends Record<string, string>, TFromSourceName extends string> = {
[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];
};
type IsTableMadeOptionalBySubsequentJoins<TTableAlias extends string | number | symbol, TJoinTypes extends Record<string, string>, TFromSourceName extends string> = TTableAlias extends TFromSourceName ? HasJoinType<TJoinTypes, `right` | `full`> : false;
export type HasJoinType<TJoinTypes extends Record<string, string>, TTargetTypes extends string> = true extends {
[K in keyof TJoinTypes]: TJoinTypes[K] extends TTargetTypes ? true : false;
}[keyof TJoinTypes] ? true : false;
export type MergeContext<TContext extends Context, TNewSchema extends ContextSchema> = MergeContextWithJoinType<TContext, TNewSchema, `left`>;
export type WithResult<TContext extends Context, TResult> = Prettify<Omit<TContext, `result`> & {
result: Prettify<TResult>;
}>;
export type Prettify<T> = {
[K in keyof T]: T[K];
} & {};
export {};