UNPKG

@a2lix/schemql

Version:

A lightweight TypeScript library that enhances your SQL workflow by combining raw SQL with targeted type safety and schema validation

81 lines (78 loc) 6.43 kB
import { StandardSchemaV1 } from '@standard-schema/spec'; interface SchemQlAdapter<T = unknown> { queryFirst: QueryFn<T | undefined>; queryFirstOrThrow: QueryFn<T>; queryAll: QueryFn<T[]>; queryIterate: IterativeQueryFn<T>; } type QueryFn<TQueryResult, TParams extends Record<string, any> | undefined = Record<string, any> | undefined> = (sql: string) => (params?: TParams) => TQueryResult | Promise<TQueryResult>; type IterativeQueryFn<TQueryResult, TParams extends Record<string, any> | undefined = Record<string, any> | undefined> = (sql: string) => (params?: TParams) => GeneratorFn<TQueryResult> | AsyncGeneratorFn<TQueryResult>; type ArrayElement<T> = T extends (infer U)[] ? U : T; type GeneratorFn<T> = () => Generator<T, void, unknown>; type AsyncGeneratorFn<T> = () => AsyncGenerator<T, void, unknown>; type TableNames<DB> = Extract<keyof DB, string>; type ColumnNames<DB, T extends TableNames<DB>> = Extract<keyof DB[T], string>; type TableColumnSelection<DB> = { [T in TableNames<DB>]?: ColumnNames<DB, T>[]; }; type ValidTableColumnCombinations<DB> = { [T in TableNames<DB>]: `${T}.${ColumnNames<DB, T>}` | `${T}.${ColumnNames<DB, T>}-`; }[TableNames<DB>]; type JsonPathForObjectArrow<T, P extends string = ''> = T extends Record<string, any> ? { [K in keyof T & string]: `${P}->${K}` | `${P}->${K}-` | `${P}->>${K}` | `${P}->>${K}-` | (NonNullable<T[K]> extends Record<string, any> ? `${P}->${K}${JsonPathForObjectArrow<NonNullable<T[K]>, ''>}` : never); }[keyof T & string] : ''; type JsonPathForObjectDot<T, P extends string = ''> = T extends Record<string, any> ? { [K in keyof T & string]: `${P}.${K}` | (NonNullable<T[K]> extends Record<string, any> ? `${P}.${K}${JsonPathForObjectDot<NonNullable<T[K]>, ''>}` : never); }[keyof T & string] : ''; type JsonPathCombinations<DB, T extends TableNames<DB>> = { [K in ColumnNames<DB, T>]: DB[T][K] extends object ? JsonPathForObjectArrow<ArrayElement<DB[T][K]>, `${T}.${K} `> | JsonPathForObjectDot<ArrayElement<DB[T][K]>, `${T}.${K} $`> : never; }[ColumnNames<DB, T>]; type ValidJsonPathCombinations<DB> = { [T in TableNames<DB>]: JsonPathCombinations<DB, T>; }[TableNames<DB>]; type SqlTemplateValue<TResultSchema, TParams, DB> = TableColumnSelection<DB> | `@${TableNames<DB>}` | `@${TableNames<DB>}.*` | `@${ValidTableColumnCombinations<DB>}` | `@${ValidJsonPathCombinations<DB>}` | `$${keyof ArrayElement<Exclude<TResultSchema, undefined>> & string}` | `:${keyof TParams & string}` | ${string}`; type SqlTemplateValues<TResultSchema, TParams, DB> = SqlTemplateValue<TResultSchema, TParams, DB>[]; type SqlOrBuilderFn<TResultSchema extends StandardSchemaV1 | undefined, TParams extends Record<string, any>, DB> = string | ((s: SchemQlSqlHelper<TResultSchema, TParams, DB>) => string); type SchemQlSqlHelper<TResultSchema extends StandardSchemaV1 | undefined, TParams extends Record<string, any>, DB> = { sql: <T extends SqlTemplateValues<TResultSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TResultSchema> : unknown, TParams, DB>>(strings: TemplateStringsArray, ...values: T) => string; sqlCond: (condition: boolean, ifTrue: string | number, ifFalse?: string | number) => ${string}`; sqlRaw: (raw: string | number) => ${string}`; }; type SchemQlOptions = { adapter: SchemQlAdapter; /** @deprecated Use `stringifyObjectParams` instead */ shouldStringifyObjectParams?: boolean; stringifyObjectParams?: boolean; quoteSqlIdentifiers?: boolean; }; type IsIterativeExecution<TParams> = TParams extends any[] ? true : TParams extends AsyncGeneratorFn<any> ? true : TParams extends GeneratorFn<any> ? true : false; type ParamsType<T> = T extends AsyncGeneratorFn<infer P> ? P : T extends GeneratorFn<infer P> ? P : T extends Array<infer P> ? P : T; type SimpleQueryExecutorResult<TQueryResult, TResultSchema extends StandardSchemaV1 | undefined> = TResultSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TResultSchema> : TQueryResult; type QueryExecutor<DB> = <TQueryResult = unknown, TParams extends QueryExecutorParams = QueryExecutorParams, TParamsSchema extends StandardSchemaV1 | undefined = undefined, TResultSchema extends StandardSchemaV1 | undefined = undefined>(options: { params?: QueryExecutorOptionsParams<TParams, TParamsSchema>; paramsSchema?: TParamsSchema; resultSchema?: TResultSchema; }) => (sqlOrBuilderFn: SqlOrBuilderFn<TResultSchema, ParamsType<TParams>, DB>) => Promise<QueryExecutorResult<TQueryResult, TParams, TResultSchema>>; type QueryExecutorParams = Record<string, any> | Record<string, any>[] | GeneratorFn<Record<string, any>> | AsyncGeneratorFn<Record<string, any>>; type QueryExecutorOptionsParams<TParams, TParamsSchema extends StandardSchemaV1 | undefined> = TParams extends AsyncGeneratorFn<infer P> ? AsyncGeneratorFn<P> : TParams extends GeneratorFn<infer P> ? GeneratorFn<P> : TParams extends Array<infer P> ? P[] : TParamsSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TParamsSchema> : TParams; type QueryExecutorResult<TQueryResult, TParams, TResultSchema extends StandardSchemaV1 | undefined> = IsIterativeExecution<TParams> extends true ? AsyncGenerator<SimpleQueryExecutorResult<TQueryResult, TResultSchema>, void, unknown> : SimpleQueryExecutorResult<TQueryResult, TResultSchema>; type IterativeQueryExecutor<DB> = <TQueryResult = unknown, TParams extends Record<string, any> = Record<string, any>, TParamsSchema extends StandardSchemaV1 | undefined = undefined, TResultSchema extends StandardSchemaV1 | undefined = undefined>(options: { params?: TParamsSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TParamsSchema> : TParams; paramsSchema?: TParamsSchema; resultSchema?: TResultSchema; }) => (sqlOrBuilderFn: SqlOrBuilderFn<TResultSchema, TParams, DB>) => Promise<AsyncGenerator<SimpleQueryExecutorResult<TQueryResult, TResultSchema>, void, unknown>>; declare class SchemQl<DB> { private readonly options; first: QueryExecutor<DB>; firstOrThrow: QueryExecutor<DB>; all: QueryExecutor<DB>; iterate: IterativeQueryExecutor<DB>; constructor(options: SchemQlOptions); private createQueryExecutor; private createIterativeExecutor; private validateAndStringifyParams; private createSqlHelper; private processLiteralExpressions; private processLiteralExpression; } export { type SchemQlAdapter as S, SchemQl as a };