import { FieldOptions, FieldOutput, FieldValidateInput, TailorFieldType, TailorToTs } from "../../types/field.types.mjs"; import { InferredAttributes } from "../../../runtime/types.mjs"; import { InferFieldsOutput, IsUnion, TypeLevelError, UnionToIntersection, output } from "../../../types/helpers.mjs"; import { DBFieldMetadata, DefinedDBFieldMetadata, ExcludeDefaultedDBFields, ExcludeHookedDBFields, ExcludeNestedDBFields, Hook, IndexDef, RelationType, SerialConfig, TailorDBField as TailorDBField$1, TailorDBType as TailorDBType$1, TypeFeatures, TypeHook, TypeValidateFn, UpdateHookFn } from "./types.mjs"; import { AllowedValues, AllowedValuesOutput } from "../../types/field.mjs"; import { FieldParseArgs } from "../../../runtime/field-parse.mjs"; import { PluginConfigs, PluginFieldExtensions } from "../../../plugin/types.mjs"; import { TailorTypeGqlPermission, TailorTypePermission } from "./permission.mjs"; import { StandardSchemaV1 } from "@standard-schema/spec"; //#region src/configure/services/tailordb/schema.d.ts type AnyBuilderMethod = any; export type TailorAnyDBField = Omit, "fields"> & { readonly fields: Record; _metadata: DBFieldMetadata; parse: AnyBuilderMethod; readonly typeName: TypeLevelError; description: AnyBuilderMethod; relation: AnyBuilderMethod; index: AnyBuilderMethod; unique: AnyBuilderMethod; vector: AnyBuilderMethod; default: AnyBuilderMethod; hooks: AnyBuilderMethod; validate: AnyBuilderMethod; serial: AnyBuilderMethod; clone: AnyBuilderMethod; }; export type TailorAnyDBType = TailorDBType; type IsAny = 0 extends 1 & T ? true : false; type DBFieldTypeNameMethod = IsAny extends true ? TypeLevelError : TypeLevelError<"typeName cannot be used on TailorDB fields">; type WithDBFieldDescription = Defined & { description: true; }; type WithDBFieldRelation = S extends "oneToOne" | "1-1" ? Defined & { unique: true; index: true; relation: true; } : S extends { type: "oneToOne" | "1-1"; } ? Defined & { unique: true; index: true; relation: true; } : Defined & { index: true; relation: true; }; type WithDBFieldIndex = Defined & { index: true; }; type WithDBFieldUnique = Defined & { unique: true; index: true; }; type WithDBFieldVector = Defined & { vector: true; }; type WithDBFieldHooks = Defined & { hooks: { create: H extends { create: unknown; } ? true : false; update: H extends { update: unknown; } ? true : false; }; serial: false; }; type WithDBFieldDefault = Defined & { default: true; }; type WithDBFieldValidate = Defined & { validate: true; }; type WithDBFieldSerial = Defined & { serial: true; hooks: { create: false; update: false; }; }; type WithDBFieldCloneOptions = IsAny extends true ? Defined : Omit & { array: NewOpt extends { array: true; } ? true : NewOpt extends { array: false; } ? false : Defined["array"]; }; type NonNullableDBFieldOutput = Exclude; type DBFieldScalarOutput = NonNullableDBFieldOutput extends (infer Item)[] ? Item : NonNullableDBFieldOutput; type DBFieldCloneArrayOutput = NewOpt extends { array: true; } ? DBFieldScalarOutput[] : NewOpt extends { array: false; } ? DBFieldScalarOutput : NonNullableDBFieldOutput; type DBFieldCloneOutput = NewOpt extends { optional: true; } ? DBFieldCloneArrayOutput | null : NewOpt extends { optional: false; } ? DBFieldCloneArrayOutput : null extends Output ? DBFieldCloneArrayOutput | null : DBFieldCloneArrayOutput; type DBFieldCloneOptions = Omit & { array?: Defined extends { validate: unknown; } ? Defined["array"] : boolean; }; type InvalidValidatedArrayCloneKeys, K extends keyof Fields, Opt extends FieldOptions> = Opt extends { array: infer ArrayOption; } ? { [P in K]: Fields[P] extends TailorDBField ? Defined extends { validate: unknown; } ? ArrayOption extends Defined["array"] ? never : P : never : never; }[K] : never; type DBFieldsCloneOptionsGuard, K extends keyof Fields, Opt extends FieldOptions> = [InvalidValidatedArrayCloneKeys] extends [never] ? unknown : TypeLevelError<"array cannot be changed on fields with custom validation">; type DefinedDBTypeMetadata = { hooks?: true; validate?: true; features?: true; indexes?: true; files?: true; permission?: true; gqlPermission?: true; description?: true; }; type WithDBTypeMetadata = Defined & Record; type DBTypeDuplicateInputGuard = IsAny extends true ? Input : Defined extends Record ? TypeLevelError : Input; type DBTypeDuplicateRestGuard = IsAny extends true ? Input : Defined extends Record ? [TypeLevelError, ...TypeLevelError[]] : Input; type FileKeyConflictError, User extends object> = Partial> & string, TypeLevelError<"file keys cannot use existing field names">>>; type PluginFieldExtensionFor, Id extends string, IdConfig> = Id extends keyof PluginFieldExtensions ? PluginFieldExtensions[Id] : Record; type PluginFieldExtensionsUnion, Config extends Record> = { [Id in keyof Config & string]: PluginFieldExtensionFor; }[keyof Config & string]; type AllExtensionKeys = Ext extends unknown ? keyof Ext : never; type PluginFieldExtensionShapeError, Config extends Record, Id extends string> = PluginFieldExtensionFor extends Record ? false : true; type PluginFieldConflict, Config extends Record, Id extends string, FileKeys extends string> = [AllExtensionKeys> & (keyof Fields | FileKeys | AllExtensionKeys>>)] extends [never] ? false : true; type PluginConfigExcessProps, Config extends Record, Id extends string> = Record[Id & keyof PluginConfigs]>, never>; type PluginExtendedFields, Config extends Record> = IsAny extends true ? Fields // For `Config = {}`, PluginFieldExtensionsUnion is `never`, and : Fields & UnionToIntersection>; type PluginConfigGuard, Config extends Record, FileKeys extends string> = IsAny extends true ? unknown : { [K in keyof Config]: K extends keyof PluginConfigs ? IsUnion extends true ? TypeLevelError<"plugin config must be a single object literal, not a union — assign the config to a variable first if it comes from a conditional expression"> : PluginFieldExtensionShapeError extends true ? TypeLevelError<"PluginFieldExtensions entry must be a Record"> : PluginFieldConflict extends true ? TypeLevelError<"plugin field extension conflicts with an existing field, a file key declared via .files(), or another plugin's field"> : PluginConfigs[K] & PluginConfigExcessProps : TypeLevelError<"unknown plugin id">; }; type DBFieldDescriptionFn> = (description: string) => TailorDBField, Output, Nested>; type DBFieldRelationFn> = { (config: RelationConfig): TailorDBField, Output, Nested>; (config: S): TailorDBField, Output, Nested>; }; type DBFieldIndexFn> = () => TailorDBField, Output, Nested>; type DBFieldUniqueFn> = () => TailorDBField, Output, Nested>; type DBFieldVectorFn> = () => TailorDBField, Output, Nested>; type DBFieldHooksFn> = >(hooks: H) => TailorDBField, Output, Nested>; type DBFieldValidateFn> = (...validate: FieldValidateInput[]) => TailorDBField, Output, Nested>; type DBFieldSerialFn> = (config: SerialConfig) => TailorDBField, Output, Nested>; type DBFieldDescriptionMethod> = IsAny extends true ? DBFieldDescriptionFn : Defined extends { description: unknown; } ? TypeLevelError<".description() has already been set"> : DBFieldDescriptionFn; type DBFieldRelationMethod> = IsAny extends true ? DBFieldRelationFn : Defined extends { relation: unknown; } ? TypeLevelError<".relation() has already been set"> : DBFieldRelationFn; type DBFieldArrayCheck = A extends true ? TypeLevelError : Ok; type DBFieldIndexMethod> = IsAny extends true ? DBFieldIndexFn : Defined extends { index: unknown; } ? TypeLevelError<".index() has already been set"> : DBFieldArrayCheck, "index cannot be set on array fields">; type DBFieldUniqueMethod> = IsAny extends true ? DBFieldUniqueFn : Defined extends { unique: unknown; } ? TypeLevelError<".unique() has already been set"> : DBFieldArrayCheck, "unique cannot be set on array fields">; type DBFieldVectorMethod> = IsAny extends true ? DBFieldVectorFn : Defined extends { vector: unknown; } ? TypeLevelError<".vector() has already been set"> : Defined extends { type: "string"; array: false; } ? DBFieldVectorFn : TypeLevelError<"vector can only be set on non-array string fields">; type DBFieldHooksMethod> = IsAny extends true ? DBFieldHooksFn : Defined extends { serial: true; hooks: { create: false; update: false; }; } ? TypeLevelError<"hooks cannot be set after serial"> : Defined extends { hooks: unknown; } ? TypeLevelError<".hooks() has already been set"> : Defined extends { type: "nested"; } ? TypeLevelError<"hooks cannot be set on nested type fields"> : DBFieldHooksFn; type DBFieldValidateMethod> = IsAny extends true ? DBFieldValidateFn : Defined extends { validate: unknown; } ? TypeLevelError<".validate() has already been set"> : DBFieldValidateFn; type DBFieldSerialMethod> = IsAny extends true ? DBFieldSerialFn : Defined extends { serial: true; } ? TypeLevelError<".serial() has already been set"> : Defined extends { serial: false; } ? TypeLevelError<"serial cannot be set after hooks"> : IsAny extends true ? Defined extends { type: "integer" | "string"; array: false; } ? DBFieldSerialFn : TypeLevelError<"serial can only be set on non-array integer or string fields"> : null extends Output ? TypeLevelError<"serial can only be set on non-array integer or string fields"> : Defined extends { type: "integer" | "string"; array: false; } ? DBFieldSerialFn : TypeLevelError<"serial can only be set on non-array integer or string fields">; type DBFieldDefaultFn> = (value: Output extends null ? NonNullable : Output) => TailorDBField, Output, Nested>; type DBFieldDefaultMethod> = IsAny extends true ? DBFieldDefaultFn : Defined extends { default: unknown; } ? TypeLevelError<".default() has already been set"> : Defined extends { type: "nested"; } ? TypeLevelError<"default cannot be set on nested type fields"> : Defined extends { serial: true; } ? TypeLevelError<"default cannot be set on serial fields"> : null extends Output ? TypeLevelError<"default cannot be set on optional fields"> : DBFieldDefaultFn; /** * Full TailorDBField interface with builder methods. * Extends the minimal structural interface from types/ with fluent API methods. */ export interface TailorDBField = Record> extends Omit, "fields"> { readonly fields: Nested; _metadata: DBFieldMetadata; /** * Parse and validate a value against this field's validation rules */ parse(args: FieldParseArgs): StandardSchemaV1.Result; /** * typeName is not available on TailorDB fields. * Use typeName on pipeline fields (t.enum / t.object) instead. */ typeName: DBFieldTypeNameMethod; /** * Set a description for the field */ description: DBFieldDescriptionMethod; /** * Define a relation to another table. */ relation: DBFieldRelationMethod; /** * Add an index to the field */ index: DBFieldIndexMethod; /** * Make the field unique (also adds an index) */ unique: DBFieldUniqueMethod; /** * Enable vector search on the field (string type only) */ vector: DBFieldVectorMethod; /** * Set a default value for the field on create. When the field is required, * this makes it optional in the Create input — the default fills in when * no value (or a nullish hook result) is provided. * * For datetime/date/time fields, pass `"now"` to use the operation timestamp. */ default: DBFieldDefaultMethod; /** * Add hooks for create/update operations on this field. */ hooks: DBFieldHooksMethod; /** * Add validation functions to the field. * * Validators receive `{ value, data, user }` and run after hooks and * built-in type validation; they are skipped when built-in validation * fails. For array fields, `value` is the complete array. */ validate: DBFieldValidateMethod; /** * Configure serial/auto-increment behavior */ serial: DBFieldSerialMethod; /** * Clone the field with optional overrides for field options. * The `array` option cannot change on fields with custom validation. */ clone>(options?: NewOpt): TailorDBField, DBFieldCloneOutput, Nested>; } /** * Full TailorDBType interface with builder methods. * Extends the minimal structural interface from types/ with fluent API methods. */ export interface TailorDBType = any, User extends object = InferredAttributes, Defined extends DefinedDBTypeMetadata = any, FileKeys extends string = never> extends TailorDBType$1 { _description?: string; hooks(hook: DBTypeDuplicateInputGuard, ".hooks() has already been set">): TailorDBType, FileKeys>; validate(fn: DBTypeDuplicateInputGuard, ".validate() has already been set">): TailorDBType, FileKeys>; features(features: DBTypeDuplicateInputGuard, ".features() has already been set">): TailorDBType, FileKeys>; indexes(...indexes: DBTypeDuplicateRestGuard>[], ".indexes() has already been set">): TailorDBType, FileKeys>; files(files: DBTypeDuplicateInputGuard & FileKeyConflictError, ".files() has already been set">): TailorDBType, FileKeys | F>; permission>> = TailorTypePermission>>>(permission: DBTypeDuplicateInputGuard): TailorDBType, FileKeys>; gqlPermission = TailorTypeGqlPermission>(permission: DBTypeDuplicateInputGuard): TailorDBType, FileKeys>; description(description: DBTypeDuplicateInputGuard): TailorDBType, FileKeys>; pickFields(keys: K[]): Pick; pickFields(keys: K[], options: Opt & DBFieldsCloneOptionsGuard): { [P in K]: Fields[P] extends TailorDBField ? TailorDBField, DBFieldCloneOutput> : never; }; omitFields(keys: K[]): Omit; plugin>(config: Config & PluginConfigGuard): TailorDBType, User, Defined, FileKeys>; } export type TailorDBInstance = any, User extends object = InferredAttributes, Defined extends DefinedDBTypeMetadata = any, FileKeys extends string = never> = TailorDBType; interface RelationConfig { type: S; toward: { table: T; as?: string; key?: keyof T["fields"] & string; type?: never; } | { /** * @deprecated since 2.6.0 — use `table` instead. codemod: v3/relation-toward-table */ type: T; as?: string; key?: keyof T["fields"] & string; table?: never; }; backward?: string; } type RelationSelfConfig = { type: RelationType; toward: { table: "self"; as?: string; key?: string; type?: never; } | { /** * @deprecated since 2.6.0 — use `table` instead. codemod: v3/relation-toward-table */ type: "self"; as?: string; key?: string; table?: never; }; backward?: string; }; type DBFieldDefined = { type: T; array: Opt extends { array: true; } ? true : false; }; type DBFieldOutput = FieldOutput; type TailorDBFieldInstance = TailorDBField, DBFieldOutput>; /** * Create a UUID field. * @param options - Field configuration options * @returns A UUID field * @example db.uuid() * @example db.uuid({ optional: true }) */ declare function uuid(options?: Opt): TailorDBFieldInstance<"uuid", Opt, string>; /** * Create a string field. * @param options - Field configuration options * @returns A string field * @example db.string() * @example db.string({ optional: true }) */ declare function string(options?: Opt): TailorDBFieldInstance<"string", Opt, string>; /** * Create a boolean field. * Note: The method name is `bool` but creates a `boolean` type field. * @param options - Field configuration options * @returns A boolean field * @example db.bool() * @example db.bool({ optional: true }) */ declare function bool(options?: Opt): TailorDBFieldInstance<"boolean", Opt, boolean>; /** * Create an integer field. * @param options - Field configuration options * @returns An integer field * @example db.int() * @example db.int({ optional: true }) */ declare function int(options?: Opt): TailorDBFieldInstance<"integer", Opt, number>; /** * Create a float (decimal number) field. * @param options - Field configuration options * @returns A float field * @example db.float() * @example db.float({ optional: true }) */ declare function float(options?: Opt): TailorDBFieldInstance<"float", Opt, number>; interface DecimalFieldOptions extends FieldOptions { scale?: number; } /** * Create a decimal field (stored as string for precision). * @param options - Field configuration options including optional scale (0-12) * @returns A decimal field * @example db.decimal() * @example db.decimal({ scale: 2 }) * @example db.decimal({ scale: 2, optional: true }) */ declare function decimal(options?: Opt): TailorDBFieldInstance<"decimal", Opt, string>; /** * Create a date field (date only, no time component). * Format: "yyyy-MM-dd" * @param options - Field configuration options * @returns A date field * @example db.date() */ declare function date(options?: Opt): TailorDBFieldInstance<"date", Opt, string>; /** * Create a datetime field (date and time). * Format: ISO 8601, such as "yyyy-MM-ddTHH:mm:ssZ" or "yyyy-MM-ddTHH:mm:ss+09:00" * @param options - Field configuration options * @returns A datetime field * @example db.datetime() */ declare function datetime(options?: Opt): TailorDBFieldInstance<"datetime", Opt, string | Date>; /** * Create a time field (time only, no date component). * Format: "HH:mm" * @param options - Field configuration options * @returns A time field * @example db.time() */ declare function time(options?: Opt): TailorDBFieldInstance<"time", Opt, string>; /** * Create an enum field with at least one allowed string value. * @param values - Array of allowed string values, or array of `{ value, description }` objects * @param options - Field configuration options * @returns An enum field * @example db.enum(["active", "inactive", "suspended"]) * @example db.enum(["small", "medium", "large"], { optional: true }) */ declare function _enum(values: V, options?: Opt): TailorDBField<{ type: "enum"; array: Opt extends { array: true; } ? true : false; }, FieldOutput, Opt>>; /** * Create a nested object field with sub-fields. * @param fields - Record of nested field definitions * @param options - Field configuration options * @returns A nested object field * @example db.object({ street: db.string(), city: db.string(), zip: db.string() }) * @example db.object({ name: db.string() }, { optional: true }) */ declare function object & ExcludeNestedDBFields & ExcludeHookedDBFields & ExcludeDefaultedDBFields, const Opt extends FieldOptions>(fields: F, options?: Opt): TailorDBField<{ type: "nested"; array: Opt extends { array: true; } ? true : false; }, FieldOutput, Opt>, F>; declare const idField: TailorDBFieldInstance<"uuid", FieldOptions, string>; type idField = typeof idField; type DBTable, Defined extends DefinedDBTypeMetadata = DefinedDBTypeMetadata> = TailorDBInstance<{ id: idField; } & F, InferredAttributes, Defined>; /** * Creates a new database table with the specified fields. * An `id` field (UUID) is automatically added to every table. * @param name - The name of the table, or a tuple of [name, pluralForm] * @param fields - The field definitions for the table * @returns A new TailorDB table instance * @example * export const user = db.table("User", { * name: db.string(), * email: db.string(), * age: db.int({ optional: true }), * role: db.enum(["admin", "member"]), * ...db.fields.timestamps(), * }); * // Always export both the value and type: * export type user = typeof user; */ declare function dbTable>(name: string | [string, string], fields: F): DBTable; /** * Creates a new database table with the specified fields and description. * An `id` field (UUID) is automatically added to every table. * @param name - The name of the table, or a tuple of [name, pluralForm] * @param description - A description of the table * @param fields - The field definitions for the table * @returns A new TailorDB table instance */ declare function dbTable>(name: string | [string, string], description: string, fields: F): DBTable>; type TimestampsUpdatedAtHookFn = UpdateHookFn; /** TailorDB schema builder utilities for defining tables and fields. */ export declare const db: { table: typeof dbTable; uuid: typeof uuid; string: typeof string; bool: typeof bool; int: typeof int; float: typeof float; decimal: typeof decimal; date: typeof date; datetime: typeof datetime; time: typeof time; enum: typeof _enum; object: typeof object; fields: { /** * Creates standard timestamp fields (createdAt, updatedAt) with automatic defaults. * Both fields default to the current time on create. updatedAt is also refreshed on update. * User-specified values are respected when provided (e.g. seeding historical records). * @returns An object with createdAt and updatedAt fields * @example * const model = db.table("Model", { * name: db.string(), * ...db.fields.timestamps(), * }); */ timestamps: () => { createdAt: TailorDBField>>, string | Date, Record>; updatedAt: TailorDBField>, { readonly update: TimestampsUpdatedAtHookFn; }>>, string | Date, Record>; }; }; }; //#endregion