@tanstack/optimistic
Version:
Core optimistic updates library
189 lines (188 loc) • 11.4 kB
TypeScript
import { ConditionOperand, ExplicitLiteral, FunctionCall, LiteralValue, Select } from './schema.js';
export type Input = Record<string, unknown>;
export type Schema = Record<string, Input>;
export type Context<TBaseSchema extends Schema = Schema, TSchema extends Schema = Schema> = {
baseSchema: TBaseSchema;
schema: TSchema;
default?: keyof TSchema;
result?: Record<string, unknown>;
};
export type Flatten<T> = {
[K in keyof T]: T[K];
} & {};
type UniqueSecondLevelKeys<T> = {
[K in keyof T]: Exclude<keyof T[K], {
[P in Exclude<keyof T, K>]: keyof T[P];
}[Exclude<keyof T, K>]>;
}[keyof T];
type InputNames<TSchema extends Schema> = RemoveIndexSignature<{
[I in keyof TSchema]: I;
}>[keyof RemoveIndexSignature<{
[I in keyof TSchema]: I;
}>];
type UniquePropertyNames<TSchema extends Schema> = UniqueSecondLevelKeys<RemoveIndexSignature<TSchema>>;
export type RemoveIndexSignature<T> = {
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
};
type QualifiedReferencesOfSchemaString<TSchema extends Schema> = RemoveIndexSignature<{
[I in keyof TSchema]: {
[P in keyof RemoveIndexSignature<TSchema[I]>]: `@${string & I}.${string & P}`;
}[keyof RemoveIndexSignature<TSchema[I]>];
}>;
type QualifiedReferenceString<TContext extends Context<Schema>> = QualifiedReferencesOfSchemaString<TContext[`schema`]>[keyof QualifiedReferencesOfSchemaString<TContext[`schema`]>];
type QualifiedReferencesOfSchemaObject<TSchema extends Schema> = RemoveIndexSignature<{
[I in keyof TSchema]: {
[P in keyof RemoveIndexSignature<TSchema[I]>]: {
col: `${string & I}.${string & P}`;
};
}[keyof RemoveIndexSignature<TSchema[I]>];
}>;
type QualifiedReferenceObject<TContext extends Context<Schema>> = QualifiedReferencesOfSchemaObject<TContext[`schema`]>[keyof QualifiedReferencesOfSchemaObject<TContext[`schema`]>];
type QualifiedReference<TContext extends Context<Schema>> = QualifiedReferenceString<TContext> | QualifiedReferenceObject<TContext>;
type DefaultReferencesOfSchemaString<TSchema extends Schema, TDefault extends keyof TSchema> = RemoveIndexSignature<{
[P in keyof TSchema[TDefault]]: `@${string & P}`;
}>;
type DefaultReferenceString<TContext extends Context<Schema>> = TContext[`default`] extends undefined ? never : DefaultReferencesOfSchemaString<TContext[`schema`], Exclude<TContext[`default`], undefined>>[keyof DefaultReferencesOfSchemaString<TContext[`schema`], Exclude<TContext[`default`], undefined>>];
type DefaultReferencesOfSchemaObject<TSchema extends Schema, TDefault extends keyof TSchema> = RemoveIndexSignature<{
[P in keyof TSchema[TDefault]]: {
col: `${string & P}`;
};
}>;
type DefaultReferenceObject<TContext extends Context<Schema>> = TContext[`default`] extends undefined ? never : DefaultReferencesOfSchemaObject<TContext[`schema`], Exclude<TContext[`default`], undefined>>[keyof DefaultReferencesOfSchemaObject<TContext[`schema`], Exclude<TContext[`default`], undefined>>];
type DefaultReference<TContext extends Context<Schema>> = DefaultReferenceString<TContext> | DefaultReferenceObject<TContext>;
type UniqueReferencesOfSchemaString<TSchema extends Schema> = RemoveIndexSignature<{
[I in keyof TSchema]: {
[P in keyof TSchema[I]]: P extends UniquePropertyNames<TSchema> ? `@${string & P}` : never;
}[keyof TSchema[I]];
}>;
type UniqueReferenceString<TContext extends Context<Schema>> = UniqueReferencesOfSchemaString<TContext[`schema`]>[keyof UniqueReferencesOfSchemaString<TContext[`schema`]>];
type UniqueReferencesOfSchemaObject<TSchema extends Schema> = RemoveIndexSignature<{
[I in keyof TSchema]: {
[P in keyof TSchema[I]]: P extends UniquePropertyNames<TSchema> ? {
col: `${string & P}`;
} : never;
}[keyof TSchema[I]];
}>;
type UniqueReferenceObject<TContext extends Context<Schema>> = UniqueReferencesOfSchemaObject<TContext[`schema`]>[keyof UniqueReferencesOfSchemaObject<TContext[`schema`]>];
type UniqueReference<TContext extends Context<Schema>> = UniqueReferenceString<TContext> | UniqueReferenceObject<TContext>;
type InputWildcardString<TContext extends Context<Schema>> = Flatten<{
[I in InputNames<TContext[`schema`]>]: `@${I}.*`;
}[InputNames<TContext[`schema`]>]>;
type InputWildcardObject<TContext extends Context<Schema>> = Flatten<{
[I in InputNames<TContext[`schema`]>]: {
col: `${I}.*`;
};
}[InputNames<TContext[`schema`]>]>;
type InputWildcard<TContext extends Context<Schema>> = InputWildcardString<TContext> | InputWildcardObject<TContext>;
type AllWildcardString = `@*`;
type AllWildcardObject = {
col: `*`;
};
type AllWildcard = AllWildcardString | AllWildcardObject;
export type PropertyReferenceString<TContext extends Context<Schema>> = DefaultReferenceString<TContext> | QualifiedReferenceString<TContext> | UniqueReferenceString<TContext>;
export type WildcardReferenceString<TContext extends Context<Schema>> = InputWildcardString<TContext> | AllWildcardString;
export type PropertyReferenceObject<TContext extends Context<Schema>> = DefaultReferenceObject<TContext> | QualifiedReferenceObject<TContext> | UniqueReferenceObject<TContext>;
export type WildcardReferenceObject<TContext extends Context<Schema>> = InputWildcardObject<TContext> | AllWildcardObject;
export type PropertyReference<TContext extends Context<Schema>> = DefaultReference<TContext> | QualifiedReference<TContext> | UniqueReference<TContext>;
export type WildcardReference<TContext extends Context<Schema>> = InputWildcard<TContext> | AllWildcard;
type InputWithProperty<TSchema extends Schema, TProperty extends string> = {
[I in keyof RemoveIndexSignature<TSchema>]: TProperty extends keyof TSchema[I] ? I : never;
}[keyof RemoveIndexSignature<TSchema>];
export type TypeFromPropertyReference<TContext extends Context<Schema>, TReference extends PropertyReference<TContext>> = TReference extends `@${infer InputName}.${infer PropName}` | {
col: `${infer InputName}.${infer PropName}`;
} ? InputName extends keyof TContext[`schema`] ? PropName extends keyof TContext[`schema`][InputName] ? TContext[`schema`][InputName][PropName] : never : never : TReference extends `@${infer PropName}` | {
col: `${infer PropName}`;
} ? PropName extends keyof TContext[`schema`][Exclude<TContext[`default`], undefined>] ? TContext[`schema`][Exclude<TContext[`default`], undefined>][PropName] : TContext[`schema`][InputWithProperty<TContext[`schema`], PropName>][PropName] : never;
/**
* Return the key that would be used in the result of the query for a given property
* reference.
* - `@id` -> `id`
* - `@employees.id` -> `id`
* - `{ col: 'id' }` -> `id`
* - `{ col: 'employees.id' }` -> `id`
*/
export type ResultKeyFromPropertyReference<TContext extends Context<Schema>, TReference extends PropertyReference<TContext>> = TReference extends `@${infer _InputName}.${infer PropName}` ? PropName : TReference extends {
col: `${infer _InputName}.${infer PropName}`;
} ? PropName : TReference extends `@${infer PropName}` ? PropName : TReference extends {
col: `${infer PropName}`;
} ? PropName : never;
export type InputReference<TContext extends Context<Schema>> = {
[I in InputNames<TContext[`schema`]>]: I;
}[InputNames<TContext[`schema`]>];
export type RenameInput<TSchema extends Schema, TInput extends keyof TSchema, TNewName extends string> = Flatten<{
[K in Exclude<keyof TSchema, TInput>]: TSchema[K];
} & {
[P in TNewName]: TSchema[TInput];
}>;
export type MaybeRenameInput<TSchema extends Schema, TInput extends keyof TSchema, TNewName extends string | undefined> = TNewName extends undefined ? TSchema : RenameInput<TSchema, TInput, Exclude<TNewName, undefined>>;
/**
* Helper type to combine result types from each select item in a tuple
*/
export type InferResultTypeFromSelectTuple<TContext extends Context<Schema>, TSelects extends ReadonlyArray<Select<TContext>>> = UnionToIntersection<{
[K in keyof TSelects]: TSelects[K] extends Select<TContext> ? InferResultType<TContext, TSelects[K]> : never;
}[number]>;
/**
* Convert a union type to an intersection type
*/
type UnionToIntersection<TUnion> = (TUnion extends any ? (x: TUnion) => void : never) extends (x: infer I) => void ? I : never;
/**
* Infers the result type from a single select item
*/
type InferResultType<TContext extends Context<Schema>, TSelect extends Select<TContext>> = TSelect extends PropertyReferenceString<TContext> ? {
[K in ResultKeyFromPropertyReference<TContext, TSelect>]: TypeFromPropertyReference<TContext, TSelect>;
} : TSelect extends WildcardReferenceString<TContext> ? TSelect extends `@*` ? InferAllColumnsType<TContext> : TSelect extends `@${infer TableName}.*` ? TableName extends keyof TContext[`schema`] ? InferTableColumnsType<TContext, TableName> : {} : {} : TSelect extends {
[alias: string]: PropertyReference<TContext> | FunctionCall<TContext>;
} ? {
[K in keyof TSelect]: TSelect[K] extends PropertyReference<TContext> ? TypeFromPropertyReference<TContext, TSelect[K]> : TSelect[K] extends FunctionCall<TContext> ? InferFunctionCallResultType<TContext, TSelect[K]> : never;
} : {};
/**
* Infers the result type for all columns from all tables
*/
type InferAllColumnsType<TContext extends Context<Schema>> = {
[K in keyof TContext[`schema`]]: {
[P in keyof TContext[`schema`][K]]: TContext[`schema`][K][P];
};
}[keyof TContext[`schema`]];
/**
* Infers the result type for all columns from a specific table
*/
type InferTableColumnsType<TContext extends Context<Schema>, TTable extends keyof TContext[`schema`]> = {
[P in keyof TContext[`schema`][TTable]]: TContext[`schema`][TTable][P];
};
/**
* Infers the result type for a function call
*/
type InferFunctionCallResultType<TContext extends Context<Schema>, TFunctionCall extends FunctionCall<TContext>> = TFunctionCall extends {
SUM: any;
} ? number : TFunctionCall extends {
COUNT: any;
} ? number : TFunctionCall extends {
AVG: any;
} ? number : TFunctionCall extends {
MIN: any;
} ? InferOperandType<TContext, TFunctionCall[`MIN`]> : TFunctionCall extends {
MAX: any;
} ? InferOperandType<TContext, TFunctionCall[`MAX`]> : TFunctionCall extends {
DATE: any;
} ? string : TFunctionCall extends {
JSON_EXTRACT: any;
} ? unknown : TFunctionCall extends {
JSON_EXTRACT_PATH: any;
} ? unknown : TFunctionCall extends {
UPPER: any;
} ? string : TFunctionCall extends {
LOWER: any;
} ? string : TFunctionCall extends {
COALESCE: any;
} ? InferOperandType<TContext, TFunctionCall[`COALESCE`]> : TFunctionCall extends {
CONCAT: any;
} ? string : TFunctionCall extends {
LENGTH: any;
} ? number : TFunctionCall extends {
ORDER_INDEX: any;
} ? number : unknown;
/**
* Infers the type of an operand
*/
type InferOperandType<TContext extends Context<Schema>, TOperand extends ConditionOperand<TContext>> = TOperand extends PropertyReference<TContext> ? TypeFromPropertyReference<TContext, TOperand> : TOperand extends LiteralValue ? TOperand : TOperand extends ExplicitLiteral ? TOperand[`value`] : TOperand extends FunctionCall<TContext> ? InferFunctionCallResultType<TContext, TOperand> : TOperand extends Array<ConditionOperand<TContext>> ? InferOperandType<TContext, TOperand[number]> : unknown;
export {};