import type { Knex } from 'knex';
import { BelongsToRelation, HasManyRelation, HasOneRelation } from './relation.js';
type Row = Record<string, unknown>;
/**
 * Paginated query result returned by {@link Model.paginate}.
 *
 * @typeParam T - Model instance type contained in `data`.
 */
interface PaginatedResult<T extends Model> {
    /** Model instances for the current page. */
    data: ModelCollection<T>;
    /** Total rows matching the scoped query across all pages. */
    total: number;
    /** Requested page size. */
    per_page: number;
    /** Current page number (1-based). */
    current_page: number;
    /** Next page number, or `null` on the last page. */
    next_page: number | null;
    /** Previous page number, or `null` on the first page. */
    prev_page: number | null;
    /** Total number of pages. */
    last_page: number;
}
/**
 * Array subclass returned by {@link Model.all} and {@link Model.paginate}.
 *
 * Extends `Array` so it remains compatible with array operations while adding
 * {@link ModelCollection.toArray | toArray()} for API serialisation.
 *
 * @typeParam T - Model instance type stored in the collection.
 */
declare class ModelCollection<T extends Model> extends Array<T> {
    /**
     * Serialises every model in the collection to a plain object.
     *
     * @returns Array of serialised records (respects each model's `hidden` fields).
     */
    toArray(): Row[];
}
/**
 * ActiveRecord-style base model backed by Knex.
 *
 * Extend this class for each database table. Table names are inferred from the
 * class name unless overridden via `override table`. Use static methods for
 * queries and instance methods for row-level persistence.
 *
 * @example
 * ```ts
 * class User extends Model {
 *   override fillable = ['name', 'email', 'password']
 *   override hidden = ['password']
 * }
 *
 * const user = await User.create({ name: 'Jane', email: 'jane@example.com' })
 * const page = await User.orderBy('name').paginate(10)
 * ```
 */
declare class Model {
    #private;
    [key: string]: any;
    /**
     * Resolved database table name for this model class.
     *
     * Honours subclass `override table` declarations.
     */
    static get currentTable(): string;
    /**
     * Active scoped Knex query built by `where()`, `orderBy()`, and other chain methods.
     *
     * Consumed and reset by terminal methods such as `first()`, `all()`, and `paginate()`.
     */
    static currentQuery: Knex.QueryBuilder<Row, Row[]> | undefined;
    /**
     * Resolves the database table name for this model class.
     *
     * Instantiates the subclass to read its `table` property, so explicit
     * `override table` values are honoured on static query paths.
     *
     * @returns Resolved table name.
     */
    static resolveTable(this: typeof Model): string;
    /**
     * Returns the active scoped query, initialising one against the model table when absent.
     *
     * Used internally by chain methods like `orderBy()` when called without a prior `where()`.
     */
    static ensureCurrentQuery(this: typeof Model): Knex.QueryBuilder<Row, Row[]>;
    /** Attributes allowed through {@link Model.save | save()} mass assignment. */
    fillable: string[];
    /** Attributes excluded from {@link Model.toArray | toArray()} and stripped after reads. */
    hidden: string[];
    /** Snake_case singular name derived from the class name (used for default foreign keys). */
    modelName: string;
    /** Database table this model maps to. Override when inference does not match your schema. */
    table: string;
    /** Primary key value, set after insert or load. */
    id?: number;
    /**
     * Creates a model instance from a database row or plain object.
     *
     * @param properties - Initial attribute values.
     */
    constructor(properties?: Row);
    /**
     * Inserts the current model using {@link Model.fillable | fillable} attributes and reloads it.
     *
     * @returns This instance with database-assigned fields (including `id`) populated.
     */
    save(): Promise<this>;
    /**
     * Updates the current row by primary key and returns a refreshed model instance.
     *
     * @param properties - Columns and values to update.
     * @returns Refreshed instance with updated attributes.
     * @throws When the instance has no `id`.
     */
    update(properties: Row): Promise<this>;
    /**
     * Deletes the current row by primary key.
     *
     * @throws When the instance has no `id`.
     */
    delete(): Promise<void>;
    /**
     * Bulk-updates rows in the model table.
     *
     * When preceded by {@link Model.where | where()}, only scoped rows are updated.
     * The query scope is reset after execution.
     *
     * @param properties - Columns and values to update.
     * @returns Number of rows updated.
     */
    static update(properties: Row): Promise<number | undefined>;
    /**
     * Bulk-deletes rows in the model table.
     *
     * When preceded by {@link Model.where | where()}, only scoped rows are deleted.
     * The query scope is reset after execution.
     *
     * @returns Number of rows deleted.
     */
    static destroy(): Promise<number | undefined>;
    /**
     * Finds a single model by primary key.
     *
     * @param id - Primary key value.
     * @param columns - Columns to select (default `'*'`).
     * @returns Model instance, or `null` when not found. Preserves the derived class type.
     */
    static find<T extends typeof Model>(this: T, id: number | string, columns?: string | string[]): Promise<InstanceType<T> | null>;
    /**
     * Finds a model by primary key or throws when it does not exist.
     *
     * @param id - Primary key value.
     * @param columns - Columns to select (default `'*'`).
     * @returns Model instance. Preserves the derived class type.
     * @throws When no row matches the given id.
     */
    static findOrFail<T extends typeof Model>(this: T, id: number | string, columns?: string | string[]): Promise<InstanceType<T>>;
    /**
     * Inserts a row and returns the created model instance.
     *
     * @param properties - Column values to insert.
     * @returns Created model with `hidden` fields stripped. Preserves the derived class type.
     */
    static create<T extends typeof Model>(this: T, properties: Row): Promise<InstanceType<T>>;
    /**
     * Inserts multiple rows sequentially and returns created model instances.
     *
     * @param properties - Array of column value objects to insert.
     * @returns Created model instances in insertion order.
     */
    static createMany<T extends typeof Model>(this: T, properties: Row[]): Promise<InstanceType<T>[]>;
    /**
     * Returns the first row matching `attributes`, or creates one with merged values.
     *
     * @param attributes - Lookup conditions.
     * @param values - Additional values used only when creating a new row.
     * @returns Existing or newly created model instance.
     */
    static firstOrCreate<T extends typeof Model>(this: T, attributes: Row, values?: Row): Promise<InstanceType<T>>;
    /**
     * Starts a scoped query with a `where` clause.
     *
     * Chain further constraints (`orderBy`, `limit`, …) then call a terminal method
     * (`first`, `all`, `paginate`, `count`, `update`, `destroy`).
     *
     * @param conditions - Equality conditions passed to Knex `where`.
     * @returns Model constructor for chaining.
     */
    static where<T extends typeof Model>(this: T, conditions?: Row): T;
    /**
     * Appends an `orderBy` clause to the current scoped query.
     *
     * @param column - Column to sort by.
     * @param direction - Sort direction (`'asc'` or `'desc'`). Defaults to `'asc'`.
     * @returns Model constructor for chaining.
     */
    static orderBy<T extends typeof Model>(this: T, column: string, direction?: 'asc' | 'desc'): T;
    /**
     * Appends a `limit` clause to the current scoped query.
     *
     * @param count - Maximum number of rows to return.
     * @returns Model constructor for chaining.
     */
    static limit<T extends typeof Model>(this: T, count: number): T;
    /**
     * Appends an `offset` clause to the current scoped query.
     *
     * @param count - Number of rows to skip (commonly paired with {@link Model.limit | limit()}).
     * @returns Model constructor for chaining.
     */
    static offset<T extends typeof Model>(this: T, count: number): T;
    /**
     * Returns the first model matching the current scope.
     *
     * When no scope is active, returns the first row in the table.
     * The query scope is reset after execution.
     *
     * @param columns - Columns to select (default `'*'`).
     * @returns First matching model, or `null` when none found.
     */
    static first<T extends typeof Model>(this: T, columns?: string | string[]): Promise<InstanceType<T> | null>;
    /**
     * Returns all models matching the current scope.
     *
     * When no scope is active, returns every row in the table.
     * The query scope is reset after execution.
     *
     * @param columns - Columns to select (default `'*'`).
     * @returns {@link ModelCollection} of matching models.
     */
    static all<T extends typeof Model>(this: T, columns?: string | string[]): Promise<ModelCollection<InstanceType<T>>>;
    /**
     * Returns a paginated result set for the current scope.
     *
     * Runs a count query and a data query against the scoped builder.
     * The query scope is reset after execution.
     *
     * @param perPage - Items per page (default `15`).
     * @param page - Page number, 1-based (default `1`).
     * @param columns - Columns to select (default `'*'`).
     * @returns Paginated data and metadata.
     *
     * @example
     * ```ts
     * const result = await Post.where({ published: true }).orderBy('created_at', 'desc').paginate(10, 2)
     * ```
     */
    static paginate<T extends typeof Model>(this: T, perPage?: number, page?: number, columns?: string | string[]): Promise<PaginatedResult<InstanceType<T>>>;
    /**
     * Returns a row count for the current scope.
     *
     * When no scope is active, counts all rows in the table.
     * The query scope is reset after execution.
     *
     * @param column - Column to count (default `'*'` for all rows).
     * @returns Matching row count.
     */
    static count(this: typeof Model, column?: string): Promise<number>;
    /**
     * Serialises the model to a plain object for API responses.
     *
     * Excludes ORM internals (`fillable`, `hidden`, `modelName`, `table`) and
     * any attributes listed in {@link Model.hidden | hidden}.
     *
     * @returns Plain data object safe to return from HTTP handlers.
     */
    toArray(): Row;
    /**
     * Removes internal and hidden fields from a model instance in place.
     *
     * @param model - Model object to strip.
     * @param keepInternalState - When `true`, retains `fillable` and `hidden` keys.
     * @returns The same object reference with keys removed.
     */
    stripColumns<T extends Record<string, unknown>>(model: T, keepInternalState?: boolean): T;
}
interface Model {
    /**
     * Defines a one-to-one relationship to another model.
     *
     * @param Related - Related model class constructor.
     * @param localKey - Parent key value (defaults to `this.id`).
     * @param foreignKey - Foreign key column on the related table (defaults to `{modelName}_id`).
     * @returns Lazy {@link HasOneRelation} — await directly or chain `where()` before executing.
     *
     * @example
     * ```ts
     * const profile = await user.profile()
     * const active = await user.profile().where({ active: true }).first()
     * ```
     */
    hasOne<T extends typeof Model>(Related: T, localKey?: number | string, foreignKey?: string): HasOneRelation<InstanceType<T>>;
    /**
     * Defines a one-to-many relationship to another model.
     *
     * @param Related - Related model class constructor.
     * @param localKey - Parent key value (defaults to `this.id`).
     * @param foreignKey - Foreign key column on the related table (defaults to `{modelName}_id`).
     * @returns Lazy {@link HasManyRelation} — await for all rows or call `.get()` / `.first()`.
     *
     * @example
     * ```ts
     * const posts = await user.posts()
     * const drafts = await user.posts().where({ status: 'draft' }).get()
     * ```
     */
    hasMany<T extends typeof Model>(Related: T, localKey?: number | string, foreignKey?: string): HasManyRelation<InstanceType<T>>;
    /**
     * Defines an inverse belongs-to relationship to a parent model.
     *
     * @param Related - Parent model class constructor.
     * @param foreignKey - Foreign key column on this model (defaults to `{relatedModelName}_id`).
     * @param ownerKey - Primary key column on the parent table (defaults to `'id'`).
     * @returns Lazy {@link BelongsToRelation} — await directly or chain `where()` before executing.
     *
     * @example
     * ```ts
     * const author = await post.author()
     * ```
     */
    belongsTo<T extends typeof Model>(Related: T, foreignKey?: string, ownerKey?: string): BelongsToRelation<InstanceType<T>>;
}
export { Model, ModelCollection };
export type { PaginatedResult };
export { HasOneRelation, HasManyRelation, BelongsToRelation, Relation } from './relation.js';
export { DB, getDB, configure, createKnexConfig, configureDatabase, setMigrationConfig, getMigrationConfig, makeMigration, migrateLatest, migrateRollback, migrateCurrentVersion, migrateList, } from './config.js';
