@kuindji/sql-type-parser
Version:
Type-level SQL parser for TypeScript
130 lines • 12 kB
TypeScript
/**
* DELETE Query Validator
*
* This module provides comprehensive validation for DELETE queries.
* It validates:
* - Table existence in schema
* - WHERE clause column references
* - USING clause table references
* - RETURNING clause column validation
*/
import type { SQLDeleteQuery, DeleteClause, UsingClause, DeleteReturningClause } from "./ast.js";
import type { TableRef, TableSource, UnboundColumnRef, ValidatableColumnRef, TableColumnRef, ParsedCondition } from "../common/ast.js";
import type { MatchError, ParseError, HasTemplateHoles } from "../common/utils.js";
import type { DatabaseSchema, GetDefaultSchema } from "../common/schema.js";
import type { ParseDeleteSQL } from "./parser.js";
export type { MatchError } from "../common/utils.js";
export type { DatabaseSchema } from "../common/schema.js";
/**
* Options for controlling DELETE query validation depth
*/
export type ValidateDeleteOptions = {
/**
* Whether to validate WHERE clause column references
* @default true
*/
validateWhere?: boolean;
/**
* Whether to validate RETURNING clause columns
* @default true
*/
validateReturning?: boolean;
};
/**
* Default validation options - full validation enabled
*/
type DefaultValidateOptions = {
validateWhere: true;
validateReturning: true;
};
/**
* Validate a DELETE query against a schema
*
* Returns true if valid, or an error message if invalid.
* For dynamic queries (non-literal strings), returns true (can't validate at compile time).
*/
export type ValidateDeleteSQL<SQL extends string, Schema extends DatabaseSchema, Options extends ValidateDeleteOptions = DefaultValidateOptions> = HasTemplateHoles<SQL> extends true ? true : ParseDeleteSQL<SQL> extends infer Parsed ? Parsed extends ParseError<infer E> ? E : Parsed extends SQLDeleteQuery<infer Query> ? ValidateDeleteClause<Query, Schema, Options> : "Failed to parse query" : never;
/**
* Validate a DELETE clause
*/
type ValidateDeleteClause<Delete extends DeleteClause, Schema extends DatabaseSchema, Options extends ValidateDeleteOptions = DefaultValidateOptions> = Delete extends DeleteClause<infer Table, infer Using, infer Where, infer Returning> ? ValidateTable<Table, Schema> extends infer TableResult ? TableResult extends true ? ValidateUsingClause<Using, Schema> extends infer UsingResult ? UsingResult extends true ? BuildValidationContext<Table, Using, Schema> extends infer Context ? Context extends MatchError<string> ? Context : ValidateWhereClause<Where, Context, Schema, Options> extends infer WhereResult ? WhereResult extends true ? ValidateReturningClause<Returning, Table, Schema, Options> : WhereResult : "WHERE validation failed" : "Context building failed" : UsingResult : "USING validation failed" : TableResult : "Table validation failed" : "Invalid DELETE clause";
/**
* Validate that the target table exists in the schema
*/
type ValidateTable<Table extends TableRef, Schema extends DatabaseSchema> = Table extends TableRef<infer TableName, infer _Alias, infer TableSchema> ? ResolveTableInSchema<TableName, TableSchema, Schema> : `Invalid table reference`;
/**
* Resolve a table in the database schema
*/
type ResolveTableInSchema<TableName extends string, TableSchema extends string | undefined, Schema extends DatabaseSchema> = TableSchema extends undefined ? GetDefaultSchema<Schema> extends infer DefaultSchema extends string ? DefaultSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][DefaultSchema] ? true : `Table '${TableName}' not found in default schema '${DefaultSchema}'` : `Default schema not found` : `Cannot determine default schema` : TableSchema extends string ? TableSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][TableSchema] ? true : `Table '${TableName}' not found in schema '${TableSchema}'` : `Schema '${TableSchema}' not found` : `Invalid schema type`;
/**
* Validate USING clause tables exist
*/
type ValidateUsingClause<Using, Schema extends DatabaseSchema> = Using extends undefined ? true : Using extends UsingClause<infer Tables> ? ValidateTableList<Tables, Schema> : true;
/**
* Validate a list of tables
*/
type ValidateTableList<Tables extends TableSource[], Schema extends DatabaseSchema> = Tables extends [infer First, ...infer Rest] ? First extends TableRef<infer TableName, infer _Alias, infer TableSchema> ? ResolveTableInSchema<TableName, TableSchema, Schema> extends infer Result ? Result extends true ? Rest extends TableSource[] ? ValidateTableList<Rest, Schema> : true : Result : "Table validation failed" : true : true;
/**
* Build validation context from main table and USING tables
*/
type BuildValidationContext<Table extends TableRef, Using, Schema extends DatabaseSchema> = ResolveTableContext<Table, Schema> extends infer MainContext ? MainContext extends MatchError<string> ? MainContext : Using extends UsingClause<infer Tables> ? MergeUsingContexts<MainContext, Tables, Schema> : MainContext : never;
/**
* Resolve table to context entry
*/
type ResolveTableContext<Table extends TableRef, Schema extends DatabaseSchema> = Table extends TableRef<infer TableName, infer Alias, infer TableSchema> ? TableSchema extends undefined ? GetDefaultSchema<Schema> extends infer DefaultSchema extends string ? DefaultSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][DefaultSchema] ? {
[K in Alias]: Schema["schemas"][DefaultSchema][TableName];
} : MatchError<`Table '${TableName}' not found`> : MatchError<`Default schema not found`> : MatchError<`Cannot determine default schema`> : TableSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][TableSchema] ? {
[K in Alias]: Schema["schemas"][TableSchema][TableName];
} : MatchError<`Table '${TableName}' not found in schema '${TableSchema}'`> : MatchError<`Schema '${TableSchema}' not found`> : MatchError<`Invalid table reference`>;
/**
* Merge USING tables into context
*/
type MergeUsingContexts<Context, Tables extends TableSource[], Schema extends DatabaseSchema> = Tables extends [infer First, ...infer Rest] ? First extends TableRef ? ResolveTableContext<First, Schema> extends infer TableContext ? TableContext extends MatchError<string> ? TableContext : Rest extends TableSource[] ? MergeUsingContexts<Context & TableContext, Rest, Schema> : Context & TableContext : Context : Context : Context;
/**
* Validate WHERE clause column references
*/
type ValidateWhereClause<Where, Context, Schema extends DatabaseSchema, Options extends ValidateDeleteOptions> = Options["validateWhere"] extends false ? true : Where extends undefined ? true : Where extends ParsedCondition<infer ColumnRefs> ? ValidateColumnRefList<ColumnRefs, Context, Schema> : true;
/**
* Validate a list of column references
*/
type ValidateColumnRefList<Refs extends ValidatableColumnRef[], Context, Schema extends DatabaseSchema> = Refs extends [infer First, ...infer Rest] ? ValidateSingleRef<First, Context, Schema> extends infer Result ? Result extends true ? Rest extends ValidatableColumnRef[] ? ValidateColumnRefList<Rest, Context, Schema> : true : Result : "Validation failed" : true;
/**
* Validate a single column reference
*/
type ValidateSingleRef<Ref, Context, Schema extends DatabaseSchema> = Ref extends TableColumnRef<infer Table, infer Column, infer ColSchema> ? ValidateTableColumn<Table, Column, ColSchema, Context, Schema> : Ref extends UnboundColumnRef<infer Column> ? ValidateUnboundColumn<Column, Context> : true;
/**
* Validate a table-qualified column
*/
type ValidateTableColumn<TableOrAlias extends string, Column extends string, ColSchema extends string | undefined, Context, Schema extends DatabaseSchema> = ColSchema extends undefined ? TableOrAlias extends keyof Context ? Context[TableOrAlias] extends infer Table ? Column extends keyof Table ? true : `Column '${Column}' not found in '${TableOrAlias}'` : never : `Table or alias '${TableOrAlias}' not found` : ColSchema extends string ? ColSchema extends keyof Schema["schemas"] ? TableOrAlias extends keyof Schema["schemas"][ColSchema] ? Column extends keyof Schema["schemas"][ColSchema][TableOrAlias] ? true : `Column '${Column}' not found in '${ColSchema}.${TableOrAlias}'` : `Table '${TableOrAlias}' not found in schema '${ColSchema}'` : `Schema '${ColSchema}' not found` : `Invalid schema type`;
/**
* Validate an unbound column exists in some table
*/
type ValidateUnboundColumn<Column extends string, Context> = ColumnExistsInContext<Column, Context>;
/**
* Check if column exists in any table in context
* Uses mapped type to avoid distributive conditional infinite recursion
*/
type ColumnExistsInContext<Column extends string, Context, _Keys = keyof Context> = true extends {
[K in keyof Context]: Column extends keyof Context[K] ? true : never;
}[keyof Context] ? true : `Column '${Column}' not found in any table`;
/**
* Validate RETURNING clause
*/
type ValidateReturningClause<Returning, Table extends TableRef, Schema extends DatabaseSchema, Options extends ValidateDeleteOptions> = Options["validateReturning"] extends false ? true : Returning extends undefined ? true : Returning extends DeleteReturningClause<infer Cols> ? Cols extends "*" ? true : Cols extends UnboundColumnRef[] ? ValidateReturningColumns<Cols, Table, Schema> : true : true;
/**
* Validate RETURNING column list
*/
type ValidateReturningColumns<Cols extends UnboundColumnRef[], Table extends TableRef, Schema extends DatabaseSchema> = Cols extends [infer First, ...infer Rest] ? First extends UnboundColumnRef<infer ColName> ? ValidateColumnExists<ColName, Table, Schema> extends infer Result ? Result extends true ? Rest extends UnboundColumnRef[] ? ValidateReturningColumns<Rest, Table, Schema> : true : Result : "RETURNING column validation failed" : true : true;
/**
* Validate a column exists in the table
*/
type ValidateColumnExists<ColumnName extends string, Table extends TableRef, Schema extends DatabaseSchema> = Table extends TableRef<infer TableName, infer _Alias, infer TableSchema> ? TableSchema extends undefined ? GetDefaultSchema<Schema> extends infer DefaultSchema extends string ? DefaultSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][DefaultSchema] ? ColumnName extends keyof Schema["schemas"][DefaultSchema][TableName] ? true : `Column '${ColumnName}' not found in table '${TableName}'` : `Table '${TableName}' not found` : `Default schema not found` : `Cannot determine default schema` : TableSchema extends string ? TableSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][TableSchema] ? ColumnName extends keyof Schema["schemas"][TableSchema][TableName] ? true : `Column '${ColumnName}' not found in table '${TableSchema}.${TableName}'` : `Table '${TableName}' not found in schema '${TableSchema}'` : `Schema '${TableSchema}' not found` : `Invalid schema type` : `Invalid table reference`;
/**
* Check if a DELETE query is valid
*/
export type IsValidDelete<SQL extends string, Schema extends DatabaseSchema> = ValidateDeleteSQL<SQL, Schema> extends true ? true : false;
/**
* Get the table columns that would be affected by a DELETE
*/
export type GetDeleteTableColumns<SQL extends string, Schema extends DatabaseSchema> = ParseDeleteSQL<SQL> extends SQLDeleteQuery<infer Query> ? Query extends DeleteClause<infer Table, infer _Using, infer _Where, infer _Return> ? Table extends TableRef<infer TableName, infer _Alias, infer TableSchema> ? TableSchema extends undefined ? GetDefaultSchema<Schema> extends infer DefaultSchema extends string ? DefaultSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][DefaultSchema] ? Schema["schemas"][DefaultSchema][TableName] : never : never : never : TableSchema extends keyof Schema["schemas"] ? TableName extends keyof Schema["schemas"][TableSchema] ? Schema["schemas"][TableSchema][TableName] : never : never : never : never : never;
//# sourceMappingURL=validator.d.ts.map