ts-flex-query
Version:
Flexible and type-safe data queries
37 lines (36 loc) • 3.86 kB
TypeScript
import { Expression } from '../../core/expression';
import { PipeOperator } from '../../core/pipe-operator';
import { ExpressionResultType } from '../../types/expression-result-type';
import { TsFlexQueryTypeMarker } from '../../types/ts-flex-query-type';
import { IfPrimitive } from '../../types/utils';
import type { Error } from '../../types/utils';
export type PrimitiveSchemaSpec = true;
type PrimitiveQuerySchemaType<TFieldType> = TFieldType;
declare enum SpecialObjectSchemaSpec {
/** Expand the object with all its primitive fields. */
expand = "expand",
/** Like expand, but when using OData, don't include the field in the $expand clause. */
select = "select"
}
type ExplicitObjectSchemaSpec<in out T = any> = {
[TKey in keyof NonNullable<T> & string]?: SpecificSchemaSpec<NonNullable<T>[TKey], NonNullable<T>>;
};
type ObjectSchemaSpec<T = any> = keyof typeof SpecialObjectSchemaSpec | ExplicitObjectSchemaSpec<T>;
type NonNullableObjectSchemaType<TIn, TSchema extends ObjectSchemaSpec<TIn>> = TSchema extends ExplicitObjectSchemaSpec<TIn> ? (TsFlexQueryTypeMarker<'record'> & {
[key in keyof TSchema]: key extends keyof NonNullable<TIn> ? SchemaType<NonNullable<TIn>[key], NonNullable<TSchema[key]>> : never;
}) : NonNullable<TIn>;
type ObjectSchemaType<TIn, TSchema extends ObjectSchemaSpec<TIn>> = undefined extends TIn ? NonNullableObjectSchemaType<TIn, TSchema> | undefined : NonNullableObjectSchemaType<TIn, TSchema>;
type ValidObjectSchemaSpec<TObj, TSchema> = keyof typeof SpecialObjectSchemaSpec | {
[TKey in keyof TSchema]: TKey extends keyof NonNullable<TObj> ? ValidSchemaSpec<NonNullable<TObj>[TKey], TSchema[TKey]> : never;
};
export type ArraySchemaSpec<TElement = any> = readonly [ObjectSchemaSpec<TElement>];
type ArraySchemaType<TElement, TSchema extends ArraySchemaSpec<TElement>> = (ObjectSchemaType<TElement, TSchema[number]>)[];
export type ExpressionSchemaSpec<TValue = any, TContainer = any> = TContainer extends null ? (valueExpr: Expression<TValue>) => Expression<unknown> : (valueExpr: Expression<TValue>, container: Expression<TContainer>) => Expression<unknown>;
type ExpressionSchemaType<TElement, TSchema extends ExpressionSchemaSpec<TElement>> = ExpressionResultType<ReturnType<TSchema>>;
export type SchemaSpec = PrimitiveSchemaSpec | ObjectSchemaSpec | ArraySchemaSpec | ExpressionSchemaSpec;
export type SpecificSchemaSpec<T, TContainer> = (NonNullable<T> extends (infer TElement)[] ? ArraySchemaSpec<TElement> : IfPrimitive<T, PrimitiveSchemaSpec, ObjectSchemaSpec<T>>) | ExpressionSchemaSpec<T, TContainer>;
export type ValidSchemaSpec<TValue, TSchema> = TSchema extends readonly [infer TObjectSchema] ? TValue extends (infer TElement)[] | undefined ? readonly [ValidObjectSchemaSpec<TElement, TObjectSchema>] : never : TSchema extends Partial<Record<string, any>> | keyof typeof SpecialObjectSchemaSpec ? ValidObjectSchemaSpec<TValue, TSchema> : TSchema extends true ? IfPrimitive<TValue, TSchema, never> : TSchema extends (...args: any[]) => any ? TSchema : never;
export type SchemaType<TValue, TSchema extends SchemaSpec> = TSchema extends PrimitiveSchemaSpec ? PrimitiveQuerySchemaType<TValue> : TSchema extends ObjectSchemaSpec ? ObjectSchemaType<TValue, TSchema> : TSchema extends ArraySchemaSpec ? TValue extends (infer TElement)[] | undefined ? ArraySchemaType<TElement, TSchema> : never : TSchema extends ExpressionSchemaSpec ? ExpressionSchemaType<TValue, TSchema> : never;
export declare function createOperatorForSchema(schema: SchemaSpec, container: Expression | null): PipeOperator;
export declare function querySchema<TIn, const TSchema extends SpecificSchemaSpec<TIn, null>>(schema: TSchema): TSchema extends ValidSchemaSpec<TIn, TSchema> ? PipeOperator<TIn, SchemaType<TIn, TSchema>> : Error<'Invalid schema. Use the SchemaFactory for a detailed error.'>;
export {};