kitcn
Version:
kitcn - React Query integration and CLI tools for Convex
1,040 lines (1,039 loc) • 235 kB
TypeScript
import { a as ReturnTypeOrValue, i as KnownKeysOnly, o as Simplify$1, t as Assume } from "./types-DF2cg_w0.js";
import * as convex_values0 from "convex/values";
import { GenericId, Validator, Value } from "convex/values";
import { DefineSchemaOptions, FilterExpression, GenericDatabaseReader, GenericDatabaseWriter, GenericIndexFields, GenericSchema, GenericTableIndexes, GenericTableSearchIndexes, GenericTableVectorIndexes, IndexRange, IndexRangeBuilder, SchedulableFunctionReference, Scheduler, SchemaDefinition, TableDefinition, VectorFilterBuilder, internalActionGeneric, internalMutationGeneric } from "convex/server";
//#region src/orm/builders/column-builder.d.ts
/**
* Core data types supported by column builders
* Maps to Convex types: string, number (float64), boolean, bigint (int64), vector
*/
type ColumnDataType = 'string' | 'number' | 'boolean' | 'bigint' | 'bytes' | 'any' | 'vector';
type ForeignKeyAction = 'cascade' | 'restrict' | 'no action' | 'set null' | 'set default';
interface ColumnReferenceConfig {
name?: string;
onDelete?: ForeignKeyAction;
onUpdate?: ForeignKeyAction;
}
/**
* Base configuration for all column builders
* Stores type-level metadata extracted by TypeScript
* Matches Drizzle's ColumnBuilderBaseConfig structure
*/
interface ColumnBuilderBaseConfig<TDataType extends ColumnDataType, TColumnType extends string> {
columnType: TColumnType;
data: unknown;
dataType: TDataType;
driverParam: unknown;
enumValues: string[] | undefined;
name: string;
}
/**
* Runtime configuration stored in builder instance
* Updated by chaining methods (.notNull(), .default(), etc.)
*/
interface ColumnBuilderRuntimeConfig<TData> {
columnType: string;
dataType: string;
default: TData | undefined;
defaultFn?: (() => unknown) | undefined;
foreignKeyConfigs: {
ref: () => ColumnBuilderBase;
config: ColumnReferenceConfig;
}[];
hasDefault: boolean;
isUnique: boolean;
name: string;
notNull: boolean;
onUpdateFn?: (() => unknown) | undefined;
primaryKey: boolean;
referenceTable?: string;
table?: unknown;
tableName?: string;
uniqueName?: string;
uniqueNulls?: 'distinct' | 'not distinct';
}
/**
* Phantom type configuration - never instantiated, just for TypeScript
* Tracks type-level state through method chaining
* Matches Drizzle's exact structure
*/
type ColumnBuilderTypeConfig<T extends ColumnBuilderBaseConfig<ColumnDataType, string>, TTypeConfig extends object> = Simplify$1<{
brand: 'ColumnBuilder';
name: T['name'];
dataType: T['dataType'];
columnType: T['columnType'];
data: T['data'];
driverParam: T['driverParam'];
notNull: T extends {
notNull: infer U;
} ? U : boolean;
hasDefault: T extends {
hasDefault: infer U;
} ? U : boolean;
isPrimaryKey: T extends {
isPrimaryKey: infer U;
} ? U : boolean;
isUnique: T extends {
isUnique: infer U;
} ? U : boolean;
enumValues: T['enumValues'];
} & TTypeConfig>;
/**
* entityKind symbol for runtime type checking
* Following Drizzle's pattern for type guards
*/
declare const entityKind: unique symbol;
interface DrizzleEntity {
[entityKind]: string;
}
/**
* ColumnBuilderBase interface - defines the phantom _ property
* This interface is crucial for proper type intersection with NotNull/HasDefault/etc.
*/
interface ColumnBuilderBase<T extends ColumnBuilderBaseConfig<ColumnDataType, string> = ColumnBuilderBaseConfig<ColumnDataType, string>, TTypeConfig extends object = object> {
_: ColumnBuilderTypeConfig<T, TTypeConfig>;
}
/**
* Use as the return type for self-referencing `.references()` callbacks.
*
* @example
* ```ts
* parentId: text().references((): AnyColumn => commentsTable.id, { onDelete: 'cascade' })
* ```
*/
type AnyColumn = ColumnBuilderBase;
/**
* Base ColumnBuilder abstract class
*
* All column builders inherit from this class.
* Implements chaining methods and stores runtime config.
*/
declare abstract class ColumnBuilder<T extends ColumnBuilderBaseConfig<ColumnDataType, string> = ColumnBuilderBaseConfig<ColumnDataType, string>, TRuntimeConfig extends object = object, TTypeConfig extends object = object> implements ColumnBuilderBase<T, TTypeConfig>, DrizzleEntity {
static readonly [entityKind]: string;
readonly [entityKind]: string;
/**
* Phantom property - never instantiated, just for types
* Accumulates type info through method chaining
*/
_: ColumnBuilderTypeConfig<T, TTypeConfig>;
/**
* Runtime configuration - actual mutable state
*/
protected config: ColumnBuilderRuntimeConfig<T['data']> & TRuntimeConfig;
constructor(name: T['name'], dataType: T['dataType'], columnType: T['columnType']);
/**
* Mark column as NOT NULL
* Returns type-branded instance with notNull: true
*/
notNull(): NotNull<this>;
/**
* Override the TypeScript type for this column.
* Mirrors Drizzle's $type() (type-only, no runtime validation changes).
*/
$type<TType>(): $Type<this, TType>;
/**
* Set default value for column
* Makes field optional on insert
*/
default(value: ColumnData<this>): HasDefault<this>;
/**
* Set default function for column (runtime evaluated on insert).
* Mirrors Drizzle's $defaultFn() / $default().
*/
$defaultFn(fn: () => ColumnData<this>): HasDefault<this>;
/**
* Alias of $defaultFn for Drizzle parity.
*/
$default(fn: () => ColumnData<this>): HasDefault<this>;
/**
* Set on-update function for column (runtime evaluated on update).
* Mirrors Drizzle's $onUpdateFn() / $onUpdate().
*/
$onUpdateFn(fn: () => ColumnData<this>): HasDefault<this>;
/**
* Alias of $onUpdateFn for Drizzle parity.
*/
$onUpdate(fn: () => ColumnData<this>): HasDefault<this>;
/**
* Mark column as primary key
* Implies NOT NULL
*/
primaryKey(): IsPrimaryKey<NotNull<this>>;
/**
* Mark column as UNIQUE
* Mirrors Drizzle column unique API
*/
unique(name?: string, config?: {
nulls: 'distinct' | 'not distinct';
}): IsUnique<this>;
/**
* Define a foreign key reference
* Mirrors Drizzle column references() API
*/
references(ref: () => ColumnBuilderBase, config?: ColumnReferenceConfig): this;
/**
* Build method - must be implemented by subclasses
* Compiles builder to Convex validator
*
* @returns Convex validator for this column
*/
abstract build(): Validator<any, any, any>;
}
/**
* Type utilities for phantom type branding
* Drizzle's EXACT pattern - verified working
*/
/**
* Brand a builder as NOT NULL
* Removes | null from extracted type
*/
type NotNull<T extends ColumnBuilderBase> = T & {
_: {
notNull: true;
};
};
/**
* Brand a builder with a table name
* Used for relation typing (fields/references must match table)
*/
type ColumnBuilderWithTableName<T extends ColumnBuilderBase, TTableName extends string> = T & {
_: {
tableName: TTableName;
};
};
/**
* Brand a builder as UNIQUE
*/
type IsUnique<T extends ColumnBuilderBase> = T & {
_: {
isUnique: true;
};
};
/**
* Brand a builder with a default value
* Makes field optional on insert
*/
type HasDefault<T extends ColumnBuilderBase> = T & {
_: {
hasDefault: true;
};
};
type ColumnData<TBuilder extends ColumnBuilderBase> = TBuilder['_'] extends {
$type: infer TType;
} ? TType : TBuilder['_']['data'];
type $Type<TBuilder extends ColumnBuilderBase, TType> = TBuilder & {
_: {
$type: TType;
};
};
/**
* Brand a builder as a primary key
* Implies NOT NULL
*/
type IsPrimaryKey<T extends ColumnBuilderBase> = T & {
_: {
isPrimaryKey: true;
notNull: true;
};
};
//#endregion
//#region src/orm/filter-expression.d.ts
/**
* Extract TypeScript type from a column builder
* Uses phantom `_` property to get type info
*/
type ColumnToType<TBuilder extends ColumnBuilder<any, any, any>> = TBuilder['_']['notNull'] extends true ? TBuilder['_']['data'] : TBuilder['_']['data'] | null;
/**
* Unique symbol for FilterExpression brand
* Prevents structural typing - only expressions created by factory functions are valid
*/
declare const FilterExpressionBrand: unique symbol;
/**
* Base filter expression interface
* All filter expressions (binary, logical, unary) implement this interface
*
* @template TValue - The TypeScript type this expression evaluates to
*/
interface FilterExpression$1<_TValue = boolean> {
/** Accept visitor for traversal */
accept<R>(visitor: ExpressionVisitor<R>): R;
/** Expression operands (FieldReference, values, or nested expressions) */
readonly operands: readonly any[];
/** Operator string (eq, and, not, etc.) */
readonly operator: string;
/** Expression type discriminator */
readonly type: 'binary' | 'logical' | 'unary';
/** Brand symbol for nominal typing */
readonly [FilterExpressionBrand]: true;
}
/**
* Binary operator expression (eq, ne, gt, gte, lt, lte, inArray, notInArray)
* Compares field to value: field eq value
*
* @template TField - Field type being compared
*/
interface BinaryExpression<TField = any> extends FilterExpression$1<boolean> {
/** [field, value] or [field, array] for inArray/notInArray */
readonly operands: readonly [FieldReference<TField>, TField | TField[]];
readonly operator: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'inArray' | 'notInArray' | 'arrayContains' | 'arrayContained' | 'arrayOverlaps' | 'like' | 'ilike' | 'notLike' | 'notIlike' | 'startsWith' | 'endsWith' | 'contains';
readonly type: 'binary';
}
/**
* Logical operator expression (and, or)
* Combines multiple filter expressions
*/
interface LogicalExpression extends FilterExpression$1<boolean> {
/** Array of nested filter expressions */
readonly operands: readonly FilterExpression$1<boolean>[];
readonly operator: 'and' | 'or';
readonly type: 'logical';
}
/**
* Unary operator expression (not, isNull, isNotNull)
* Negates or checks null state of an expression
*/
interface UnaryExpression extends FilterExpression$1<boolean> {
/** Single nested filter expression or field reference for null checks */
readonly operands: readonly [FilterExpression$1<boolean> | FieldReference<any>];
readonly operator: 'not' | 'isNull' | 'isNotNull';
readonly type: 'unary';
}
/**
* CRITICAL: FieldReference abstraction
*
* Decouples filter expressions from M2 table configuration
* Allows filter expressions to reference fields without knowing about validators
*
* @template TValue - TypeScript type of the field
*/
interface FieldReference<TValue = unknown> {
readonly __brand: 'FieldReference';
/** Phantom type for type inference - not present at runtime */
readonly __type?: TValue;
readonly fieldName: string;
}
/**
* Create a field reference
* Used internally by operator functions
*/
declare function fieldRef<T>(fieldName: string): FieldReference<T>;
/**
* Type guard for FieldReference
*/
declare function isFieldReference(value: any): value is FieldReference<any>;
/**
* Column wrapper - combines builder with column name
* Used in where clause to pass column objects to operators
* Following Drizzle's pattern: operators receive columns, not extracted types
*
* @template TBuilder - The column builder type
* @template TName - The column name (string literal)
*/
interface Column<TBuilder extends ColumnBuilder<any, any, any> = any, TName extends string = string> {
readonly builder: TBuilder;
readonly columnName: TName;
}
type ColumnArgument<TBuilder extends ColumnBuilder<any, any, any>> = Column<TBuilder, string> | TBuilder;
/**
* Create a column wrapper
* Used internally by query builder's _createColumnProxies
*/
/**
* Expression visitor interface for tree traversal
* Extensible pattern - add new visit methods without modifying expression classes
*
* @template R - Return type of visit operations
*/
interface ExpressionVisitor<R = void> {
visitBinary(expr: BinaryExpression): R;
visitLogical(expr: LogicalExpression): R;
visitUnary(expr: UnaryExpression): R;
}
/**
* Equality operator: field == value
*
* @example
* const filter = eq(cols.name, 'Alice');
*/
declare function eq<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, value: ColumnToType<TBuilder>): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Not equal operator: field != value
*/
declare function ne<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, value: ColumnToType<TBuilder>): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Greater than operator: field > value
*/
declare function gt<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, value: ColumnToType<TBuilder>): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Greater than or equal operator: field >= value
*/
declare function gte<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, value: ColumnToType<TBuilder>): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Less than operator: field < value
*/
declare function lt<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, value: ColumnToType<TBuilder>): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Less than or equal operator: field <= value
*/
declare function lte<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, value: ColumnToType<TBuilder>): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Between operator: field BETWEEN min AND max (inclusive)
*
* Sugar for and(gte(field, min), lte(field, max)).
*/
declare function between<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, min: ColumnToType<TBuilder>, max: ColumnToType<TBuilder>): FilterExpression$1<boolean>;
/**
* Not between operator: field < min OR field > max
*
* Sugar for or(lt(field, min), gt(field, max)).
*/
declare function notBetween<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, min: ColumnToType<TBuilder>, max: ColumnToType<TBuilder>): FilterExpression$1<boolean>;
/**
* LIKE operator: SQL-style pattern matching with % wildcards
* Note: Implemented as post-filter (Convex has no native LIKE)
*
* @example
* const users = await db.query.users.findMany({
* where: like(users.name, '%alice%'),
* });
*/
declare function like<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, pattern: string): BinaryExpression<string>;
/**
* ILIKE operator: Case-insensitive LIKE
* Note: Implemented as post-filter (Convex has no native LIKE)
*
* @example
* const users = await db.query.users.findMany({
* where: ilike(users.name, '%ALICE%'),
* });
*/
declare function ilike<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, pattern: string): BinaryExpression<string>;
/**
* startsWith operator: Check if string starts with prefix
* Optimized for prefix matching
*
* @example
* const users = await db.query.users.findMany({
* where: startsWith(users.email, 'admin@'),
* });
*/
declare function startsWith<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, prefix: string): BinaryExpression<string>;
/**
* endsWith operator: Check if string ends with suffix
*
* @example
* const users = await db.query.users.findMany({
* where: endsWith(users.email, '@example.com'),
* });
*/
declare function endsWith<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, suffix: string): BinaryExpression<string>;
/**
* contains operator: Check if string contains substring
* Can use search index for optimization when available
*
* @example
* const posts = await db.query.posts.findMany({
* where: contains(posts.title, 'javascript'),
* });
*/
declare function contains<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, substring: string): BinaryExpression<string>;
/**
* Logical AND: all expressions must be true
* Filters out undefined expressions (following Drizzle pattern)
*
* @example
* const filter = and(
* eq(fieldRef('age'), 25),
* eq(fieldRef('name'), 'Alice')
* );
*/
declare function and(...expressions: (FilterExpression$1<boolean> | undefined)[]): LogicalExpression | undefined;
/**
* Logical OR: at least one expression must be true
* Filters out undefined expressions (following Drizzle pattern)
*
* @example
* const filter = or(
* eq(fieldRef('status'), 'active'),
* eq(fieldRef('status'), 'pending')
* );
*/
declare function or(...expressions: (FilterExpression$1<boolean> | undefined)[]): LogicalExpression | undefined;
/**
* Logical NOT: negates expression
*
* @example
* const filter = not(eq(fieldRef('isDeleted'), true));
*/
declare function not(expression: FilterExpression$1<boolean>): UnaryExpression;
/**
* Array membership operator: field IN array
*
* @example
* const filter = inArray(cols.status, ['active', 'pending']);
*/
declare function inArray<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, values: readonly ColumnToType<TBuilder>[]): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Array exclusion operator: field NOT IN array
* Validates array is non-empty at construction time
*
* @example
* const filter = notInArray(cols.role, ['admin', 'moderator']);
*/
declare function notInArray<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>, values: readonly ColumnToType<TBuilder>[]): BinaryExpression<ColumnToType<TBuilder>>;
/**
* Null check operator: field IS NULL
* Type validation: Only works with nullable fields
*
* @example
* const filter = isNull(cols.deletedAt);
*/
declare function isNull<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>): UnaryExpression;
/**
* Not null check operator: field IS NOT NULL
* Type validation: Only works with nullable fields
*
* @example
* const filter = isNotNull(cols.deletedAt);
*/
declare function isNotNull<TBuilder extends ColumnBuilder<any, any, any>>(col: ColumnArgument<TBuilder>): UnaryExpression;
//#endregion
//#region src/orm/builders/system-fields.d.ts
/**
* System ID field builder (public id, internal _id)
* Always present, always non-null
*/
type ConvexSystemIdConfig = ColumnBuilderBaseConfig<'string', 'ConvexSystemId'> & {
data: string;
driverParam: string;
enumValues: undefined;
};
declare class ConvexSystemIdBuilder<_TTableName extends string> extends ColumnBuilder<ConvexSystemIdConfig, {}, {
notNull: true;
}> {
static readonly [entityKind]: string;
readonly [entityKind]: string;
constructor();
build(): convex_values0.VString<string, "required">;
/**
* Convex validator - runtime access
* System fields use v.string() for _id
*/
get convexValidator(): convex_values0.VString<string, "required">;
}
/**
* System creation time field builder (_creationTime)
* Always present, always non-null, always a number (milliseconds)
*/
type ConvexSystemCreationTimeConfig = ColumnBuilderBaseConfig<'number', 'ConvexSystemCreationTime'> & {
data: number;
driverParam: number;
enumValues: undefined;
};
declare class ConvexSystemCreationTimeBuilder extends ColumnBuilder<ConvexSystemCreationTimeConfig, {}, {
notNull: true;
}> {
static readonly [entityKind]: string;
readonly [entityKind]: string;
constructor();
build(): convex_values0.VFloat64<number, "required">;
/**
* Convex validator - runtime access
* System fields use v.number() for _creationTime
*/
get convexValidator(): convex_values0.VFloat64<number, "required">;
}
type ConvexSystemCreatedAtConfig = ColumnBuilderBaseConfig<'number', 'ConvexSystemCreatedAt'> & {
data: number;
driverParam: number;
enumValues: undefined;
};
declare class ConvexSystemCreatedAtBuilder extends ColumnBuilder<ConvexSystemCreatedAtConfig, {}, {
notNull: true;
}> {
static readonly [entityKind]: string;
readonly [entityKind]: string;
constructor();
build(): convex_values0.VFloat64<number, "required">;
get convexValidator(): convex_values0.VFloat64<number, "required">;
}
/**
* Create system field builders for a table
* These are automatically added to every ConvexTable
*/
type SystemFields<TName extends string> = {
id: ColumnBuilderWithTableName<ConvexSystemIdBuilder<TName>, TName>;
};
type InternalSystemFields<TName extends string> = {
_creationTime: ColumnBuilderWithTableName<ConvexSystemCreationTimeBuilder, TName>;
};
type SystemFieldAliases<TName extends string, TColumns extends Record<string, unknown> = {}> = 'createdAt' extends keyof TColumns ? {} : {
createdAt: ColumnBuilderWithTableName<ConvexSystemCreatedAtBuilder, TName>;
};
type SystemFieldsWithAliases<TName extends string, TColumns extends Record<string, unknown> = {}> = SystemFields<TName> & InternalSystemFields<TName> & SystemFieldAliases<TName, TColumns>;
//#endregion
//#region src/orm/symbols.d.ts
/**
* Symbol-based metadata storage for ORM tables
* Following Drizzle's pattern for type-safe runtime introspection
*/
type OrmRuntimeDefaults = {
defaultLimit?: number;
countBackfillBatchSize?: number;
relationFanOutMaxKeys?: number;
aggregateCartesianMaxKeys?: number;
aggregateWorkBudget?: number;
mutationBatchSize?: number;
mutationLeafBatchSize?: number;
mutationMaxRows?: number;
mutationMaxBytesPerBatch?: number;
mutationScheduleCallCap?: number;
mutationExecutionMode?: 'sync' | 'async';
mutationAsyncDelayMs?: number;
};
type OrmDeleteMode = 'hard' | 'soft' | 'scheduled';
type OrmTableDeleteConfig = {
mode: OrmDeleteMode;
delayMs?: number;
};
type TablePolymorphicVariantRuntime = {
fieldNames: readonly string[];
requiredFieldNames: readonly string[];
};
type TablePolymorphicConfigRuntime = {
discriminator: string;
alias: string;
generatedFieldNames: readonly string[];
variants: Readonly<Record<string, TablePolymorphicVariantRuntime>>;
};
declare const TableName: unique symbol;
declare const Columns: unique symbol;
declare const Brand: unique symbol;
declare const RlsPolicies: unique symbol;
declare const EnableRLS: unique symbol;
declare const TableDeleteConfig: unique symbol;
declare const TablePolymorphic: unique symbol;
declare const OrmSchemaDefinition: unique symbol;
declare const OrmSchemaExtensionTables: unique symbol;
declare const OrmSchemaExtensions: unique symbol;
declare const OrmSchemaExtensionRelations: unique symbol;
declare const OrmSchemaExtensionTriggers: unique symbol;
declare const OrmSchemaRelations: unique symbol;
declare const OrmSchemaTriggers: unique symbol;
//#endregion
//#region src/orm/unset-token.d.ts
declare const unsetToken: unique symbol;
type UnsetToken = typeof unsetToken;
//#endregion
//#region src/orm/types.d.ts
/**
* Value or array helper (Drizzle pattern).
*/
type ValueOrArray<T> = T | T[];
/**
* Type equality check - returns true if X and Y are exactly the same type
* Pattern from Drizzle: drizzle-orm/src/utils.ts:172
*/
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
/**
* Merge two object types without using intersection
* Intersection can cause TypeScript to lose phantom type brands
* This manually combines keys from both types
*/
type Merge<A, B> = { [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never };
type IndexKey = (Value | undefined)[];
type FindManyUnionSource<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = {
where?: RelationsFilter<TTableConfig, any> | WhereCallback<TTableConfig>;
};
type PipelineRelationName<TTableConfig extends TableRelationalConfig> = Extract<keyof TTableConfig['relations'], string>;
type FindManyPipelineFlatMapConfig<TTableConfig extends TableRelationalConfig = TableRelationalConfig, TRelationName extends PipelineRelationName<TTableConfig> = PipelineRelationName<TTableConfig>> = {
relation: TRelationName;
where?: unknown;
orderBy?: unknown;
limit?: number;
includeParent?: boolean;
};
type FindManyPipelineFlatMapStage<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = {
flatMap: FindManyPipelineFlatMapConfig<TTableConfig>;
};
type FindManyPipelineFilterWithStage<TRow = unknown> = {
filterWith: (row: TRow) => boolean | Promise<boolean>;
};
type FindManyPipelineMapStage<TRow = unknown, TOutput = unknown> = {
map: (row: TRow) => TOutput | null | Promise<TOutput | null>;
};
type FindManyPipelineDistinctStage = {
distinct: {
fields: string[];
};
};
type FindManyPipelineStageForInput<TSchema extends TablesRelationalConfig = TablesRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig, TRow = BuildQueryResult<TSchema, TTableConfig, true>> = FindManyPipelineFilterWithStage<TRow> | FindManyPipelineMapStage<TRow> | FindManyPipelineDistinctStage | FindManyPipelineFlatMapStage<TTableConfig>;
type FindManyPipelineConfig<TSchema extends TablesRelationalConfig = TablesRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig, TStages extends readonly unknown[] = readonly FindManyPipelineStageForInput<TSchema, TTableConfig, BuildQueryResult<TSchema, TTableConfig, true>>[]> = {
union?: FindManyUnionSource<TTableConfig>[];
interleaveBy?: string[];
stages?: TStages;
};
type FindManyPageByKeyConfig = {
index?: string;
order?: 'asc' | 'desc';
startKey?: IndexKey;
startInclusive?: boolean;
endKey?: IndexKey;
endInclusive?: boolean;
targetMaxRows?: number;
absoluteMaxRows?: number;
};
type KeyPageResult<T> = {
page: T[];
indexKeys: IndexKey[];
hasMore: boolean;
};
/**
* Extract full document type from a ConvexTable (includes system fields)
* Uses GetColumnData in 'query' mode to respect notNull brands
*
* @example
* const users = convexTable('users', { name: text().notNull() });
* type User = InferSelectModel<typeof users>;
* // → { id: string, createdAt: number, name: string }
*
* const posts = convexTable('posts', { title: text() }); // nullable
* type Post = InferSelectModel<typeof posts>;
* // → { id: string, createdAt: number, title: string | null }
*/
type InferSelectModel<TTable extends ConvexTable<any>> = Simplify$1<Merge<{
id: string;
createdAt: number;
}, { [K in keyof TTable['_']['columns']]: GetColumnData<TTable['_']['columns'][K], 'query'> }>>;
type RequiredKeyOnly<TKey extends string, TColumn extends ColumnBuilderBase> = TColumn['_']['notNull'] extends true ? TColumn['_']['hasDefault'] extends true ? never : TKey : never;
type OptionalKeyOnly<TKey extends string, TColumn extends ColumnBuilderBase> = TColumn['_']['notNull'] extends true ? TColumn['_']['hasDefault'] extends true ? TKey : never : TKey;
type InferInsertModelFromColumns<TColumns extends Record<string, ColumnBuilderBase>, TExcludeKeys extends string = never> = Simplify$1<{ [K in keyof TColumns & string as K extends TExcludeKeys ? never : RequiredKeyOnly<K, TColumns[K]>]: GetColumnData<TColumns[K], 'query'> } & { [K in keyof TColumns & string as K extends TExcludeKeys ? never : OptionalKeyOnly<K, TColumns[K]>]?: GetColumnData<TColumns[K], 'query'> | undefined }>;
type TablePolymorphicInsertMetadata<TTable extends ConvexTable<any>> = { [K in keyof TTable['_']['columns'] & string]: TTable['_']['columns'][K] extends {
__polymorphic: infer TMeta;
} ? TMeta extends {
variants: infer TVariants extends Record<string, Record<string, ColumnBuilderBase>>;
} ? {
discriminator: K;
variants: TVariants;
} : never : never }[keyof TTable['_']['columns'] & string];
type PolymorphicVariantFieldNames<TVariants extends Record<string, Record<string, ColumnBuilderBase>>> = Extract<TVariants[keyof TVariants & string] extends infer TVariantColumns ? TVariantColumns extends Record<string, ColumnBuilderBase> ? keyof TVariantColumns : never : never, string>;
type PolymorphicVariantInsertCase<TBase extends Record<string, unknown>, TDiscriminator extends string, TCase extends string, TVariantColumns extends Record<string, ColumnBuilderBase>, TAllGeneratedFields extends string> = Simplify$1<TBase & { [K in TDiscriminator]: TCase } & { [K in keyof TVariantColumns & string as RequiredKeyOnly<K, TVariantColumns[K]>]: GetColumnData<TVariantColumns[K], 'query'> } & { [K in keyof TVariantColumns & string as OptionalKeyOnly<K, TVariantColumns[K]>]?: GetColumnData<TVariantColumns[K], 'query'> | undefined } & { [K in Exclude<TAllGeneratedFields, keyof TVariantColumns & string>]?: never }>;
type PolymorphicVariantInsertUnion<TBase extends Record<string, unknown>, TMetadata extends {
discriminator: string;
variants: Record<string, Record<string, ColumnBuilderBase>>;
}> = { [TCase in keyof TMetadata['variants'] & string]: PolymorphicVariantInsertCase<TBase, TMetadata['discriminator'], TCase, TMetadata['variants'][TCase], PolymorphicVariantFieldNames<TMetadata['variants']>> }[keyof TMetadata['variants'] & string];
type InferPolymorphicInsertModel<TTable extends ConvexTable<any>, TMetadata extends {
discriminator: string;
variants: Record<string, Record<string, ColumnBuilderBase>>;
}> = PolymorphicVariantInsertUnion<InferInsertModelFromColumns<TTable['_']['columns'], TMetadata['discriminator'] | PolymorphicVariantFieldNames<TMetadata['variants']>>, TMetadata>;
/**
* Extract insert type from a ConvexTable (excludes system fields).
* Mirrors Drizzle behavior: required if notNull && no default, otherwise optional.
*
* @example
* const users = convexTable('users', { name: text().notNull() });
* type NewUser = InferInsertModel<typeof users>;
* // → { name: string }
*/
type InferInsertModel<TTable extends ConvexTable<any>> = Simplify$1<[TablePolymorphicInsertMetadata<TTable>] extends [never] ? InferInsertModelFromColumns<TTable['_']['columns']> : InferPolymorphicInsertModel<TTable, Extract<TablePolymorphicInsertMetadata<TTable>, object>>>;
/**
* Extract column data type with mode-based handling (Drizzle pattern)
*
* Following Drizzle's GetColumnData pattern for consistent type extraction:
* - 'raw' mode: Returns base data type without null (for inserts, operator comparisons)
* - 'query' mode: Respects notNull brand, adds | null for nullable fields (for selects)
*
* @template TColumn - Column builder type
* @template TInferMode - 'query' (default, adds | null) or 'raw' (base type only)
*
* @example
* const name = text().notNull();
* type NameQuery = GetColumnData<typeof name, 'query'>; // string
* type NameRaw = GetColumnData<typeof name, 'raw'>; // string
*
* const age = integer(); // nullable
* type AgeQuery = GetColumnData<typeof age, 'query'>; // number | null
* type AgeRaw = GetColumnData<typeof age, 'raw'>; // number
*/
type GetColumnData<TColumn extends ColumnBuilderBase, TInferMode extends 'query' | 'raw' = 'query'> = TInferMode extends 'raw' ? ColumnDataWithOverride<TColumn> : TColumn['_']['notNull'] extends true ? ColumnDataWithOverride<TColumn> : ColumnDataWithOverride<TColumn> | null;
type ColumnDataWithOverride<TColumn extends ColumnBuilderBase> = TColumn['_'] extends {
$type: infer TType;
} ? unknown extends TType ? TColumn['_']['data'] : TType : TColumn['_']['data'];
type AggregateIndexMap<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = TTableConfig['table'] extends ConvexTable<any, any, any, any, infer TAggregateIndexes extends Record<string, string>> ? TAggregateIndexes : Record<string, string>;
type AggregateIndexedFieldName<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = Extract<{ [K in keyof AggregateIndexMap<TTableConfig>]: AggregateIndexMap<TTableConfig>[K] }[keyof AggregateIndexMap<TTableConfig>], string>;
type AggregateScalarFieldName<TTableConfig extends TableRelationalConfig> = Extract<keyof TTableConfig['table']['_']['columns'], string>;
type AggregateWhereFieldName<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = AggregateIndexedFieldName<TTableConfig>;
type AggregateWhereFieldValue<TTableConfig extends TableRelationalConfig, TFieldName extends string> = TFieldName extends keyof TTableConfig['table']['_']['columns'] ? TTableConfig['table']['_']['columns'][TFieldName] extends ColumnBuilderBase ? GetColumnData<TTableConfig['table']['_']['columns'][TFieldName], 'query'> : unknown : unknown;
type AggregateWhereFieldFilter<TValue> = TValue | {
eq?: TValue | undefined;
in?: readonly TValue[] | undefined;
isNull?: true | undefined;
gt?: TValue | undefined;
gte?: TValue | undefined;
lt?: TValue | undefined;
lte?: TValue | undefined;
};
type AggregateNoScanWhereBase<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = { [K in AggregateWhereFieldName<TTableConfig>]?: AggregateWhereFieldFilter<AggregateWhereFieldValue<TTableConfig, K>> };
type AggregateNoScanWhere<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = Simplify$1<AggregateNoScanWhereBase<TTableConfig> & {
AND?: AggregateNoScanWhereBase<TTableConfig>[] | undefined;
OR?: AggregateNoScanWhereBase<TTableConfig>[] | undefined;
}>;
type AggregateNoScanWhereArg<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = [AggregateWhereFieldName<TTableConfig>] extends [never] ? never : AggregateNoScanWhere<TTableConfig>;
/**
* Query configuration for findMany/findFirst
*
* @template TRelationType - 'one' or 'many' determines available options
* @template TSchema - Full schema configuration
* @template TTableConfig - Configuration for the queried table
*/
type DBQueryConfig<TRelationType extends 'one' | 'many' = 'one' | 'many', _TIsRoot extends boolean = boolean, TSchema extends TablesRelationalConfig = TablesRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig> = {
/**
* Column selection - pick specific columns to return
* If omitted, all columns are selected
*/
columns?: { [K in keyof TableColumns<TTableConfig>]?: boolean } | undefined;
/**
* Relation loading - specify which relations to include
* Can be `true` for default config or nested config object
*/
with?: KnownKeysOnly<{ [K in keyof TTableConfig['relations']]?: true | DBQueryConfig<TTableConfig['relations'][K] extends One<any, any> ? 'one' : 'many', false, TSchema, FindTableByDBName<TSchema, TTableConfig['relations'][K]['targetTableName']>> | undefined } & {
_count?: { [K in keyof TTableConfig['relations']]?: true | {
where?: AggregateNoScanWhereArg<FindTableByDBName<TSchema, Extract<TTableConfig['relations'][K]['targetTableName'], string>>> | undefined;
} } | undefined;
}, TTableConfig['relations'] & {
_count?: unknown;
}> | undefined;
/**
* Auto-include one() relations for discriminator-backed tables.
*/
withVariants?: true | undefined;
/**
* Extra computed fields (post-fetch, computed in JS at runtime)
*/
extras?: Record<string, Value | ((row: InferModelFromColumns<TableColumns<TTableConfig>>) => Value)> | ((fields: Simplify$1<[TableColumns<TTableConfig>] extends [never] ? {} : TableColumns<TTableConfig>>) => Record<string, Value | ((row: InferModelFromColumns<TableColumns<TTableConfig>>) => Value)>) | undefined;
/**
* Order results - callback or object syntax
*/
orderBy?: DBQueryConfigOrderBy<TTableConfig> | undefined; /** Skip first N results */
offset?: number | undefined;
/**
* Cursor pagination (Convex native). When `cursor` is provided, `limit` is
* required and the result type changes to a paginated shape.
*
* - First page: cursor: null
* - Next page: cursor: previous.continueCursor
*/
cursor?: _TIsRoot extends true ? string | null : never;
/**
* Pin the end boundary to a previously returned cursor.
* Only valid with cursor pagination.
*/
endCursor?: _TIsRoot extends true ? string | null : never;
/**
* Maximum documents to scan during predicate `where(fn)` pagination.
* Only valid when `cursor` is provided.
*/
maxScan?: _TIsRoot extends true ? number : never;
/**
* Full-text search query configuration.
* Only available on tables that declare search indexes.
*/
search?: SearchQueryConfig<TTableConfig> | undefined;
/**
* Vector search query configuration.
* Only available on tables that declare vector indexes.
*/
vectorSearch?: VectorQueryConfig<TTableConfig> | undefined;
/**
* Stream-backed advanced query pipeline.
*/
pipeline?: _TIsRoot extends true ? FindManyPipelineConfig<TSchema, TTableConfig> : never;
/**
* Key-based page boundaries.
*/
pageByKey?: _TIsRoot extends true ? FindManyPageByKeyConfig : never;
} & (TRelationType extends 'many' ? {
/** Limit number of results */limit?: number | undefined;
} : {}) & {
/**
* Relation-aware filter object (v1) or callback expression.
*/
where?: RelationsFilter<TTableConfig, TSchema> | WhereCallback<TTableConfig> | undefined;
/**
* Allow full scans when no index can be used.
*/
allowFullScan?: boolean | undefined;
};
type CountConfig<_TSchema extends TablesRelationalConfig = TablesRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig> = {
where?: AggregateNoScanWhereArg<TTableConfig> | undefined;
orderBy?: DBQueryConfigOrderBy<TTableConfig> | undefined;
skip?: number | undefined;
take?: number | undefined;
cursor?: { [K in Extract<keyof TTableConfig['table']['_']['columns'], string>]?: GetColumnData<TableColumns<TTableConfig>[K], 'query'> | undefined } | undefined;
select?: ({
_all?: true | undefined;
} & { [K in Extract<keyof TTableConfig['table']['_']['columns'], string>]?: true | undefined }) | undefined;
};
type AggregateNumericFieldName<TTableConfig extends TableRelationalConfig> = { [K in AggregateScalarFieldName<TTableConfig>]: NonNullable<GetColumnData<TableColumns<TTableConfig>[K], 'query'>> extends number ? K : never }[AggregateScalarFieldName<TTableConfig>];
type AggregateFieldValue<TTableConfig extends TableRelationalConfig, TField extends AggregateScalarFieldName<TTableConfig>> = GetColumnData<TableColumns<TTableConfig>[TField], 'query'>;
type AggregateConfig<_TSchema extends TablesRelationalConfig = TablesRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig> = {
where?: AggregateNoScanWhereArg<TTableConfig> | undefined;
orderBy?: DBQueryConfigOrderBy<TTableConfig> | undefined;
skip?: number | undefined;
take?: number | undefined;
cursor?: { [K in Extract<keyof TTableConfig['table']['_']['columns'], string>]?: GetColumnData<TableColumns<TTableConfig>[K], 'query'> | undefined } | undefined;
_count?: true | ({
_all?: true | undefined;
} & { [K in AggregateScalarFieldName<TTableConfig>]?: true | undefined }) | undefined;
_sum?: { [K in AggregateNumericFieldName<TTableConfig>]?: true | undefined } | undefined;
_avg?: { [K in AggregateNumericFieldName<TTableConfig>]?: true | undefined } | undefined;
_min?: { [K in AggregateScalarFieldName<TTableConfig>]?: true | undefined } | undefined;
_max?: { [K in AggregateScalarFieldName<TTableConfig>]?: true | undefined } | undefined;
};
type GroupByByInput<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = AggregateWhereFieldName<TTableConfig> | readonly AggregateWhereFieldName<TTableConfig>[];
type GroupBySelectedFields<TBy> = TBy extends readonly (infer TField)[] ? Extract<TField, string> : Extract<TBy, string>;
type GroupByByResult<TTableConfig extends TableRelationalConfig, TBy> = Simplify$1<{ [K in GroupBySelectedFields<TBy> & AggregateScalarFieldName<TTableConfig>]: AggregateFieldValue<TTableConfig, K> }>;
type GroupByOrderDirection = 'asc' | 'desc';
type GroupByByOrderBy<TBy> = Partial<Record<GroupBySelectedFields<TBy>, GroupByOrderDirection>>;
type GroupByMetricOrderBy<TTableConfig extends TableRelationalConfig> = {
_count?: GroupByOrderDirection | ({
_all?: GroupByOrderDirection | undefined;
} & { [K in AggregateScalarFieldName<TTableConfig>]?: GroupByOrderDirection | undefined }) | undefined;
_sum?: { [K in AggregateNumericFieldName<TTableConfig>]?: GroupByOrderDirection | undefined } | undefined;
_avg?: { [K in AggregateNumericFieldName<TTableConfig>]?: GroupByOrderDirection | undefined } | undefined;
_min?: { [K in AggregateScalarFieldName<TTableConfig>]?: GroupByOrderDirection | undefined } | undefined;
_max?: { [K in AggregateScalarFieldName<TTableConfig>]?: GroupByOrderDirection | undefined } | undefined;
};
type GroupByOrderBy<TTableConfig extends TableRelationalConfig, TBy> = ValueOrArray<GroupByByOrderBy<TBy> | GroupByMetricOrderBy<TTableConfig>>;
type GroupByHavingValue<TValue> = TValue | {
eq?: TValue | undefined;
in?: readonly TValue[] | undefined;
isNull?: true | undefined;
gt?: TValue | undefined;
gte?: TValue | undefined;
lt?: TValue | undefined;
lte?: TValue | undefined;
};
type GroupByHaving<TTableConfig extends TableRelationalConfig, TBy> = Simplify$1<{ [K in GroupBySelectedFields<TBy>]?: GroupByHavingValue<AggregateFieldValue<TTableConfig, Extract<K, AggregateScalarFieldName<TTableConfig>>>> } & {
_count?: GroupByHavingValue<number> | ({
_all?: GroupByHavingValue<number> | undefined;
} & { [K in AggregateScalarFieldName<TTableConfig>]?: GroupByHavingValue<number> | undefined }) | undefined;
_sum?: { [K in AggregateNumericFieldName<TTableConfig>]?: GroupByHavingValue<number | null> | undefined } | undefined;
_avg?: { [K in AggregateNumericFieldName<TTableConfig>]?: GroupByHavingValue<number | null> | undefined } | undefined;
_min?: { [K in AggregateScalarFieldName<TTableConfig>]?: GroupByHavingValue<AggregateFieldValue<TTableConfig, K> | null> | undefined } | undefined;
_max?: { [K in AggregateScalarFieldName<TTableConfig>]?: GroupByHavingValue<AggregateFieldValue<TTableConfig, K> | null> | undefined } | undefined;
AND?: GroupByHaving<TTableConfig, TBy>[] | undefined;
}>;
type GroupByConfig<_TSchema extends TablesRelationalConfig = TablesRelationalConfig, TTableConfig extends TableRelationalConfig = TableRelationalConfig> = {
by: GroupByByInput<TTableConfig>;
where?: AggregateNoScanWhereArg<TTableConfig> | undefined;
orderBy?: GroupByOrderBy<TTableConfig, GroupByByInput<TTableConfig>> | undefined;
skip?: number | undefined;
take?: number | undefined;
cursor?: Record<string, unknown> | undefined;
having?: GroupByHaving<TTableConfig, GroupByByInput<TTableConfig>> | undefined;
_count?: true | ({
_all?: true | undefined;
} & { [K in AggregateScalarFieldName<TTableConfig>]?: true | undefined }) | undefined;
_sum?: { [K in AggregateNumericFieldName<TTableConfig>]?: true | undefined } | undefined;
_avg?: { [K in AggregateNumericFieldName<TTableConfig>]?: true | undefined } | undefined;
_min?: { [K in AggregateScalarFieldName<TTableConfig>]?: true | undefined } | undefined;
_max?: { [K in AggregateScalarFieldName<TTableConfig>]?: true | undefined } | undefined;
};
type SelectedTrueKeys<TSelection> = Extract<{ [K in keyof TSelection]-?: TSelection[K] extends true ? K : never }[keyof TSelection], string>;
type CountSelectResult<TTableConfig extends TableRelationalConfig, TSelect extends Record<string, unknown>> = Simplify$1<(TSelect extends {
_all: true;
} ? {
_all: number;
} : {}) & { [K in SelectedTrueKeys<TSelect> & AggregateScalarFieldName<TTableConfig>]: number }>;
type AggregateCountResult<TTableConfig extends TableRelationalConfig, TCount> = TCount extends true ? number : TCount extends Record<string, unknown> ? CountSelectResult<TTableConfig, TCount> : never;
type AggregateNumericNullableResult<TSelect> = Simplify$1<{ [K in SelectedTrueKeys<NonNullable<TSelect>>]: number | null }>;
type AggregateComparableResult<TTableConfig extends TableRelationalConfig, TSelect> = Simplify$1<{ [K in SelectedTrueKeys<NonNullable<TSelect>> & AggregateScalarFieldName<TTableConfig>]: AggregateFieldValue<TTableConfig, K> | null }>;
type CountResult<TTableConfig extends TableRelationalConfig, TConfig extends CountConfig<any, TTableConfig> | undefined> = TConfig extends {
select: infer TSelect extends Record<string, unknown>;
} ? CountSelectResult<TTableConfig, TSelect> : number;
type AggregateResult<TTableConfig extends TableRelationalConfig, TConfig extends AggregateConfig<any, TTableConfig>> = Simplify$1<(TConfig extends {
_count: infer TCount;
} ? {
_count: AggregateCountResult<TTableConfig, TCount>;
} : {}) & (TConfig extends {
_sum: infer TSum extends Record<string, unknown>;
} ? {
_sum: AggregateNumericNullableResult<TSum>;
} : {}) & (TConfig extends {
_avg: infer TAvg extends Record<string, unknown>;
} ? {
_avg: AggregateNumericNullableResult<TAvg>;
} : {}) & (TConfig extends {
_min: infer TMin extends Record<string, unknown>;
} ? {
_min: AggregateComparableResult<TTableConfig, TMin>;
} : {}) & (TConfig extends {
_max: infer TMax extends Record<string, unknown>;
} ? {
_max: AggregateComparableResult<TTableConfig, TMax>;
} : {})>;
type GroupByRowResult<TTableConfig extends TableRelationalConfig, TConfig extends GroupByConfig<any, TTableConfig>> = Simplify$1<GroupByByResult<TTableConfig, TConfig['by']> & (TConfig extends {
_count: infer TCount;
} ? {
_count: AggregateCountResult<TTableConfig, TCount>;
} : {}) & (TConfig extends {
_sum: infer TSum extends Record<string, unknown>;
} ? {
_sum: AggregateNumericNullableResult<TSum>;
} : {}) & (TConfig extends {
_avg: infer TAvg extends Record<string, unknown>;
} ? {
_avg: AggregateNumericNullableResult<TAvg>;
} : {}) & (TConfig extends {
_min: infer TMin extends Record<string, unknown>;
} ? {
_min: AggregateComparableResult<TTableConfig, TMin>;
} : {}) & (TConfig extends {
_max: infer TMax extends Record<string, unknown>;
} ? {
_max: AggregateComparableResult<TTableConfig, TMax>;
} : {})>;
type GroupByResult<TTableConfig extends TableRelationalConfig, TConfig extends GroupByConfig<any, TTableConfig>> = GroupByRowResult<TTableConfig, TConfig>[];
type PredicateWhereClause<TTableConfig extends TableRelationalConfig> = {
readonly __kind: 'predicate';
readonly predicate: (row: InferModelFromColumns<TableColumns<TTableConfig>>) => boolean | Promise<boolean>;
};
type WhereCallback<TTableConfig extends TableRelationalConfig> = (table: TTableConfig['table'], operators: FilterOperators<TTableConfig>) => FilterExpression$1<boolean> | PredicateWhereClause<TTableConfig> | undefined;
type PredicateWhereIndexMap<TTableConfig extends TableRelationalConfig> = TTableConfig['table'] extends ConvexTable<any, infer TIndexes, any, any> ? TIndexes : Record<string, GenericIndexFields>;
type PredicateWhereIndexName<TTableConfig extends TableRelationalConfig> = Extract<keyof PredicateWhereIndexMap<TTableConfig>, string>;
type PredicateWhereNamedIndex<TTableConfig extends TableRelationalConfig, TIndexName extends string> = TIndexName extends PredicateWhereIndexName<TTableConfig> ? PredicateWhereIndexMap<TTableConfig>[TIndexName] extends GenericIndexFields ? PredicateWhereIndexMap<TTableConfig>[TIndexName] : GenericIndexFields : GenericIndexFields;
type PredicateWhereIndexConfig<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = [PredicateWhereIndexName<TTableConfig>] extends [never] ? {
name: string;
range?: (q: IndexRangeBuilder<InferModelFromColumns<TableColumns<TTableConfig>>, GenericIndexFields>) => IndexRange;
} : { [TIndexName in PredicateWhereIndexName<TTableConfig>]: {
name: TIndexName;
range?: (q: IndexRangeBuilder<InferModelFromColumns<TableColumns<TTableConfig>>, PredicateWhereNamedIndex<TTableConfig, TIndexName>>) => IndexRange;
} }[PredicateWhereIndexName<TTableConfig>];
type SearchIndexMap<TTableConfig extends TableRelationalConfig> = TTableConfig['table'] extends ConvexTable<any, any, infer TSearchIndexes, any> ? TSearchIndexes : Record<string, {
searchField: string;
filterFields: string;
}>;
type SearchIndexName<TTableConfig extends TableRelationalConfig> = Extract<keyof SearchIndexMap<TTableConfig>, string>;
type SearchIndexConfigByName<TTableConfig extends TableRelationalConfig, TIndexName extends SearchIndexName<TTableConfig>> = SearchIndexMap<TTableConfig>[TIndexName];
type SearchFilterFieldNames<TTableConfig extends TableRelationalConfig, TIndexName extends SearchIndexName<TTableConfig>> = SearchIndexConfigByName<TTableConfig, TIndexName> extends {
filterFields: infer TFilterFields extends string;
} ? TFilterFields : never;
type SearchFilterValueForField<TTableConfig extends TableRelationalConfig, TFieldName extends string> = TFieldName extends keyof TableColumns<TTableConfig> ? TableColumns<TTableConfig>[TFieldName] extends ColumnBuilder<any, any, any> ? GetColumnData<TableColumns<TTableConfig>[TFieldName], 'raw'> : never : never;
type SearchFiltersForIndex<TTableConfig extends TableRelationalConfig, TIndexName extends SearchIndexName<TTableConfig>> = Partial<{ [K in SearchFilterFieldNames<TTableConfig, TIndexName>]: SearchFilterValueForField<TTableConfig, K> }>;
type SearchQueryConfig<TTableConfig extends TableRelationalConfig = TableRelationalConfig> = [SearchIndexName<TTableConfig>] extends [never] ? never : { [TIndexName in SearchIndexName<TTableConfig>]: {
index: TIndexName;
query: string;
filters?: SearchFiltersForIndex<TTableConfig, TIndexName> | undefined;
} }[SearchIndexName<TTableConfig>];
type SearchWhereFilter<TTableConfig extends TableRelationalConfig> = TableFilter<TTableConfig['table']>;
type VectorIndexMap<TTableConfig extends TableRelationalConfig> = TTableConfig['table'] extends ConvexTable<any, any, any, infer TVectorIndexes> ? TVectorIndexes : Record<string, {
vectorField: string;
dimensions: number;
filterFields: string;
}>;
type VectorIndexName<TTableConfig extends TableRelationalConfig> = Extract<keyof VectorIndexMap<TTableConfig>, string>;
type VectorIndexConfigByName<TTableConfig extends TableRelationalConfig, TIndexName extends VectorIndexName<TTableConfig>> = VectorIndexMap<TTableConfig>[TIndexName];
type VectorFilterFieldNames<TTableConfig extends TableRelationalConfig, TIndexName extends VectorIndexName<TTableConfig>> = VectorIndexConfigByName<TTableConfig, TIndexName> extends {
filterFields: infer TFilterFields extends string;
} ? TFilt