# ActiveRecord API reference

> Look up record, query and field methods, options and return types. Start with the guide for the normal workflow.

- Package: `@db3.ai/app`
- Canonical page: [https://db3.ai/docs/active-record-api](https://db3.ai/docs/active-record-api)
- Markdown: [https://db3.ai/docs/active-record-api.md](https://db3.ai/docs/active-record-api.md)
- Framework source of truth: `packages/app/src/db/README.md`

<a id="using-this-reference"></a>

## Use the guide first

This reference is generated from the package declarations. Use it to check a method signature or option in the four public entry points below.

Import normal model APIs from @db3.ai/app/db. Source-relative imports in a declaration are internal type dependencies, not new supported import paths. The package is still pre-release; availability is explained in the walkthrough.

- [ActiveRecord guide](https://db3.ai/docs/active-record.md)
- [Run a complete note workflow](https://db3.ai/docs/guide-workspace-notes.md)

<a id="record-methods"></a>

## Records, validation and persistence

Use `create()`/new for an unsaved model; `save()` persists. `find()`/`findByPk()` return null when absent; `findOrFail()` throws. Request filling, validation, errors, dirty state, JSON, soft deletion and form metadata are listed below.

`withDb()` provides a scoped connection. `useDb()`, constructor db options, `setDb()` and explicit query connections are lower-level controls; do not thread an optional database parameter through ordinary feature functions.

### @db3.ai/app/db/ActiveRecord

````typescript
import type { Knex } from 'knex';
import { DbRow, DbWriteData, DomFormRenderSpec, FieldError, type FieldClass, type FieldDbValue, type FieldDefinition, type FieldDisplayValue, type FieldMap, type FieldInputMap, type FieldInputValue, FieldType, type FieldValue, FrontendComponentSpec, type DbWriteOptions } from './FieldType.js';
import { ActiveQueryBuilder } from './ActiveQueryBuilder.js';
import { type ActiveRecordSoftDeleteConfig } from './SoftDeletes.js';
import type { FieldBuilder } from './fields/field.js';
import { type ActiveRecordLookup } from './errors.js';
import type { ValidationRules } from '../validation/index.js';
export type { FieldBuilder } from './fields/field.js';
export { RecordNotFoundError } from './errors.js';
export type { ActiveRecordLookup } from './errors.js';
export interface ModelFormOptions {
    name?: string;
    mode?: 'create' | 'edit' | 'search';
    includeGenerated?: boolean;
}
/**
 * Options accepted by the ActiveRecord constructor.
 */
export interface ActiveRecordOptions {
    /** Optional database connection/session for this record instance. */
    db?: Knex;
    /** True when the provided input is a raw database row. */
    fromDb?: boolean;
    /** Whether the record already exists in the database. */
    persisted?: boolean;
}
/**
 * Options for assigning untrusted request/form values to a record.
 */
export interface ActiveRecordRequestOptions {
    /** Whether primary-key fields may be set from request data. Defaults to false. */
    includePrimary?: boolean;
    /** Whether generated fields may be set from request data. Defaults to false. */
    includeGenerated?: boolean;
    /** Explicit fillable fields for this request. Defaults to the model config. */
    fillable?: readonly string[];
    /** Explicit guarded fields for this request. Defaults to the model config. */
    guarded?: readonly string[];
}
export interface ActiveRecordValidationRulesOptions extends ActiveRecordRequestOptions {
    /** Whether hidden fields should be included. Defaults to false. */
    includeHidden?: boolean;
}
export type ActiveRecordRequestMap = Record<string, string>;
export type ActiveRecordConstructor<TRecord extends ActiveRecord = ActiveRecord> = {
    new (input?: Record<string, unknown>, options?: ActiveRecordOptions): TRecord;
};
export type ActiveRecordInstance<TModel extends ActiveRecordConstructor> = InstanceType<TModel>;
/**
 * Static side of an ActiveRecord model class.
 *
 * Each subclass acts as its own schema by defining static `table`, `primaryKey`,
 * and a `fields(field)` method.
 */
export type ActiveRecordClass<TRecord extends ActiveRecord = ActiveRecord> = ActiveRecordConstructor<TRecord> & {
    /** Runtime JavaScript class name. */
    readonly name: string;
    /** Database table name. */
    table: string;
    /** Developer-facing model note for generated schemas and tooling. */
    comment?: string;
    /** Logical primary-key field name. */
    primaryKey: string;
    /** Fields used to render row labels when this model is linked from another model. */
    labelFields?: string[];
    /** Logical fields that request filling may assign. Undefined means all non-guarded fields. */
    requestFillable?: readonly string[];
    /** Logical fields that request filling may not assign. */
    requestGuarded?: readonly string[];
    /** Static field definitions for the model. */
    fields(field: FieldBuilder): FieldInputMap;
    /** Resolved static field definitions for the model. */
    getFields(): FieldMap;
    /** Returns a DomForm render spec composed from the model's FieldTypes. */
    getForm(options?: ModelFormOptions): DomFormRenderSpec;
    /** Returns search filter render specs composed from the model's FieldTypes. */
    getSearchFilters(options?: ModelFormOptions): Record<string, FrontendComponentSpec>;
    /** Looks up one resolved static field definition. */
    getField(fieldName: string): FieldType<any, any, any, any, any>;
    /** Optional default database connection for this model. Falls back to the shared app connection. */
    db?: Knex;
    /** Whether inserts/updates should call `.returning('*')`. */
    returning?: boolean;
    /** Soft-delete setting. True uses the conventional `deletedAt` logical field. */
    softDeletes: ActiveRecordSoftDeleteConfig;
    /** Returns the database connection for this model in the current app/scope. */
    getDb(): Knex;
    /** Runs work with a temporary database connection for all ActiveRecord statics. */
    withDb<TResult>(db: Knex, callback: () => TResult): TResult;
    /** Binds a default database connection to the model class. */
    useDb<TModel extends ActiveRecordConstructor>(this: TModel, db: Knex): TModel;
    /** Creates a new unsaved record bound to the model's current database. */
    create<TModel extends ActiveRecordConstructor>(this: TModel, input?: Record<string, unknown>, options?: Omit<ActiveRecordOptions, 'db'>): ActiveRecordInstance<TModel>;
    /** Starts a field-aware query for the model. */
    query<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /** Starts a query that includes soft-deleted rows. */
    withTrashed<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /** Starts a query that only includes soft-deleted rows. */
    onlyTrashed<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /** Starts a query that excludes soft-deleted rows. */
    withoutTrashed<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /** Convenience helper for `query().where(...)`. */
    where<TModel extends ActiveRecordConstructor>(this: TModel, criteria: Record<string, unknown>): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    where<TModel extends ActiveRecordConstructor>(this: TModel, fieldName: string, value: unknown): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    where<TModel extends ActiveRecordConstructor>(this: TModel, fieldName: string, operator: string, value: unknown): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /** Finds one record by the configured primary key. */
    findByPk<TModel extends ActiveRecordConstructor>(this: TModel, id: unknown, db?: Knex): Promise<ActiveRecordInstance<TModel> | null>;
    /** Finds one record by the configured primary key. */
    find<TModel extends ActiveRecordConstructor>(this: TModel, lookup: ActiveRecordLookup, db?: Knex): Promise<ActiveRecordInstance<TModel> | null>;
    /** Finds one record by the configured primary key or throws an error if not found. */
    findOrFail<TModel extends ActiveRecordConstructor>(this: TModel, lookup: ActiveRecordLookup, db?: Knex): Promise<ActiveRecordInstance<TModel>>;
    /** Hydrates a model instance from a raw database row. */
    fromDb<TModel extends ActiveRecordConstructor>(this: TModel, row: DbRow, db?: Knex): ActiveRecordInstance<TModel>;
    /** Returns validation rules generated from model fields. */
    validationRules(options?: ActiveRecordValidationRulesOptions): ValidationRules;
};
/**
 * Minimal ActiveRecord base class.
 *
 * Subclasses define their table and fields statically. Each instance creates
 * private live field objects, and public model properties proxy through to those
 * fields.
 *
 * Example:
 *
 * ```ts
 * class User extends ActiveRecord {
 *   static table = 'users';
 *   static fields(field: FieldBuilder) {
 *     return {
 *       email: field.email({ required: true }),
 *     };
 *   }
 * }
 *
 * const user = new User();
 * user.email = 'STEVE@EXAMPLE.COM';
 * console.log(user.email); // 'steve@example.com'
 * ```
 */
export declare abstract class ActiveRecord {
    /** Database table name. Override in subclasses. */
    static table: string;
    /** Developer-facing model note for generated schemas and tooling. */
    static comment: string;
    /** Logical primary-key field name. Override if not `id`. */
    static primaryKey: string;
    /** Fields used to render row labels when this model is linked from another model. */
    static labelFields: string[];
    /** Logical fields that request filling may assign. Undefined means all non-guarded fields. */
    static requestFillable?: readonly string[];
    /** Logical fields that request filling may not assign. */
    static requestGuarded: readonly string[];
    /** Static field factory. Override in subclasses. */
    static fields(_field: FieldBuilder): FieldInputMap;
    /** Optional model-level database connection. Falls back to the shared app connection. */
    static db?: Knex;
    /**
     * Whether to call `.returning('*')` after inserts/updates.
     *
     * This is usually desirable for PostgreSQL. Set to `false` for dialects where
     * returning is unsupported or unwanted.
     */
    static returning: boolean;
    /** Soft-delete setting. True uses the conventional `deletedAt` logical field. */
    static softDeletes: ActiveRecordSoftDeleteConfig;
    /** Per-record live fields, keyed by logical field name. */
    private readonly $fields;
    /** Whether the record currently represents an existing database row. */
    protected $persisted: boolean;
    /** Optional instance-level database connection/session. */
    protected $db?: Knex;
    constructor(input?: Record<string, unknown>, options?: ActiveRecordOptions);
    /**
     * Binds a custom default database connection to the model class.
     *
     * Most models can use the active app connection automatically. For tests,
     * prefer creating an app with the test database. For scoped work such as
     * transactions, use `withDb()`.
     */
    static useDb<TModel extends ActiveRecordConstructor>(this: TModel, db: Knex): TModel;
    /**
     * Returns the database connection for the current ActiveRecord operation.
     */
    static getDb(): Knex;
    /**
     * Runs work with a temporary database connection for all ActiveRecord statics.
     */
    static withDb<TResult>(db: Knex, callback: () => TResult): TResult;
    /**
     * Creates a new unsaved record bound to this model's current database.
     */
    static create<TModel extends ActiveRecordConstructor>(this: TModel, input?: Record<string, unknown>, options?: Omit<ActiveRecordOptions, 'db'>): ActiveRecordInstance<TModel>;
    /**
     * Resolves the model's static field factory with the framework field helper.
     */
    static getFields<TRecord extends ActiveRecord>(this: ActiveRecordClass<TRecord>): FieldMap;
    /**
     * Returns a DomForm render spec composed from this model's FieldTypes.
     */
    static getForm<TRecord extends ActiveRecord>(this: ActiveRecordClass<TRecord>, options?: ModelFormOptions): DomFormRenderSpec;
    /**
     * Returns search filter render specs composed from this model's FieldTypes.
     */
    static getSearchFilters<TRecord extends ActiveRecord>(this: ActiveRecordClass<TRecord>, options?: ModelFormOptions): Record<string, FrontendComponentSpec>;
    /**
     * Looks up one resolved field definition by logical field name.
     */
    static getField<TRecord extends ActiveRecord>(this: ActiveRecordClass<TRecord>, fieldName: string): FieldType<any, any, any, any, any>;
    /**
     * Starts a field-aware query for this model.
     */
    static query<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /**
     * Starts a query that includes soft-deleted rows.
     */
    static withTrashed<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /**
     * Starts a query that only includes soft-deleted rows.
     */
    static onlyTrashed<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /**
     * Starts a query that excludes soft-deleted rows.
     */
    static withoutTrashed<TModel extends ActiveRecordConstructor>(this: TModel, db?: Knex): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /**
     * Convenience helper for `Model.query().where(...)`.
     */
    static where<TModel extends ActiveRecordConstructor>(this: TModel, criteria: Record<string, unknown>): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    static where<TModel extends ActiveRecordConstructor>(this: TModel, fieldName: string, value: unknown): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    static where<TModel extends ActiveRecordConstructor>(this: TModel, fieldName: string, operator: string, value: unknown): ActiveQueryBuilder<ActiveRecordInstance<TModel>>;
    /**
     * Finds one record by the configured primary key.
     */
    static findByPk<TModel extends ActiveRecordConstructor>(this: TModel, id: unknown, db?: Knex): Promise<ActiveRecordInstance<TModel> | null>;
    /**
     * Finds one record by the configured primary key or field criteria.
     */
    static find<TModel extends ActiveRecordConstructor>(this: TModel, lookup: ActiveRecordLookup, db?: Knex): Promise<ActiveRecordInstance<TModel> | null>;
    /**
     * Finds one record by the configured primary key or field criteria.
     *
     * Throws a `RecordNotFoundError` if no matching row exists.
     */
    static findOrFail<TModel extends ActiveRecordConstructor>(this: TModel, lookup: ActiveRecordLookup, db?: Knex): Promise<ActiveRecordInstance<TModel>>;
    private static queryForLookup;
    /**
     * Hydrates a model instance from a raw database row.
     */
    static fromDb<TModel extends ActiveRecordConstructor>(this: TModel, row: DbRow, db?: Knex): ActiveRecordInstance<TModel>;
    /**
     * Returns Laravel-style validation rules generated from this model's fields.
     */
    static validationRules<TRecord extends ActiveRecord>(this: ActiveRecordClass<TRecord>, options?: ActiveRecordValidationRulesOptions): ValidationRules;
    /**
     * Assigns app/input values by logical field name.
     *
     * Unknown keys are ignored. Use `set(fieldName, value)` if you want an error
     * for unknown fields.
     */
    assign(input: Record<string, unknown>): this;
    /**
     * Assigns request/form values using logical model field names.
     */
    assignFromRequest(input: unknown, options?: ActiveRecordRequestOptions): this;
    /**
     * Fills this record from request/form values using logical model field names.
     *
     * Unknown keys are ignored. Primary/generated/guarded fields are skipped by
     * default, and model/request fillable config controls what may be assigned.
     */
    setFromRequest(input: unknown, options?: ActiveRecordRequestOptions): this;
    /**
     * Fills this record from request/form values using a request-key to model-field map.
     */
    setFromRequestWithMap(input: unknown, dataToFieldMap: ActiveRecordRequestMap, options?: ActiveRecordRequestOptions): this;
    /**
     * Dynamically sets a field by logical name.
     *
     * Useful for runtime/database-stored schemas where TypeScript cannot know the
     * field names at compile time.
     */
    set(fieldName: string, value: unknown): this;
    /**
     * Dynamically gets a field by logical name.
     */
    get(fieldName: string): unknown;
    /**
     * Dynamically binds this record instance to a database connection/session.
     */
    setDb(db: Knex): this;
    /**
     * Returns true if the model has the given logical field.
     */
    hasField(fieldName: string): boolean;
    /**
     * Returns the bound runtime field for framework-level hydration helpers.
     */
    getBoundField(fieldName: string): FieldType<any, any, any, any, any>;
    /**
     * Validates fields and stores field errors on each field state.
     */
    validate(options?: {
        onlyDirty?: boolean;
    }): Promise<boolean>;
    /**
     * Clears all current validation errors.
     */
    clearErrors(): void;
    /**
     * Returns true if any field currently has validation errors.
     */
    hasErrors(): boolean;
    /**
     * Returns all field errors on this record.
     */
    getErrors(): FieldError[];
    /**
     * Returns current validation errors for one field.
     */
    getFieldErrors(fieldName: string): FieldError[];
    /**
     * Returns database insert/update data for the record.
     *
     * This calls every field's `getDataForDb()` method. This is where passwords
     * are hashed, JSON fields are stringified, link fields produce foreign keys,
     * and compound fields can return multiple columns.
     */
    getDataForDb(options?: Partial<DbWriteOptions>): Promise<DbWriteData>;
    /**
     * Inserts or updates this record.
     *
     * Validation runs before any SQL is executed. On validation failure this throws
     * `RecordValidationError` containing all field errors.
     */
    save(): Promise<this>;
    /**
     * Deletes the current database row.
     *
     * Models with `softDeletes` enabled update their delete timestamp instead of
     * physically removing the row.
     */
    delete(db?: Knex): Promise<number>;
    /**
     * Physically deletes the current database row.
     */
    forceDelete(db?: Knex): Promise<number>;
    /**
     * Restores the current soft-deleted database row.
     */
    restore(db?: Knex): Promise<number>;
    /**
     * Returns true when this soft-deletable record has been trashed.
     */
    trashed(): boolean;
    /**
     * Returns hydrated backend values keyed by logical field name.
     */
    toAppData(): Record<string, unknown>;
    /**
     * Serialises this record using each field's display value.
     */
    toDisplayData(): Record<string, unknown>;
    /**
     * JSON transport alias for display data.
     */
    toJSON(): Record<string, unknown>;
    /**
     * Returns true if this record was loaded from or saved to the database.
     */
    isPersisted(): boolean;
    /**
     * Returns whether one field or any field has unsaved in-memory changes.
     *
     * @param fieldName - Optional logical field name to inspect.
     * @returns True when the selected field scope contains unsaved changes.
     */
    isDirty(fieldName?: string): boolean;
    /**
     * Protected field getter used by generated accessors and `get()`.
     */
    protected $get(fieldName: string): unknown;
    /**
     * Protected field setter used by generated accessors and `set()`.
     */
    protected $set(fieldName: string, value: unknown): void;
    /**
     * Hydrates all fields from a raw database row.
     */
    protected $hydrateFromDb(row: DbRow): void;
    /**
     * Marks all fields as clean after a successful save/hydration.
     */
    protected $markClean(): void;
    /**
     * Returns a database where-clause object for the primary key.
     */
    protected $primaryKeyWhere(): Record<string, unknown>;
    /**
     * Returns one of this record's live field objects.
     */
    protected $field(fieldName: string): FieldType<any, any, any, any, any>;
    /**
     * Soft deletes the current database row.
     */
    private softDelete;
    /**
     * Mirrors soft-delete timestamp writes into this record's live field state.
     */
    private $setSoftDeleteFieldValues;
    /**
     * Returns the static model class for this instance.
     */
    private $model;
    private $canFillFromRequest;
    /**
     * Defines an instance getter/setter for a configured field.
     */
    private $installAccessor;
    /**
     * Checks whether a model class owns a custom accessor for a field.
     *
     * Explicit model accessors may wrap the underlying field through `$get`
     * and `$set` when a domain value needs a stable model-owned interface.
     *
     * @param fieldName - Logical field name being installed.
     * @returns True when a subclass prototype defines a getter or setter.
     */
    private $hasModelAccessor;
}
type ResolvedFieldInput<TInput> = TInput extends FieldType<any, any, any, any, any> ? TInput : TInput extends FieldClass<infer TField> ? TField : TInput extends FieldDefinition<infer TField> ? TField : never;
type ModelFieldInputs<TModel extends {
    fields(field: FieldBuilder): FieldInputMap;
}> = ReturnType<TModel['fields']>;
export declare namespace ActiveRecord {
    type InferInput<TModel extends {
        fields(field: FieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ModelFieldInputs<TModel>]: FieldInputValue<ResolvedFieldInput<ModelFieldInputs<TModel>[fieldName]>>;
    };
    type InferValue<TModel extends {
        fields(field: FieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ModelFieldInputs<TModel>]: FieldValue<ResolvedFieldInput<ModelFieldInputs<TModel>[fieldName]>>;
    };
    type InferDbRow<TModel extends {
        fields(field: FieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ModelFieldInputs<TModel>]: FieldDbValue<ResolvedFieldInput<ModelFieldInputs<TModel>[fieldName]>>;
    };
    type InferDisplay<TModel extends {
        fields(field: FieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ModelFieldInputs<TModel>]: FieldDisplayValue<ResolvedFieldInput<ModelFieldInputs<TModel>[fieldName]>>;
    };
}
````

<a id="query-methods"></a>

## Queries, filters and results

The builder accepts logical field names. It covers field selection, filters, vector similarity, ordering, bounded reads, counts and deletion. `toKnex()` exposes the underlying query for advanced work; the application then owns raw result handling and SQL-level choices.

### @db3.ai/app/db/ActiveQueryBuilder

```typescript
import type { Knex } from 'knex';
import type { ActiveRecord, ActiveRecordClass } from './ActiveRecord.js';
export interface VectorSimilarityOptions {
    /** SQL result alias used for the computed vector distance. Defaults to `distance`. */
    as?: string;
    /** Optional maximum vector distance for filtering candidate rows. */
    maxDistance?: number;
    /** Whether to order rows by closest distance. Defaults to ascending distance. */
    orderBy?: 'asc' | 'desc' | false;
}
/**
 * Field-aware query builder that wraps Knex.
 *
 * Add wrapper methods as you need them. `toKnex()` is the escape hatch for raw
 * Knex operations.
 */
export declare class ActiveQueryBuilder<TRecord extends ActiveRecord> {
    private readonly Model;
    private readonly db;
    private readonly qb;
    private readonly includedFields;
    private readonly includedRelations;
    private selectedFields;
    private softDeleteScope;
    constructor(Model: ActiveRecordClass<TRecord>, db: Knex);
    /**
     * Includes soft-deleted rows in query results and write operations.
     */
    withTrashed(): this;
    /**
     * Restricts the query to soft-deleted rows only.
     */
    onlyTrashed(): this;
    /**
     * Restricts the query to rows that have not been soft deleted.
     */
    withoutTrashed(): this;
    /**
     * Includes an opt-in field that normal fetches omit by default.
     */
    withField(fieldName: string): this;
    /**
     * Eager-loads a link field and serializes it as nested model JSON.
     *
     * The relation name may be the logical link field name, the target model table
     * name, or the target model class name. Prefer the field name when a model has
     * more than one link to the same table.
     */
    with(relationName: string): this;
    /**
     * Restricts hydrated query results to the requested logical model fields.
     *
     * This is intended for bounded read models and polling endpoints that should
     * not load large model columns they do not render.
     *
     * @param fieldNames - Logical model field names to select.
     * @returns This query builder.
     *
     * @example
     * const pages = await WebsitePage
     * 	.where('website', websiteId)
     * 	.select('analyzeStatus', 'analyzeData')
     * 	.all();
     */
    select(...fieldNames: string[]): this;
    /**
     * Adds field-aware equality conditions from an object.
     */
    where(criteria: Record<string, unknown>): this;
    /**
     * Adds a field-aware `where field = value` condition.
     */
    where(fieldName: string, value: unknown): this;
    /**
     * Adds a field-aware `where field operator value` condition.
     */
    where(fieldName: string, operator: string, value: unknown): this;
    /**
     * Adds a primary-key equality condition.
     */
    wherePk(id: unknown): this;
    /**
     * Adds a field-aware `where in (...)` condition.
     */
    whereIn(fieldName: string, values: unknown[]): this;
    /**
     * Adds a field-aware `where column is null` condition.
     */
    whereNull(fieldName: string): this;
    /**
     * Adds a field-aware `where column is not null` condition.
     */
    whereNotNull(fieldName: string): this;
    /**
     * Adds a raw where clause.
     *
     * Prefer field-aware methods where possible. Use parameter bindings to avoid
     * SQL injection when using raw SQL.
     */
    whereRaw(sql: string, bindings?: readonly unknown[]): this;
    /**
     * Adds a dialect-aware vector similarity projection, optional distance filter,
     * and closest-first ordering for a vector field.
     *
     * @param fieldName - Logical vector field name.
     * @param vector - Query vector to compare against the stored field.
     * @param options - Projection alias, optional distance threshold, and ordering.
     * @returns This query builder.
     *
     * @example
     * WebsiteEmbedding
     * 	.query()
     * 	.where('website', websiteId)
     * 	.whereVectorSimilarTo('embedding', queryVector)
     * 	.limit(10)
     * 	.toKnex()
     */
    whereVectorSimilarTo(fieldName: string, vector: readonly number[], options?: VectorSimilarityOptions): this;
    /**
     * Returns whether the active database dialect can run vector similarity search.
     *
     * @returns True when `whereVectorSimilarTo()` can build SQL for this connection.
     */
    supportsVectorSimilaritySearch(): boolean;
    /**
     * Returns a model-visible message for unsupported vector similarity dialects.
     *
     * @returns Readable unsupported-dialect message.
     */
    vectorSimilarityUnsupportedMessage(): string;
    /**
     * Adds field-aware ordering.
     */
    orderBy(fieldName: string, direction?: 'asc' | 'desc'): this;
    /**
     * Limits the number of returned records.
     */
    limit(count: number): this;
    /**
     * Offsets returned records.
     */
    offset(count: number): this;
    /**
     * Escape hatch for raw database column names.
     *
     * This bypasses field conversion and validation. Use it for low-level cases,
     * not normal application queries.
     */
    whereColumn(column: string, value: unknown): this;
    whereColumn(column: string, operator: string, value: unknown): this;
    /**
     * Executes the query and returns the first hydrated record, or null.
     */
    first(): Promise<TRecord | null>;
    /**
     * Executes the query and returns the first hydrated record.
     *
     * @returns First matching record.
     * @throws {RecordNotFoundError} When the query has no matching rows.
     *
     * @example
     * const user = await User
     * 	.where('email', email)
     * 	.firstOrFail();
     */
    firstOrFail(): Promise<TRecord>;
    /**
     * Executes the query and returns hydrated records.
     */
    all(): Promise<TRecord[]>;
    /**
     * Counts matching records without hydrating or transferring model rows.
     *
     * @param fieldName - Optional logical field whose non-null values should be counted.
     * @returns Number of matching records or non-null field values.
     *
     * @example
     * const keywordCount = await Keywords
     * 	.where('website', websiteId)
     * 	.count();
     */
    count(fieldName?: string): Promise<number>;
    /**
     * Updates matching rows using field-aware assignment/conversion.
     *
     * This does not load records before updating them.
     */
    patch(input: Record<string, unknown>): Promise<number>;
    /**
     * Deletes matching rows, using soft deletes when the model opts in.
     */
    delete(): Promise<number>;
    /**
     * Physically deletes matching rows, bypassing soft delete behavior.
     */
    forceDelete(): Promise<number>;
    /**
     * Restores matching soft-deleted rows by clearing their delete timestamp.
     */
    restore(): Promise<number>;
    /**
     * Returns a scoped clone of the underlying Knex query builder.
     *
     * After calling this, you are outside the ActiveRecord hydration layer. Raw
     * Knex results will not automatically become model instances.
     */
    toKnex(): Knex.QueryBuilder;
    /**
     * Looks up a field by logical model field name.
     */
    private getField;
    /**
     * Looks up a field and requires it to be a native vector field.
     *
     * @param fieldName - Logical model field name.
     * @returns Native vector field instance.
     */
    private getVectorField;
    /**
     * Builds a dialect-aware vector distance expression for a vector field.
     *
     * @param field - Vector field being compared.
     * @param vector - Query vector to compare against.
     * @returns SQL expression and bindings for the active dialect.
     */
    private vectorDistanceSql;
    /**
     * Returns the supported vector-search dialect name for this query connection.
     *
     * @returns Supported dialect name, or null when not supported.
     */
    private vectorDistanceDialect;
    /**
     * Returns a model-table-qualified database column name for field-aware clauses.
     *
     * @param field - Model field or metadata whose storage column should be referenced.
     * @returns Column qualified with the ActiveRecord model table.
     */
    private qualifiedColumn;
    /**
     * Looks up a requested relation and requires it to resolve to one link field.
     */
    private getRelationField;
    /**
     * Loads included link records in batches and attaches them to each record.
     */
    private loadIncludedRelations;
    /**
     * Loads one included link relation for all hydrated records.
     */
    private loadIncludedRelation;
    /**
     * Attaches loaded relation records to the bound link fields.
     */
    private attachLoadedRelation;
    /**
     * Returns table-qualified columns for fields included in model hydration.
     */
    private selectedColumns;
    /**
     * Returns true when a field should be included in hydrated query results.
     */
    private shouldSelectField;
    /**
     * Applies the current soft-delete scope to a Knex query clone.
     */
    private applySoftDeleteScope;
}
```

<a id="projections"></a>

## Joined and computed read shapes

`ActiveProjection` converts SQL rows through reusable fields without pretending a joined result is a writable table record. Import it from `@db3.ai/app/db`. Your query owns aliases and scope; the projection owns conversion and output.

### @db3.ai/app/db/ActiveProjection

```typescript
import { DbRow, FieldConfig, type FieldClass, type FieldDbValue, type FieldDefinition, type FieldDisplayValue, type FieldInputMap, type FieldInputValue, type FieldMap, FieldType, type FieldValue } from './FieldType.js';
import type { ActiveRecordClass } from './ActiveRecord.js';
import { type FieldBuilder } from './fields/field.js';
export interface ProjectionSourceFieldOptions {
    /** Row key used when a query aliases the source column. */
    alias?: string;
    /** Explicit row key. Defaults to `alias`, then the source field's DB column. */
    column?: string;
    /** Projection-only default used when the row omits the projected column. */
    default?: FieldConfig['default'];
}
export interface ProjectionFromModelOptions {
    /** Optional logical fields to include from the source model. Defaults to all fields. */
    fields?: readonly string[];
    /** Optional logical fields to omit from the source model. */
    except?: readonly string[];
    /** Prefix for projected logical field names. */
    prefix?: string;
    /** Per-field aliases used by the query row. */
    aliases?: Record<string, string>;
    /** Per-field projection defaults. */
    defaults?: Record<string, FieldConfig['default']>;
}
export interface ProjectionFieldBuilder extends FieldBuilder {
    from<TModel extends {
        fields(field: FieldBuilder): FieldInputMap;
    } & ActiveRecordClass, TFieldName extends keyof ModelFieldInputs<TModel> & string>(Model: TModel, fieldName: TFieldName, options?: ProjectionSourceFieldOptions): ResolvedFieldInput<ModelFieldInputs<TModel>[TFieldName]>;
    fromModel<TModel extends ActiveRecordClass>(Model: TModel, options?: ProjectionFromModelOptions): FieldInputMap;
}
export type ActiveProjectionConstructor<TProjection extends ActiveProjection = ActiveProjection> = {
    new (row?: DbRow): TProjection;
};
export type ActiveProjectionClass<TProjection extends ActiveProjection = ActiveProjection> = ActiveProjectionConstructor<TProjection> & {
    readonly name: string;
    table: string;
    primaryKey: string;
    fields(field: ProjectionFieldBuilder): FieldInputMap;
    getFields(): FieldMap;
    fromDb<TClass extends ActiveProjectionConstructor>(this: TClass, row: DbRow): InstanceType<TClass>;
    fromDbRows<TClass extends ActiveProjectionConstructor>(this: TClass, rows: readonly DbRow[]): InstanceType<TClass>[];
};
export declare abstract class ActiveProjection {
    static table: string;
    static primaryKey: string;
    static fields(_field: ProjectionFieldBuilder): FieldInputMap;
    private readonly $fields;
    constructor(row?: DbRow);
    static getFields<TProjection extends ActiveProjection>(this: ActiveProjectionClass<TProjection>): FieldMap;
    static fromDb<TClass extends ActiveProjectionConstructor>(this: TClass, row: DbRow): InstanceType<TClass>;
    static fromDbRows<TClass extends ActiveProjectionConstructor>(this: TClass, rows: readonly DbRow[]): InstanceType<TClass>[];
    setFromDb(row: DbRow): this;
    get(fieldName: string): unknown;
    toAppData(): Record<string, unknown>;
    toDisplayData(): Record<string, unknown>;
    toJSON(): Record<string, unknown>;
    protected $field(fieldName: string): FieldType<any, any, any, any, any>;
    private $projection;
    private $installAccessor;
}
export declare const projectionField: ProjectionFieldBuilder;
type ResolvedFieldInput<TInput> = TInput extends FieldType<any, any, any, any, any> ? TInput : TInput extends FieldClass<infer TField> ? TField : TInput extends FieldDefinition<infer TField> ? TField : never;
type ModelFieldInputs<TModel extends {
    fields(field: FieldBuilder): FieldInputMap;
}> = ReturnType<TModel['fields']>;
type ProjectionFieldInputs<TProjection extends {
    fields(field: ProjectionFieldBuilder): FieldInputMap;
}> = ReturnType<TProjection['fields']>;
export declare namespace ActiveProjection {
    type InferInput<TProjection extends {
        fields(field: ProjectionFieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ProjectionFieldInputs<TProjection>]: FieldInputValue<ResolvedFieldInput<ProjectionFieldInputs<TProjection>[fieldName]>>;
    };
    type InferValue<TProjection extends {
        fields(field: ProjectionFieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ProjectionFieldInputs<TProjection>]: FieldValue<ResolvedFieldInput<ProjectionFieldInputs<TProjection>[fieldName]>>;
    };
    type InferDbRow<TProjection extends {
        fields(field: ProjectionFieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ProjectionFieldInputs<TProjection>]: FieldDbValue<ResolvedFieldInput<ProjectionFieldInputs<TProjection>[fieldName]>>;
    };
    type InferDisplay<TProjection extends {
        fields(field: ProjectionFieldBuilder): FieldInputMap;
    }> = {
        [fieldName in keyof ProjectionFieldInputs<TProjection>]: FieldDisplayValue<ResolvedFieldInput<ProjectionFieldInputs<TProjection>[fieldName]>>;
    };
}
export {};
```

<a id="field-contract"></a>

## Field conversion and extension points

FieldType describes input, backend, database and display values. Use existing fields first. A custom field should override only the parts of that lifecycle which differ, and supply validation and schema metadata for its behaviour.

### @db3.ai/app/db/FieldType

```typescript
import type { Knex } from 'knex';
import type { ValidationRule } from '../validation/index.js';
import type { DatabaseDialect, DatabaseValueOptions } from './dialects/index.js';
/**
 * Generic database row shape returned by the SQL driver.
 */
export type DbRow = Record<string, unknown>;
/**
 * Partial database row used for inserts and updates.
 *
 * A field returns an object instead of a scalar because some fields may map to
 * multiple database columns. For example, a map/location field could return
 * `{ location_lat, location_lng }`.
 */
export type DbWriteData = Record<string, unknown>;
/**
 * A structured validation error attached to a specific model field.
 */
export interface FieldError {
    /** Logical field name on the model, for example `email` or `password`. */
    field: string;
    /** Human-readable error message. */
    message: string;
    /** Stable machine-readable error code, for example `required`. */
    code?: string;
    /** Offending value, where safe to expose. Avoid storing secrets here. */
    value?: unknown;
    /** Extra structured data for UI/API consumers. */
    details?: unknown;
}
/**
 * Error thrown by `ActiveRecord.save()` when one or more fields are invalid.
 */
export declare class RecordValidationError extends Error {
    readonly errors: FieldError[];
    constructor(errors: FieldError[]);
}
export type FieldDefault = null | string | number | boolean | Record<string, unknown> | unknown[];
export type FieldDefaultFactory = () => unknown;
export type GeneratedValue = boolean | 'db' | 'ulid' | 'uuid-v4' | 'now';
export interface FrontendComponentSpec {
    component: string;
    props: Record<string, unknown>;
}
export interface DomFormRenderSpec {
    component: 'DomForm';
    props: Record<string, unknown>;
    children: FrontendComponentSpec[];
}
export interface FieldFrontendConfig {
    component?: string;
    props?: Record<string, unknown>;
    searchComponent?: string;
    searchProps?: Record<string, unknown>;
}
export interface FieldRenderOptions {
    mode?: 'create' | 'edit' | 'search';
}
/**
 * Core configuration shared by all fields.
 *
 * Concrete field types should extend this with their own options.
 */
export interface FieldConfig {
    /** Database column name. Defaults to the model field name. */
    column?: string;
    /** Developer-facing note for generated models and schema tooling. */
    comment?: string;
    /** Whether the field must have a non-empty value. */
    required?: boolean;
    /** Whether the field is the model primary key. */
    primary?: boolean;
    /** Whether the value should be omitted from `toJSON()`. */
    hidden?: boolean;
    /** Whether normal ActiveRecord fetches should include this field's columns. */
    selectedByDefault?: boolean;
    /** Whether the generated database schema should include a unique constraint. */
    unique?: boolean;
    /** Whether the generated database schema should include an index on this field's primary column. */
    index?: boolean;
    /** Optional name for the generated single-column index. */
    indexName?: string;
    /** Additional generated database schema indexes for this field. */
    indexes?: DbIndexSpec[];
    /** Optional human-friendly label for UI/admin/form generation. */
    label?: string;
    /** Static default value or runtime factory. Use static values for serializable config. */
    default?: FieldDefault | FieldDefaultFactory;
    /** Named generation strategy. This is serializable and lets the field/framework decide how to generate the value. */
    generated?: GeneratedValue;
    /** Frontend rendering hints composed by FieldType render helpers. */
    frontend?: FieldFrontendConfig;
}
export type FieldClass<TField extends FieldType<any, any, any, any, any> = FieldType<any, any, any, any, any>> = new (config?: any) => TField;
export interface FieldDefinition<TField extends FieldType<any, any, any, any, any> = FieldType<any, any, any, any, any>> {
    type: FieldClass<TField>;
    config: ConstructorParameters<FieldClass<TField>>[0];
}
export type FieldInput<TField extends FieldType<any, any, any, any, any> = FieldType<any, any, any, any, any>> = FieldClass<TField> | FieldDefinition<TField> | TField;
export type FieldInputMap = Record<string, FieldInput<any>>;
export type FieldMap = Record<string, FieldType<any, any, any, any, any>>;
export type FieldMapFactory = (field: any) => FieldInputMap;
/**
 * Context passed into low-level field methods.
 *
 * Record instances normally use the higher-level field instance API. This
 * context remains for schema/query work and for concrete field internals.
 */
export interface FieldContext {
    /** The model class metadata. */
    model: ModelMetadata;
    /** Database dialect used for schema/value conversion when available. */
    dialect?: DatabaseDialect;
    /** Knex table builder when schema is being applied to the database. */
    table?: Knex.TableBuilder;
    /** Options used when writing columns through `table`. */
    columnWriteOptions?: DbColumnWriteOptions;
    /** The active record instance when available. Query code may omit this. */
    record?: unknown;
    /** Logical field name on the model, for example `email`. */
    fieldName: string;
}
/**
 * Minimal model metadata required by fields.
 *
 * This avoids importing `ActiveRecord` into the field base class and keeps the
 * dependency direction simple.
 */
export interface ModelMetadata {
    /** Database table name. */
    table: string;
    /** Logical primary-key field name. */
    primaryKey: string;
    /** Static field definitions on the model class. */
    fields: FieldMapFactory;
}
/**
 * Options passed when collecting database write data from fields.
 */
export interface DbWriteOptions {
    /** True for insert, false for update. */
    isInsert: boolean;
    /** Whether clean fields should be excluded from the generated row. */
    onlyDirty: boolean;
    /** Database value conversion context for driver-specific field storage. */
    valueOptions?: DatabaseValueOptions;
}
/**
 * Basic state used by most one-column value fields.
 */
export interface BasicFieldState<TValue = unknown> {
    /** Current app-memory value. */
    value: TValue;
    /** Value originally loaded from the database or initial default. */
    originalValue: TValue;
    /** Whether the current value differs from the original value. */
    dirty: boolean;
    /** Validation errors for this field on this record. */
    errors: FieldError[];
}
/**
 * Database column description produced by a field's `getDbSchema()`.
 *
 * The `type` string comes from the active dialect and is applied directly by
 * `Database` via Knex `specificType`.
 */
export interface DbColumnSpec {
    /** Database column name. */
    name: string;
    /** Database column type, e.g. `varchar(255)`, `char(26)`, `json`, or `longtext`. */
    type: string;
    /** Whether null is allowed. */
    nullable?: boolean;
    /** Whether this column is the primary key. */
    primary?: boolean;
    /** Whether this column has a unique constraint. */
    unique?: boolean;
    /** Database default value. */
    default?: unknown;
    /** Database-native column comment where supported, such as MySQL. */
    comment?: string;
}
/**
 * Options for writing a column onto a Knex table builder.
 */
export interface DbColumnWriteOptions {
    alter?: boolean;
    alterNullable?: boolean;
    alterType?: boolean;
    applyDefault?: boolean;
    applyComment?: boolean;
}
/**
 * Writes a column spec onto a Knex table builder.
 */
export declare function writeDbColumn(table: Knex.TableBuilder, column: DbColumnSpec, options?: DbColumnWriteOptions): void;
/**
 * Neutral database index description.
 */
export interface DbIndexSpec {
    /** Columns included in the index. */
    columns: DbIndexColumnSpec[];
    /** Optional index name. */
    name?: string;
    /** Whether the index is unique. */
    unique?: boolean;
    /** Database index kind. Defaults to a normal scalar index. */
    type?: 'normal' | 'vector';
}
export type DbIndexColumnSpec = string | {
    name: string;
    order?: 'asc' | 'desc';
};
export declare function fieldSchemaIndexes(column: string, config: FieldConfig): DbIndexSpec[] | undefined;
/**
 * Neutral foreign-key description.
 */
export interface DbForeignKeySpec {
    /** Local database column. */
    column: string;
    /** Referenced database table. */
    referencesTable: string;
    /** Referenced database column. */
    referencesColumn: string;
    /** Optional ON DELETE action. */
    onDelete?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'NO ACTION';
    /** Optional ON UPDATE action. */
    onUpdate?: 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'NO ACTION';
}
/**
 * Database schema contribution produced by a single field.
 */
export interface DbSchemaPart {
    /** Columns required by this field. */
    columns?: DbColumnSpec[];
    /** Indexes required by this field. */
    indexes?: DbIndexSpec[];
    /** Foreign keys required by this field. */
    foreignKeys?: DbForeignKeySpec[];
}
/**
 * Base class for reusable field behaviour.
 *
 * Static model fields are schema definitions. Each ActiveRecord instance creates
 * private live field objects that own their value, dirty state, errors, field
 * name, and parent record reference.
 *
 * The low-level lifecycle remains:
 *
 * - `createState()` creates per-record storage.
 * - `setValue()` handles input assignment and stores the hydrated backend value.
 * - `getValue()` handles normal property reads.
 * - `validate()` stores field errors.
 * - `getDataForDb()` returns database write data.
 * - `setFromDb()` hydrates state from a database row.
 * - `getDisplayValue()` serializes for frontend/form/API-safe output.
 */
export declare abstract class FieldType<TValue = unknown, TDbValue = TValue, TDisplayValue = TValue, TInput = TValue, TState extends {
    errors: FieldError[];
} = BasicFieldState<TValue>> {
    readonly config: FieldConfig;
    private $fieldName?;
    private $model?;
    private $record?;
    private $state?;
    private $activeContext?;
    constructor(config?: FieldConfig);
    /**
     * Logical field name on the parent record.
     */
    get name(): string;
    /**
     * Logical field name on the parent record/model.
     */
    get fieldName(): string;
    /**
     * Parent model metadata.
     */
    get model(): ModelMetadata;
    /**
     * Parent ActiveRecord instance.
     */
    get record(): unknown;
    required(value?: boolean): this;
    /**
     * Primary database column for this bound field.
     */
    get column(): string;
    /**
     * Current app-memory value for this bound field.
     */
    get value(): TValue;
    set value(input: TInput);
    /**
     * Whether this bound field has changed since hydration/default creation.
     */
    get dirty(): boolean;
    /**
     * Current validation errors for this bound field.
     */
    get errors(): FieldError[];
    /**
     * Clears validation errors for this bound field.
     */
    clearErrors(): void;
    /**
     * Hydrates this bound field from a database row.
     */
    hydrate(row: DbRow): void;
    /**
     * Validates this bound field.
     */
    validateField(): Promise<FieldError[]>;
    /**
     * Returns database write data for this bound field.
     */
    getBoundDataForDb(options: DbWriteOptions): Promise<DbWriteData>;
    /**
     * Returns a frontend/form/API-safe value for this bound field.
     */
    getBoundDisplayValue(): TDisplayValue | undefined;
    /**
     * Converts a query value for this bound field.
     */
    getBoundQueryValue(input: TInput): unknown;
    /**
     * Marks this bound field as clean.
     */
    markBoundClean(): void;
    /**
     * Returns the column for this field blueprint on a model.
     */
    getColumnFor(model: ModelMetadata, fieldName: string): string;
    /**
     * Converts a query value for this field blueprint on a model.
     */
    getQueryValueFor(model: ModelMetadata, fieldName: string, input: TInput): unknown;
    /**
     * Returns schema metadata for this field blueprint on a model.
     */
    getDbSchemaFor(model: ModelMetadata, fieldName: string): DbSchemaPart;
    /**
     * Returns the DomStudio component spec for rendering this field in a form.
     */
    getFormComponent(options?: FieldRenderOptions, ctx?: FieldContext): FrontendComponentSpec;
    /**
     * Returns the DomStudio component spec for rendering this field as a search filter.
     */
    getSearchFilterComponent(options?: FieldRenderOptions, ctx?: FieldContext): FrontendComponentSpec | null;
    /**
     * Returns a form component spec for an unbound model field.
     */
    getFormComponentFor(model: ModelMetadata, fieldName: string, options?: FieldRenderOptions): FrontendComponentSpec;
    /**
     * Returns a search component spec for an unbound model field.
     */
    getSearchFilterComponentFor(model: ModelMetadata, fieldName: string, options?: FieldRenderOptions): FrontendComponentSpec | null;
    /**
     * Returns the primary database column for this field.
     *
     * Compound fields may still return additional columns from `getDataForDb()`.
     */
    getColumn(ctx?: FieldContext): string;
    /**
     * Creates per-record runtime state for this field.
     */
    createState(ctx?: FieldContext): TState;
    /**
     * Handles app-level assignment, e.g. `user.email = 'x@example.com'`.
     *
     * Keep this mostly synchronous. Async work such as hashing should usually
     * happen in `getDataForDb()` during save.
     */
    setValue(state: TState, input: TInput, ctx?: FieldContext): void;
    /**
     * Handles app-level property reads, e.g. `user.email`.
     */
    getValue(state: TState, ctx?: FieldContext): TValue;
    /**
     * Hydrates field state from a raw database row.
     */
    setFromDb(state: TState, row: DbRow, ctx?: FieldContext): void;
    /**
     * Validates the field and stores the resulting errors on the field state.
     */
    validate(state: TState, ctx?: FieldContext): Promise<FieldError[]>;
    /**
     * Returns current validation errors for this field state.
     */
    getErrors(state: TState): FieldError[];
    /**
     * Returns true if this field state currently has validation errors.
     */
    hasErrors(state: TState): boolean;
    /**
     * Returns true if the field has changed since hydration/default creation.
     */
    isDirty(state: TState): boolean;
    /**
     * Marks the state as clean after a successful save or hydration.
     */
    markClean(state: TState): void;
    /**
     * Returns database write data for this field.
     *
     * The default implementation maps one field to one column.
     */
    getDataForDb(state: TState, options: DbWriteOptions): Promise<DbWriteData>;
    getDataForDb(state: TState, ctx: FieldContext, options: DbWriteOptions): Promise<DbWriteData>;
    /**
     * Returns a frontend/form/API-safe value for this field.
     */
    getDisplayValue(state: TState, ctx?: FieldContext): TDisplayValue | undefined;
    /**
     * Alias used by JSON transport. Framework docs call this display data.
     */
    getJsonValue(state: TState, ctx?: FieldContext): TDisplayValue | undefined;
    /**
     * Converts an input query value into its database representation.
     *
     * Query builder methods call this so `where('email', 'STEVE@EXAMPLE.COM')`
     * can compare against the normalized database value.
     */
    getQueryValue(input: TInput, ctx?: FieldContext): unknown;
    /**
     * Returns database schema metadata for dev sync and diff tooling.
     *
     * When `ctx.table` is present the field also writes its column(s) onto that
     * Knex builder using the dialect-owned SQL type string.
     */
    getDbSchema(ctx?: FieldContext): DbSchemaPart;
    /**
     * Returns request/input validation rules for this field.
     */
    getValidationRules(ctx?: FieldContext): ValidationRule[];
    /**
     * Parses app/input assignment into the field's app-memory value.
     */
    protected parse(input: TInput): TValue;
    /**
     * Default form component for this field type.
     */
    protected defaultFormComponent(): string;
    /**
     * Default form props derived from FieldType config.
     */
    protected defaultFormComponentProps(_options: FieldRenderOptions): Record<string, unknown>;
    /**
     * Default search component for this field type.
     */
    protected defaultSearchFilterComponent(): string | null;
    /**
     * Default search props derived from FieldType config.
     */
    protected defaultSearchFilterComponentProps(_options: FieldRenderOptions): Record<string, unknown>;
    protected fieldLabel(): string;
    /**
     * Converts a raw database value into app memory.
     */
    protected fromDbValue(input: TDbValue): TValue;
    /**
     * Converts an app-memory value into database storage form.
     */
    protected toDbValue(input: TValue, _options?: DatabaseValueOptions): TDbValue;
    /**
     * Converts a hydrated backend value into frontend/form display data.
     */
    protected toDisplayValue(input: TValue): TDisplayValue;
    /**
     * Collects validation errors for this field state.
     *
     * Concrete fields should call `super.collectErrors()` then append their own
     * errors.
     */
    protected collectErrors(state: TState): Promise<FieldError[]>;
    /**
     * Tests whether a value should count as empty for required validation.
     */
    protected isEmpty(value: unknown): boolean;
    /**
     * Returns the database schema default implied by the runtime field default.
     */
    protected getDbDefaultValue(): unknown;
    /**
     * Context for this bound field.
     */
    protected get context(): FieldContext;
    /**
     * Dialect for schema generation, falling back to the configured connection.
     */
    protected schemaDialect(): DatabaseDialect;
    /**
     * Returns schema metadata and optionally writes columns onto `ctx.table`.
     */
    protected completeDbSchema(part: DbSchemaPart, ctx?: FieldContext): DbSchemaPart;
    /**
     * State for this bound field.
     */
    protected get state(): TState;
    /**
     * Attaches this field instance to a model without creating record state.
     */
    bindToModel(model: ModelMetadata, fieldName: string): this;
    /**
     * Returns an unbound copy of this field definition.
     */
    clone(): this;
    /**
     * Returns a cloned field definition with config overrides applied.
     */
    withConfig(config: Partial<FieldConfig>): this;
    /**
     * Attaches this field instance to a concrete ActiveRecord instance.
     */
    bindToRecord(record: unknown, fieldName: string): this;
    bindToRecord(model: ModelMetadata, record: unknown, fieldName: string): this;
    protected resolveDbWriteArgs(ctxOrOptions: FieldContext | DbWriteOptions, options?: DbWriteOptions): {
        ctx?: FieldContext;
        options: DbWriteOptions;
    };
    /**
     * We are trying to deprecate this function in favour of using object functions like this.get
     * @param ctx @deprecated this.schemaDialect()
     * @returns
     */
    protected withContext<TResult>(ctx: FieldContext | undefined, callback: () => TResult): TResult;
    private modelFromRecord;
    private requireModel;
    private requireFieldName;
    /**
     * Resolves the configured default value.
     */
    private getDefaultValue;
}
export type FieldValue<TField> = TField extends FieldType<infer TValue, any, any, any, any> ? TValue : never;
export type FieldDbValue<TField> = TField extends FieldType<any, infer TDbValue, any, any, any> ? TDbValue : never;
export type FieldDisplayValue<TField> = TField extends FieldType<any, any, infer TDisplayValue, any, any> ? TDisplayValue : never;
export type FieldInputValue<TField> = TField extends FieldType<any, any, any, infer TInput, any> ? TInput : never;
```

## Related documentation
- [ActiveRecord](https://db3.ai/docs/active-record.md): Define your fields once. Create, validate, query and save records without repeating database conversion in every endpoint.
- [Keep one workspace’s notes separate from another’s](https://db3.ai/docs/guide-workspace-notes.md): Run a small database workflow: create a note, protect ownership, list the right records, reject invalid input and roll back a failed write.

## Guidance for AI tools
Use the documented public import `@db3.ai/app` and its exported types. Prefer the source-backed examples and behavioural outcomes above over invented APIs or source-relative internal imports.
