import type { AllowIterable, RequiredBy } from '@sequelize/utils';
import type { WhereOptions } from '../abstract-dialect/where-sql-builder-types.js';
import type { AttributeNames, Attributes, BulkCreateOptions, CreateOptions, CreationAttributes, Filterable, FindAttributeOptions, FindOptions, InstanceDestroyOptions, InstanceUpdateOptions, Model, ModelOptions, ModelStatic, Transactionable } from '../model';
import type { Association, AssociationOptions, AssociationScope, ForeignKeyOptions, MultiAssociationAccessors, MultiAssociationOptions, NormalizedAssociationOptions } from './base';
import { MultiAssociation } from './base';
import type { BelongsToAssociation } from './belongs-to.js';
import { HasManyAssociation } from './has-many.js';
import { HasOneAssociation } from './has-one.js';
import type { MaybeForwardedModelStatic } from './helpers';
/**
 * Many-to-many association with a join/through table.
 * See {@link Model.belongsToMany}
 *
 * When the join table has additional attributes, these can be passed in the options object:
 *
 * ```js
 * UserProject = sequelize.define('user_project', {
 *   role: DataTypes.STRING
 * });
 * User.belongsToMany(Project, { through: UserProject });
 * Project.belongsToMany(User, { through: UserProject });
 * // through is required!
 *
 * user.addProject(project, { through: { role: 'manager' }});
 * ```
 *
 * All methods allow you to pass either a persisted instance, its primary key, or a mixture:
 *
 * ```js
 * const project = await Project.create({ id: 11 });
 * await user.addProjects([project, 12]);
 * ```
 *
 * If you want to set several target instances, but with different attributes you have to set the attributes on the instance, using a property with the name of the through model:
 *
 * ```js
 * p1.UserProjects = {
 *   started: true
 * }
 * user.setProjects([p1, p2], { through: { started: false }}) // The default value is false, but p1 overrides that.
 * ```
 *
 * Similarly, when fetching through a join table with custom attributes, these attributes will be available as an object with the name of the through model.
 * ```js
 * const projects = await user.getProjects();
 * const p1 = projects[0];
 * p1.UserProjects.started // Is this project started yet?
 * ```
 *
 * In the API reference below, add the name of the association to the method, e.g. for `User.belongsToMany(Project)` the getter will be `user.getProjects()`.
 */
export declare class BelongsToManyAssociation<SourceModel extends Model = Model, TargetModel extends Model = Model, ThroughModel extends Model = Model, SourceKey extends AttributeNames<SourceModel> = any, TargetKey extends AttributeNames<TargetModel> = any> extends MultiAssociation<SourceModel, TargetModel, string, TargetKey, NormalizedBelongsToManyOptions<SourceKey, TargetKey, ThroughModel>> {
    #private;
    readonly accessors: MultiAssociationAccessors;
    get foreignKey(): string;
    /**
     * The name of the Foreign Key attribute, located on the through table, that points to the Target model.
     *
     * Not to be confused with {@link BelongsToManyAssociation#foreignKey}, which points to the Source model instead.
     */
    get otherKey(): string;
    /**
     * @deprecated use {@link BelongsToManyAssociation#foreignKey}
     */
    get identifier(): string;
    /**
     * The corresponding column name of {@link BelongsToManyAssociation#foreignKey}
     */
    get identifierField(): string;
    /**
     * The corresponding column name of {@link BelongsToManyAssociation#otherKey}
     */
    get foreignIdentifierField(): string;
    /**
     * The name of the Attribute that the {@link foreignKey} fk (located on the Through Model) will reference on the Source model.
     */
    get sourceKey(): SourceKey;
    /**
     * The name of the Column that the {@link foreignKey} fk (located on the Through Table) will reference on the Source model.
     */
    get sourceKeyField(): string;
    /**
     * The name of the Attribute that the {@link otherKey} fk (located on the Through Model) will reference on the Target model.
     */
    get targetKey(): TargetKey;
    /**
     * The name of the Column that the {@link otherKey} fk (located on the Through Table) will reference on the Target model.
     */
    get targetKeyField(): string;
    /**
     * The corresponding association this entity is paired with.
     */
    pairedWith: BelongsToManyAssociation<TargetModel, SourceModel, ThroughModel, TargetKey, SourceKey>;
    readonly fromSourceToThrough: HasManyAssociation<SourceModel, ThroughModel, SourceKey, any>;
    readonly fromSourceToThroughOne: HasOneAssociation<SourceModel, ThroughModel, SourceKey, any>;
    get fromThroughToSource(): BelongsToAssociation<ThroughModel, SourceModel, any, SourceKey>;
    get fromTargetToThrough(): HasManyAssociation<TargetModel, ThroughModel, TargetKey, any>;
    get fromTargetToThroughOne(): HasOneAssociation<TargetModel, ThroughModel, TargetKey, any>;
    get fromThroughToTarget(): BelongsToAssociation<ThroughModel, TargetModel, any, TargetKey>;
    get through(): NormalizedThroughOptions<ThroughModel>;
    get throughModel(): ModelStatic<ThroughModel>;
    constructor(secret: symbol, source: ModelStatic<SourceModel>, target: ModelStatic<TargetModel>, options: NormalizedBelongsToManyOptions<SourceKey, TargetKey, ThroughModel>, pair?: BelongsToManyAssociation<TargetModel, SourceModel, ThroughModel, TargetKey, SourceKey>, parent?: Association<any>);
    static associate<S extends Model, T extends Model, ThroughModel extends Model, SourceKey extends AttributeNames<S>, TargetKey extends AttributeNames<T>>(secret: symbol, source: ModelStatic<S>, target: ModelStatic<T>, options: BelongsToManyOptions<SourceKey, TargetKey, ThroughModel>, pair?: BelongsToManyAssociation<T, S, ThroughModel, TargetKey, SourceKey>, parent?: Association<any>): BelongsToManyAssociation<S, T, ThroughModel, SourceKey, TargetKey>;
    /**
     * Get everything currently associated with this, using an optional where clause.
     *
     * See {@link Model} for a full explanation of options
     *
     * @param instance instance
     * @param options find options
     */
    get(instance: SourceModel, options?: BelongsToManyGetAssociationsMixinOptions<TargetModel>): Promise<TargetModel[]>;
    /**
     * Count everything currently associated with this, using an optional where clause.
     *
     * @param instance instance
     * @param options find options
     */
    count(instance: SourceModel, options?: BelongsToManyCountAssociationsMixinOptions<TargetModel>): Promise<number>;
    /**
     * Check if one or more instance(s) are associated with this. If a list of instances is passed, the function returns true if _all_ instances are associated
     *
     * @param sourceInstance source instance to check for an association with
     * @param targetInstancesOrPks Can be an array of instances or their primary keys
     * @param options Options passed to getAssociations
     */
    has(sourceInstance: SourceModel, targetInstancesOrPks: AllowIterable<TargetModel | Exclude<TargetModel[TargetKey], any[]>>, options?: BelongsToManyHasAssociationMixinOptions<TargetModel>): Promise<boolean>;
    /**
     * Set the associated models by passing an array of instances or their primary keys.
     * Everything that it not in the passed array will be un-associated.
     *
     * @param sourceInstance source instance to associate new instances with
     * @param newInstancesOrPrimaryKeys A single instance or primary key, or a mixed array of persisted instances or primary keys
     * @param options Options passed to `through.findAll`, `bulkCreate`, `update` and `destroy`
     */
    set(sourceInstance: SourceModel, newInstancesOrPrimaryKeys: AllowIterable<TargetModel | Exclude<TargetModel[TargetKey], any[]>>, options?: BelongsToManySetAssociationsMixinOptions<TargetModel>): Promise<void>;
    /**
     * Associate one or several rows with source instance. It will not un-associate any already associated instance
     * that may be missing from `newInstances`.
     *
     * @param sourceInstance source instance to associate new instances with
     * @param newInstancesOrPrimaryKeys A single instance or primary key, or a mixed array of persisted instances or primary keys
     * @param options Options passed to `through.findAll`, `bulkCreate` and `update`
     */
    add(sourceInstance: SourceModel, newInstancesOrPrimaryKeys: AllowIterable<TargetModel | Exclude<TargetModel[TargetKey], any[]>>, options?: BelongsToManyAddAssociationsMixinOptions<TargetModel>): Promise<void>;
    /**
     * Un-associate one or more instance(s).
     *
     * @param sourceInstance instance to un associate instances with
     * @param targetInstanceOrPks Can be an Instance or its primary key, or a mixed array of instances and primary keys
     * @param options Options passed to `through.destroy`
     */
    remove(sourceInstance: SourceModel, targetInstanceOrPks: AllowIterable<TargetModel | Exclude<TargetModel[TargetKey], any[]>>, options?: BelongsToManyRemoveAssociationMixinOptions): Promise<void>;
    /**
     * Create a new instance of the associated model and associate it with this.
     *
     * @param sourceInstance source instance
     * @param values values for target model
     * @param options Options passed to create and add
     */
    create(sourceInstance: SourceModel, values?: CreationAttributes<TargetModel>, options?: BelongsToManyCreateAssociationMixinOptions<TargetModel> | BelongsToManyCreateAssociationMixinOptions<TargetModel>['fields']): Promise<TargetModel>;
}
/**
 * Used for the through table in n:m associations.
 *
 * Used in {@link BelongsToManyOptions.through}
 */
export interface ThroughOptions<ThroughModel extends Model> {
    /**
     * The model used to join both sides of the N:M association.
     * Can be a string if you want the model to be generated by sequelize.
     */
    model: MaybeForwardedModelStatic<ThroughModel> | string;
    /**
     * See {@link ModelOptions.timestamps}
     */
    timestamps?: ModelOptions['timestamps'];
    /**
     * See {@link ModelOptions.paranoid}
     */
    paranoid?: ModelOptions['paranoid'];
    /**
     * A key/value set that will be used for association create and find defaults on the through model.
     * (Remember to add the attributes to the through model)
     */
    scope?: AssociationScope;
    /**
     * If true a unique constraint will be added on the foreign key pair.
     * If set to a string, the generated unique key will use the string as its name.
     * If set to false, no unique constraint will be added.
     * Useful if you want to turn this off and create your own unique constraint when using scopes.
     *
     * This option only works if the model already has a Primary Key,
     * as the unique constraint will not be added if the foreign keys are already part of the composite primary key.
     *
     * @default true
     */
    unique?: boolean | string;
}
/**
 * Attributes for the join table
 */
export interface JoinTableAttributes {
    [attribute: string]: unknown;
}
type NormalizedBelongsToManyOptions<SourceKey extends string, TargetKey extends string, ThroughModel extends Model> = Omit<RequiredBy<BelongsToManyOptions<SourceKey, TargetKey, ThroughModel>, 'throughAssociations'>, 'through' | 'as' | 'hooks' | 'foreignKey' | 'inverse'> & {
    through: NormalizedThroughOptions<ThroughModel>;
    inverse?: Exclude<BelongsToManyOptions<SourceKey, TargetKey, ThroughModel>['inverse'], string>;
} & Pick<NormalizedAssociationOptions<string>, 'as' | 'name' | 'hooks' | 'foreignKey'>;
type NormalizedThroughOptions<ThroughModel extends Model> = Omit<ThroughOptions<ThroughModel>, 'model'> & {
    model: ModelStatic<ThroughModel>;
};
/**
 * Options provided when associating models with belongsToMany relationship.
 *
 * Used by {@link Model.belongsToMany}.
 */
export interface BelongsToManyOptions<SourceKey extends string = string, TargetKey extends string = string, ThroughModel extends Model = Model> extends MultiAssociationOptions<AttributeNames<ThroughModel>> {
    /**
     * The name of the inverse association, or an object for further association setup.
     */
    inverse?: string | undefined | {
        as?: AssociationOptions<string>['as'];
        scope?: MultiAssociationOptions<string>['scope'];
        foreignKeyConstraints?: AssociationOptions<string>['foreignKeyConstraints'];
    };
    /**
     * Should "ON UPDATE", "ON DELETE" and "REFERENCES" constraints be enabled on the foreign key?
     *
     * This only affects the foreign key that points to the source model.
     * to control the one that points to the target model, set the "foreignKeyConstraints" option in {@link BelongsToManyOptions.inverse}.
     */
    foreignKeyConstraints?: boolean;
    /**
     * The name of the table that is used to join source and target in n:m associations. Can also be a
     * Sequelize model if you want to define the junction table yourself and add extra attributes to it.
     */
    through: MaybeForwardedModelStatic<ThroughModel> | string | ThroughOptions<ThroughModel>;
    /**
     * Configures the name of the associations that will be defined between the source model and the through model,
     * as well as between the target model and the through model.
     */
    throughAssociations?: {
        /**
         * The name of the HasMany association going from the Source model to the Through model.
         *
         * By default, the association will be the name of the BelongsToMany association
         * + the name of the inverse BelongsToMany association.
         */
        fromSource?: string | undefined;
        /**
         * The name of the BelongsTo association going from the Through model to the Source model.
         *
         * By default, the association name will be the name of the inverse BelongsToMany association, singularized.
         */
        toSource?: string | undefined;
        /**
         * The name of the HasMany association going from the Target model to the Through model.
         *
         * By default, the association will be the name of the Inverse BelongsToMany association
         * + the name of the BelongsToMany association.
         */
        fromTarget?: string | undefined;
        /**
         * The name of the BelongsTo association going from the Through model to the Target model.
         *
         * By default, the association name will be the name of the parent BelongsToMany association, singularized.
         */
        toTarget?: string | undefined;
    };
    /**
     * The name of the foreign key attribute in the through model (representing the target model) or an object representing
     * the type definition for the other column (see `Sequelize.define` for syntax). When using an object, you
     * can add a `name` property to set the name of the colum. Defaults to the name of target + primary key of
     * target
     */
    otherKey?: AttributeNames<ThroughModel> | ForeignKeyOptions<AttributeNames<ThroughModel>>;
    /**
     * The name of the attribute to use as the key for the association in the source table.
     * Defaults to the primary key attribute of the source model
     */
    sourceKey?: SourceKey;
    /**
     * The name of the attribute to use as the key for the association in the target table.
     * Defaults to the primary key attribute of the target model
     */
    targetKey?: TargetKey;
}
/**
 * The options for the getAssociations mixin of the belongsToMany association.
 *
 * @see BelongsToManyGetAssociationsMixin
 */
export interface BelongsToManyGetAssociationsMixinOptions<T extends Model> extends FindOptions<Attributes<T>> {
    /**
     * A list of the attributes from the join table that you want to select.
     */
    joinTableAttributes?: FindAttributeOptions<Attributes<T>>;
    /**
     * Apply a scope on the related model, or remove its default scope by passing false.
     */
    scope?: string | boolean;
    /**
     * Apply a schema on the related model
     */
    schema?: string;
    schemaDelimiter?: string;
    through?: {
        where?: WhereOptions;
        paranoid?: boolean;
    };
}
/**
 * The getAssociations mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *  declare getRoles: BelongsToManyGetAssociationsMixin<Role>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyGetAssociationsMixin<T extends Model> = (options?: BelongsToManyGetAssociationsMixinOptions<T>) => Promise<T[]>;
/**
 * The options for the setAssociations mixin of the belongsToMany association.
 *
 * @see BelongsToManySetAssociationsMixin
 */
export interface BelongsToManySetAssociationsMixinOptions<TargetModel extends Model> extends FindOptions<Attributes<TargetModel>>, BulkCreateOptions<Attributes<TargetModel>>, InstanceUpdateOptions<Attributes<TargetModel>>, InstanceDestroyOptions {
    /**
     * Additional attributes for the join table.
     */
    through?: JoinTableAttributes;
}
/**
 * The setAssociations mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare setRoles: BelongsToManySetAssociationsMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManySetAssociationsMixin<TModel extends Model, TModelPrimaryKey> = (newAssociations?: Iterable<TModel | TModelPrimaryKey> | null, options?: BelongsToManySetAssociationsMixinOptions<TModel>) => Promise<void>;
/**
 * The options for the addAssociations mixin of the belongsToMany association.
 *
 * @see BelongsToManyAddAssociationsMixin
 */
export interface BelongsToManyAddAssociationsMixinOptions<TModel extends Model> extends FindOptions<Attributes<TModel>>, BulkCreateOptions<Attributes<TModel>>, InstanceUpdateOptions<Attributes<TModel>>, InstanceDestroyOptions {
    through?: JoinTableAttributes;
}
/**
 * The addAssociations mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare addRoles: BelongsToManyAddAssociationsMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyAddAssociationsMixin<T extends Model, TModelPrimaryKey> = (newAssociations?: Iterable<T | TModelPrimaryKey>, options?: BelongsToManyAddAssociationsMixinOptions<T>) => Promise<void>;
/**
 * The options for the addAssociation mixin of the belongsToMany association.
 *
 * @see BelongsToManyAddAssociationMixin
 */
export interface BelongsToManyAddAssociationMixinOptions<T extends Model> extends FindOptions<Attributes<T>>, BulkCreateOptions<Attributes<T>>, InstanceUpdateOptions<Attributes<T>>, InstanceDestroyOptions {
    through?: JoinTableAttributes;
}
/**
 * The addAssociation mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare addRole: BelongsToManyAddAssociationMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyAddAssociationMixin<T extends Model, TModelPrimaryKey> = (newAssociation?: T | TModelPrimaryKey, options?: BelongsToManyAddAssociationMixinOptions<T>) => Promise<void>;
/**
 * The options for the createAssociation mixin of the belongsToMany association.
 *
 * @see BelongsToManyCreateAssociationMixin
 */
export interface BelongsToManyCreateAssociationMixinOptions<T extends Model> extends CreateOptions<Attributes<T>> {
    through?: JoinTableAttributes;
}
/**
 * The createAssociation mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare createRole: BelongsToManyCreateAssociationMixin<Role>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyCreateAssociationMixin<T extends Model> = (values?: CreationAttributes<T>, options?: BelongsToManyCreateAssociationMixinOptions<T>) => Promise<T>;
/**
 * The options for the removeAssociation mixin of the belongsToMany association.
 *
 * @see BelongsToManyRemoveAssociationMixin
 */
export interface BelongsToManyRemoveAssociationMixinOptions extends InstanceDestroyOptions {
}
/**
 * The removeAssociation mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare removeRole: BelongsToManyRemoveAssociationMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyRemoveAssociationMixin<TModel, TModelPrimaryKey> = (oldAssociated?: TModel | TModelPrimaryKey, options?: BelongsToManyRemoveAssociationMixinOptions) => Promise<void>;
/**
 * The options for the removeAssociations mixin of the belongsToMany association.
 *
 * @see BelongsToManyRemoveAssociationsMixin
 */
export interface BelongsToManyRemoveAssociationsMixinOptions extends InstanceDestroyOptions, InstanceDestroyOptions {
}
/**
 * The removeAssociations mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare removeRoles: BelongsToManyRemoveAssociationsMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyRemoveAssociationsMixin<TModel, TModelPrimaryKey> = (associationsToRemove?: Iterable<TModel | TModelPrimaryKey>, options?: BelongsToManyRemoveAssociationsMixinOptions) => Promise<void>;
/**
 * The options for the hasAssociation mixin of the belongsToMany association.
 *
 * @see BelongsToManyHasAssociationMixin
 */
export interface BelongsToManyHasAssociationMixinOptions<T extends Model> extends BelongsToManyGetAssociationsMixinOptions<T> {
}
/**
 * The hasAssociation mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare hasRole: BelongsToManyHasAssociationMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyHasAssociationMixin<TModel extends Model, TModelPrimaryKey> = (target: TModel | TModelPrimaryKey, options?: BelongsToManyHasAssociationMixinOptions<TModel>) => Promise<boolean>;
/**
 * The options for the hasAssociations mixin of the belongsToMany association.
 *
 * @see BelongsToManyHasAssociationsMixin
 */
export interface BelongsToManyHasAssociationsMixinOptions<T extends Model> extends BelongsToManyGetAssociationsMixinOptions<T> {
}
/**
 * The removeAssociations mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare hasRoles: BelongsToManyHasAssociationsMixin<Role, Role['id']>;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyHasAssociationsMixin<TModel extends Model, TModelPrimaryKey> = (targets: Iterable<TModel | TModelPrimaryKey>, options?: BelongsToManyHasAssociationsMixinOptions<TModel>) => Promise<boolean>;
/**
 * The options for the countAssociations mixin of the belongsToMany association.
 *
 * @see BelongsToManyCountAssociationsMixin
 */
export interface BelongsToManyCountAssociationsMixinOptions<T extends Model> extends Transactionable, Filterable<Attributes<T>> {
    /**
     * Apply a scope on the related model, or remove its default scope by passing false.
     */
    scope?: string | boolean;
}
/**
 * The countAssociations mixin applied to models with belongsToMany.
 * An example of usage is as follows:
 *
 * ```typescript
 * class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
 *   declare countRoles: Sequelize.BelongsToManyCountAssociationsMixin;
 * }
 *
 * User.belongsToMany(Role, { through: UserRole });
 * ```
 *
 * @see Model.belongsToMany
 */
export type BelongsToManyCountAssociationsMixin<T extends Model> = (options?: BelongsToManyCountAssociationsMixinOptions<T>) => Promise<number>;
export {};
