/// <reference path="../../../adonis-typings/index.d.ts" />
import { Hooks } from '@poppinss/hooks';
import { IocContract } from '@ioc:Adonis/Core/Application';
import { QueryClientContract, TransactionClientContract } from '@ioc:Adonis/Lucid/Database';
import { LucidRow, CacheNode, LucidModel, CherryPick, EventsList, ModelObject, HooksHandler, ModelOptions, ColumnOptions, ComputedOptions, AdapterContract, CherryPickFields, ModelColumnOptions, ModelKeysContract, ModelAssignOptions, ModelAdapterOptions, ModelRelationOptions, ModelRelations, RelationOptions, RelationshipsContract, ThroughRelationOptions, ManyToManyRelationOptions } from '@ioc:Adonis/Lucid/Orm';
import { SnakeCaseNamingStrategy } from '../NamingStrategies/SnakeCase';
import { LazyLoadAggregates } from '../Relations/AggregatesLoader/LazyLoad';
/**
 * Abstract class to define fully fledged data models
 */
export declare class BaseModel implements LucidRow {
    /**
     * The adapter to be used for persisting and fetching data.
     *
     * NOTE: Adapter is a singleton and share among all the models, unless
     * a user wants to swap the adapter for a given model
     */
    static $adapter: AdapterContract;
    /**
     * Naming strategy for model properties
     */
    static namingStrategy: SnakeCaseNamingStrategy;
    /**
     * The container required to resolve hooks
     *
     * NOTE: Container is a singleton and share among all the models, unless
     * a user wants to swap the container for a given model
     */
    static $container: IocContract;
    /**
     * Primary key is required to build relationships across models
     */
    static primaryKey: string;
    /**
     * Whether or not the model has been booted. Booting the model initializes it's
     * static properties. Base models must not be initialized.
     */
    static booted: boolean;
    /**
     * Query scopes defined on the model
     */
    static $queryScopes: any;
    /**
     * A set of properties marked as computed. Computed properties are included in
     * the `toJSON` result, else they behave the same way as any other instance
     * property.
     */
    static $computedDefinitions: Map<string, ComputedOptions>;
    /**
     * Columns makes it easier to define extra props on the model
     * and distinguish them with the attributes to be sent
     * over to the adapter
     */
    static $columnsDefinitions: Map<string, ModelColumnOptions>;
    /**
     * Registered relationships for the given model
     */
    static $relationsDefinitions: Map<string, RelationshipsContract>;
    /**
     * The name of database table. It is auto generated from the model name, unless
     * specified
     */
    static table: string;
    /**
     * Self assign the primary instead of relying on the database to
     * return it back
     */
    static selfAssignPrimaryKey: boolean;
    /**
     * A custom connection to use for queries. The connection defined on
     * query builder is preferred over the model connection
     */
    static connection?: string;
    /**
     * Storing model hooks
     */
    static $hooks: Hooks;
    /**
     * Keys mappings to make the lookups easy
     */
    static $keys: {
        attributesToColumns: ModelKeysContract;
        attributesToSerialized: ModelKeysContract;
        columnsToAttributes: ModelKeysContract;
        columnsToSerialized: ModelKeysContract;
        serializedToColumns: ModelKeysContract;
        serializedToAttributes: ModelKeysContract;
    };
    /**
     * Creates a new model instance with payload and adapter options
     */
    private static newUpWithOptions;
    /**
     * Helper method for `fetchOrNewUpMany`, `fetchOrCreateMany` and `createOrUpdate`
     * many.
     */
    private static newUpIfMissing;
    /**
     * Returns the model query instance for the given model
     */
    static query(options?: ModelAdapterOptions): any;
    /**
     * Create a model instance from the adapter result. The result value must
     * be a valid object, otherwise `null` is returned.
     */
    static $createFromAdapterResult(adapterResult: ModelObject, sideloadAttributes?: ModelObject, options?: ModelAdapterOptions): any | null;
    /**
     * Creates an array of models from the adapter results. The `adapterResults`
     * must be an array with valid Javascript objects.
     *
     * 1. If top level value is not an array, then an empty array is returned.
     * 2. If row is not an object, then it will be ignored.
     */
    static $createMultipleFromAdapterResult<T extends LucidModel>(this: T, adapterResults: ModelObject[], sideloadAttributes?: ModelObject, options?: ModelAdapterOptions): InstanceType<T>[];
    /**
     * Define a new column on the model. This is required, so that
     * we differentiate between plain properties vs model attributes.
     */
    static $addColumn(name: string, options: Partial<ColumnOptions>): ModelColumnOptions;
    /**
     * Returns a boolean telling if column exists on the model
     */
    static $hasColumn(name: string): boolean;
    /**
     * Returns the column for a given name
     */
    static $getColumn(name: string): ModelColumnOptions | undefined;
    /**
     * Adds a computed node
     */
    static $addComputed(name: string, options: Partial<ComputedOptions>): ComputedOptions;
    /**
     * Find if some property is marked as computed
     */
    static $hasComputed(name: string): boolean;
    /**
     * Get computed node
     */
    static $getComputed(name: string): ComputedOptions | undefined;
    /**
     * Register has one relationship
     */
    protected static $addHasOne(name: string, relatedModel: () => LucidModel, options: RelationOptions<ModelRelations>): void;
    /**
     * Register has many relationship
     */
    protected static $addHasMany(name: string, relatedModel: () => LucidModel, options: RelationOptions<ModelRelations>): void;
    /**
     * Register belongs to relationship
     */
    protected static $addBelongsTo(name: string, relatedModel: () => LucidModel, options: RelationOptions<ModelRelations>): void;
    /**
     * Register many to many relationship
     */
    protected static $addManyToMany(name: string, relatedModel: () => LucidModel, options: ManyToManyRelationOptions<ModelRelations>): void;
    /**
     * Register many to many relationship
     */
    protected static $addHasManyThrough(name: string, relatedModel: () => LucidModel, options: ThroughRelationOptions<ModelRelations>): void;
    /**
     * Adds a relationship
     */
    static $addRelation(name: string, type: ModelRelations['__opaque_type'], relatedModel: () => LucidModel, options: ModelRelationOptions): void;
    /**
     * Find if some property is marked as a relation or not
     */
    static $hasRelation(name: any): boolean;
    /**
     * Returns relationship node for a given relation
     */
    static $getRelation(name: any): any;
    /**
     * Define a static property on the model using the inherit or
     * define strategy.
     *
     * Inherit strategy will clone the property from the parent model
     * and will set it on the current model
     */
    static $defineProperty<Model extends LucidModel, Prop extends keyof Model>(this: Model, propertyName: Prop, defaultValue: Model[Prop], strategy: 'inherit' | 'define' | ((value: Model[Prop]) => Model[Prop])): void;
    /**
     * Boot the model
     */
    static boot(): void;
    /**
     * Register before hooks
     */
    static before(event: EventsList, handler: HooksHandler<any, EventsList>): typeof BaseModel;
    /**
     * Register after hooks
     */
    static after(event: EventsList, handler: HooksHandler<any, EventsList>): typeof BaseModel;
    /**
     * Returns a fresh persisted instance of model by applying
     * attributes to the model instance
     */
    static create(values: any, options?: ModelAssignOptions): Promise<any>;
    /**
     * Same as [[BaseModel.create]], but persists multiple instances. The create
     * many call will be wrapped inside a managed transaction for consistency.
     * If required, you can also pass a transaction client and the method
     * will use that instead of create a new one.
     */
    static createMany(values: any, options?: ModelAssignOptions): Promise<any[]>;
    /**
     * Find model instance using the primary key
     */
    static find(value: any, options?: ModelAdapterOptions): Promise<any>;
    /**
     * Find model instance using the primary key
     */
    static findOrFail(value: any, options?: ModelAdapterOptions): Promise<any>;
    /**
     * Find model instance using a key/value pair
     */
    static findBy(key: string, value: any, options?: ModelAdapterOptions): Promise<any>;
    /**
     * Find model instance using a key/value pair
     */
    static findByOrFail(key: string, value: any, options?: ModelAdapterOptions): Promise<any>;
    /**
     * Same as `query().first()`
     */
    static first(options?: ModelAdapterOptions): Promise<any>;
    /**
     * Same as `query().firstOrFail()`
     */
    static firstOrFail(options?: ModelAdapterOptions): Promise<any>;
    /**
     * Find model instance using a key/value pair
     */
    static findMany(value: any[], options?: ModelAdapterOptions): Promise<any>;
    /**
     * Find model instance using a key/value pair or create a
     * new one without persisting it.
     */
    static firstOrNew(searchPayload: any, savePayload?: any, options?: ModelAssignOptions): Promise<any>;
    /**
     * Same as `firstOrNew`, but also persists the newly created model instance.
     */
    static firstOrCreate(searchPayload: any, savePayload?: any, options?: ModelAssignOptions): Promise<any>;
    /**
     * Updates or creates a new row inside the database
     */
    static updateOrCreate(searchPayload: any, updatedPayload: any, options?: ModelAssignOptions): Promise<any>;
    /**
     * Find existing rows or create an in-memory instances of the missing ones.
     */
    static fetchOrNewUpMany(uniqueKeys: any, payload: any, options?: ModelAssignOptions): Promise<any[]>;
    /**
     * Find existing rows or create missing one's. One database call per insert
     * is invoked, so that each insert goes through the lifecycle of model
     * hooks.
     */
    static fetchOrCreateMany(uniqueKeys: any, payload: any, options?: ModelAssignOptions): Promise<any[]>;
    /**
     * Update existing rows or create missing one's. One database call per insert
     * is invoked, so that each insert and update goes through the lifecycle
     * of model hooks.
     */
    static updateOrCreateMany(uniqueKeys: any, payload: any, options?: ModelAssignOptions): Promise<any>;
    /**
     * Returns all rows from the model table
     */
    static all(options?: ModelAdapterOptions): Promise<any>;
    /**
     * Truncate model table
     */
    static truncate(cascade?: boolean): any;
    constructor();
    /**
     * Custom options defined on the model instance that are
     * passed to the adapter
     */
    private modelOptions?;
    /**
     * Reference to transaction that will be used for performing queries on a given
     * model instance.
     */
    private modelTrx?;
    /**
     * The transaction listener listens for the `commit` and `rollback` events and
     * cleansup the `$trx` reference
     */
    private transactionListener;
    /**
     * When `fill` method is called, then we may have a situation where it
     * removed the values which exists in `original` and hence the dirty
     * diff has to do a negative diff as well
     */
    private fillInvoked;
    /**
     * A copy of cached getters
     */
    private cachedGetters;
    /**
     * Find if force updates are enabled
     */
    private forceUpdate;
    /**
     * Raises exception when mutations are performed on a delete model
     */
    private ensureIsntDeleted;
    /**
     * Invoked when performing the insert call. The method initiates
     * all `datetime` columns, if there are not initiated already
     * and `autoCreate` or `autoUpdate` flags are turned on.
     */
    protected initiateAutoCreateColumns(): void;
    /**
     * Invoked when performing the update call. The method initiates
     * all `datetime` columns, if there have `autoUpdate` flag
     * turned on.
     */
    protected initiateAutoUpdateColumns(): void;
    /**
     * Preparing the object to be sent to the adapter. We need
     * to create the object with the property names to be
     * used by the adapter.
     */
    protected prepareForAdapter(attributes: ModelObject): {};
    /**
     * Returns true when the field must be included
     * inside the serialized object.
     */
    private shouldSerializeField;
    /**
     * A type only reference to the columns
     */
    $columns: any;
    /**
     * A copy of attributes that will be sent over to adapter
     */
    $attributes: ModelObject;
    /**
     * Original represents the properties that already has been
     * persisted or loaded by the adapter.
     */
    $original: ModelObject;
    /**
     * Preloaded relationships on the model instance
     */
    $preloaded: {
        [relation: string]: LucidRow | LucidRow[];
    };
    /**
     * Extras are dynamic properties set on the model instance, which
     * are not serialized and neither casted for adapter calls.
     *
     * This is helpful when adapter wants to load some extra data conditionally
     * and that data must not be persisted back the adapter.
     */
    $extras: ModelObject;
    /**
     * Sideloaded are dynamic properties set on the model instance, which
     * are not serialized and neither casted for adapter calls.
     *
     * This is helpful when you want to add dynamic meta data to the model
     * and it's children as well.
     *
     * The difference between [[extras]] and [[sideloaded]] is:
     *
     * - Extras can be different for each model instance
     * - Extras are not shared down the hierarchy (example relationships)
     * - Sideloaded are shared across multiple model instances created via `$createMultipleFromAdapterResult`.
     * - Sideloaded are passed to the relationships as well.
     */
    $sideloaded: ModelObject;
    /**
     * Persisted means the model has been persisted with the adapter. This will
     * also be true, when model instance is created as a result of fetch
     * call from the adapter.
     */
    $isPersisted: boolean;
    /**
     * Once deleted the model instance cannot make calls to the adapter
     */
    $isDeleted: boolean;
    /**
     * `$isLocal` tells if the model instance was created locally vs
     * one generated as a result of fetch call from the adapter.
     */
    $isLocal: boolean;
    /**
     * Returns the value of primary key. The value must be
     * set inside attributes object
     */
    get $primaryKeyValue(): any | undefined;
    /**
     * Opposite of [[this.isPersisted]]
     */
    get $isNew(): boolean;
    /**
     * Returns dirty properties of a model by doing a diff
     * between original values and current attributes
     */
    get $dirty(): any;
    /**
     * Finding if model is dirty with changes or not
     */
    get $isDirty(): boolean;
    /**
     * Returns the transaction
     */
    get $trx(): TransactionClientContract | undefined;
    /**
     * Set the trx to be used by the model to executing queries
     */
    set $trx(trx: TransactionClientContract | undefined);
    /**
     * Get options
     */
    get $options(): ModelOptions | undefined;
    /**
     * Set options
     */
    set $options(options: ModelOptions | undefined);
    /**
     * Set options on the model instance along with transaction
     */
    $setOptionsAndTrx(options?: ModelAdapterOptions): void;
    /**
     * A chainable method to set transaction on the model
     */
    useTransaction(trx: TransactionClientContract): this;
    /**
     * A chainable method to set transaction on the model
     */
    useConnection(connection: string): this;
    /**
     * Set attribute
     */
    $setAttribute(key: string, value: any): void;
    /**
     * Get value of attribute
     */
    $getAttribute(key: string): any;
    /**
     * Returns the attribute value from the cache which was resolved by
     * the mutated by a getter. This is done to avoid re-mutating
     * the same attribute value over and over again.
     */
    $getAttributeFromCache(key: string, callback: CacheNode['getter']): any;
    /**
     * Returns the related model or default value when model is missing
     */
    $getRelated(key: any): any;
    /**
     * A boolean to know if relationship has been preloaded or not
     */
    $hasRelated(key: any): boolean;
    /**
     * Sets the related data on the model instance. The method internally handles
     * `one to one` or `many` relations
     */
    $setRelated(key: any, models: LucidRow | LucidRow[]): void;
    /**
     * Push related adds to the existing related collection
     */
    $pushRelated(key: any, models: LucidRow | LucidRow[]): void;
    /**
     * Merges the object with the model attributes, assuming object keys
     * are coming the database.
     *
     * 1. If key is unknown, it will be added to the `extras` object.
     * 2. If key is defined as a relationship, it will be ignored and one must call `$setRelated`.
     */
    $consumeAdapterResult(adapterResult: ModelObject, sideloadedAttributes?: ModelObject): void;
    /**
     * Sync originals with the attributes. After this `isDirty` will
     * return false
     */
    $hydrateOriginals(): void;
    /**
     * Set bulk attributes on the model instance. Setting relationships via
     * fill isn't allowed, since we disallow setting relationships
     * locally
     */
    fill(values: any, allowExtraProperties?: boolean): this;
    /**
     * Merge bulk attributes with existing attributes.
     *
     * 1. If key is unknown, it will be added to the `extras` object.
     * 2. If key is defined as a relationship, it will be ignored and one must call `$setRelated`.
     */
    merge(values: any, allowExtraProperties?: boolean): this;
    /**
     * Enable force update even when no attributes
     * are dirty
     */
    enableForceUpdate(): this;
    /**
     * Preloads one or more relationships for the current model
     */
    load(relationName: any, callback?: any): Promise<void>;
    /**
     * @deprecated
     */
    preload(relationName: any, callback?: any): Promise<void>;
    /**
     * Lazy load the relationship aggregate value
     */
    loadAggregate(relationName: any, callback?: any): LazyLoadAggregates<this>;
    /**
     * Lazy load the relationship count value
     */
    loadCount(relationName: any, callback?: any): LazyLoadAggregates<this>;
    /**
     * Perform save on the model instance to commit mutations.
     */
    save(): Promise<this>;
    /**
     * Perform delete by issuing a delete request on the adapter
     */
    delete(): Promise<void>;
    /**
     * Serializes model attributes to a plain object
     */
    serializeAttributes(fields?: CherryPickFields, raw?: boolean): ModelObject;
    /**
     * Serializes model compute properties to an object.
     */
    serializeComputed(fields?: CherryPickFields): ModelObject;
    /**
     * Serializes relationships to a plain object. When `raw=true`, it will
     * recurisvely serialize the relationships as well.
     */
    serializeRelations(cherryPick?: CherryPick['relations'], raw?: boolean): ModelObject | {
        [key: string]: LucidRow | LucidRow[];
    };
    /**
     * Converting model to it's JSON representation
     */
    serialize(cherryPick?: CherryPick): any;
    /**
     * Convert model to a plain Javascript object
     */
    toObject(): {
        $extras: ModelObject;
    };
    /**
     * Returns the serialize method output. However, any model can overwrite
     * it to define it's custom serialize output
     */
    toJSON(): any;
    /**
     * Returns the query for `insert`, `update` or `delete` actions.
     * Since the query builder for these actions are not exposed to
     * the end user, this method gives a way to compose queries.
     */
    $getQueryFor(action: 'insert' | 'update' | 'delete' | 'refresh', client: QueryClientContract): any;
    /**
     * Returns an instance of relationship on the given model
     */
    related(relationName: any): any;
    /**
     * Reload/Refresh the model instance
     */
    refresh(): Promise<this>;
}
