不要怂,就是干,撸起袖子干!

Commit 871157bc by Harry Yu Committed by GitHub

feat(types): added optional stricter typing for Model attributes (#12405)

1 parent e36212c8
......@@ -19,7 +19,21 @@ Example of a minimal TypeScript project:
import { Sequelize, Model, DataTypes, BuildOptions } from 'sequelize';
import { HasManyGetAssociationsMixin, HasManyAddAssociationMixin, HasManyHasAssociationMixin, Association, HasManyCountAssociationsMixin, HasManyCreateAssociationMixin } from 'sequelize';
class User extends Model {
// These are the minimum attributes needed to create a User
interface UserCreationAttributes {
name: string;
preferredName: string | null;
}
// These are all the attributes in the User model
interface UserAttributes extends UserCreationAttributes {
id: number;
}
// You can choose to omit the `UserAttributes` and `UserCreationAttributes`
// generic types to simplify your types. This will come at the cost of making
// typechecking slightly less strict.
class User extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
public id!: number; // Note that the `null assertion` `!` is required in strict mode.
public name!: string;
public preferredName!: string | null; // for nullable fields
......@@ -49,7 +63,16 @@ class User extends Model {
const sequelize = new Sequelize('mysql://root:asd123@localhost:3306/mydb');
class Project extends Model {
interface ProjectAttributes {
ownerId: number;
name: string;
}
interface ProjectAttributes extends ProjectCreationAttributes {
id: number;
}
class Project extends Model<ProjectAttributes, ProjectCreationAttributes> implements ProjectAttributes {
public id!: number;
public ownerId!: number;
public name!: string;
......@@ -58,7 +81,12 @@ class Project extends Model {
public readonly updatedAt!: Date;
}
class Address extends Model {
interface AddressAttributes {
userId: number;
address: string;
}
class Address extends Model<AddressAttributes> implements AddressAttributes {
public userId!: number;
public address!: string;
......@@ -149,21 +177,45 @@ async function stuff() {
## Usage of `sequelize.define`
TypeScript doesn't know how to generate a `class` definition when we use the `sequelize.define` method to define a Model. Therefore, we need to do some manual work and declare an interface and a type, and eventually cast the result of `.define` to the _static_ type.
In Sequelize versions before v5, the default way of defining a model involved using `sequelize.define`. It's still possible to define models with that, and you can also add typings to these models using interfaces.
```ts
// We need to declare an interface for our model that is basically what our class would be
interface MyModel extends Model {
// We recommend you declare an interface for the attributes, for stricter typechecking
interface MyModelAttributes {
readonly id: number;
name: string;
}
interface MyModelCreationAttributes extends Optional<MyModelAttributes, 'id'> {}
// We need to declare an interface for our model that is basically what our class would be
interface MyModel extends Model<MyModelAttributes, MyModelCreationAttributes>, MyModelAttributes {}
const MyDefineModel = sequelize.define<MyModel>('MyDefineModel', {
id: {
primaryKey: true,
type: DataTypes.INTEGER.UNSIGNED,
}
});
async function stuffTwo() {
const myModel = await MyDefineModel.findByPk(1, {
rejectOnEmpty: true,
});
console.log(myModel.id);
}
```
If you're comfortable with somewhat less strict typing for the attributes on a model, you can save some code by defining the Instance to just extend `Model` without any attributes in the generic types.
// Need to declare the static model so `findOne` etc. use correct types.
type MyModelStatic = typeof Model & {
new (values?: object, options?: BuildOptions): MyModel;
```ts
// We need to declare an interface for our model that is basically what our class would be
interface MyModel extends Model {
readonly id: number;
name: string;
}
// TS can't derive a proper class definition from a `.define` call, therefor we need to cast here.
const MyDefineModel = <MyModelStatic>sequelize.define('MyDefineModel', {
const MyDefineModel = sequelize.define<MyModel>('MyDefineModel', {
id: {
primaryKey: true,
type: DataTypes.INTEGER.UNSIGNED,
......
......@@ -17,3 +17,9 @@ export { BaseError as Error } from './lib/errors';
export { useInflection } from './lib/utils';
export { Utils, QueryTypes, Op, TableHints, IndexHints, DataTypes, Deferrable };
export { Validator as validator } from './lib/utils/validator-extras';
/**
* Type helper for making certain fields of an object optional. This is helpful
* for creating the `CreationAttributes` from your `Attributes` for a Model.
*/
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
......@@ -104,7 +104,7 @@ export class BelongsToMany<S extends Model = Model, T extends Model = Model> ext
* The options for the getAssociations mixin of the belongsToMany association.
* @see BelongsToManyGetAssociationsMixin
*/
export interface BelongsToManyGetAssociationsMixinOptions extends FindOptions {
export interface BelongsToManyGetAssociationsMixinOptions extends FindOptions<any> {
/**
* A list of the attributes from the join table that you want to select.
*/
......@@ -149,9 +149,9 @@ export type BelongsToManyGetAssociationsMixin<TModel> = (
* @see BelongsToManySetAssociationsMixin
*/
export interface BelongsToManySetAssociationsMixinOptions
extends FindOptions,
BulkCreateOptions,
InstanceUpdateOptions,
extends FindOptions<any>,
BulkCreateOptions<any>,
InstanceUpdateOptions<any>,
InstanceDestroyOptions {
through?: JoinTableAttributes;
}
......@@ -191,9 +191,9 @@ export type BelongsToManySetAssociationsMixin<TModel, TModelPrimaryKey> = (
* @see BelongsToManyAddAssociationsMixin
*/
export interface BelongsToManyAddAssociationsMixinOptions
extends FindOptions,
BulkCreateOptions,
InstanceUpdateOptions,
extends FindOptions<any>,
BulkCreateOptions<any>,
InstanceUpdateOptions<any>,
InstanceDestroyOptions {
through?: JoinTableAttributes;
}
......@@ -233,9 +233,9 @@ export type BelongsToManyAddAssociationsMixin<TModel, TModelPrimaryKey> = (
* @see BelongsToManyAddAssociationMixin
*/
export interface BelongsToManyAddAssociationMixinOptions
extends FindOptions,
BulkCreateOptions,
InstanceUpdateOptions,
extends FindOptions<any>,
BulkCreateOptions<any>,
InstanceUpdateOptions<any>,
InstanceDestroyOptions {
through?: JoinTableAttributes;
}
......@@ -274,7 +274,7 @@ export type BelongsToManyAddAssociationMixin<TModel, TModelPrimaryKey> = (
* The options for the createAssociation mixin of the belongsToMany association.
* @see BelongsToManyCreateAssociationMixin
*/
export interface BelongsToManyCreateAssociationMixinOptions extends CreateOptions {
export interface BelongsToManyCreateAssociationMixinOptions extends CreateOptions<any> {
through?: JoinTableAttributes;
}
/**
......@@ -455,7 +455,7 @@ export type BelongsToManyHasAssociationsMixin<TModel, TModelPrimaryKey> = (
* The options for the countAssociations mixin of the belongsToMany association.
* @see BelongsToManyCountAssociationsMixin
*/
export interface BelongsToManyCountAssociationsMixinOptions extends Transactionable, Filterable {
export interface BelongsToManyCountAssociationsMixinOptions extends Transactionable, Filterable<any> {
/**
* Apply a scope on the related model, or remove its default scope by passing false.
*/
......
......@@ -30,7 +30,7 @@ export class BelongsTo<S extends Model = Model, T extends Model = Model> extends
* The options for the getAssociation mixin of the belongsTo association.
* @see BelongsToGetAssociationMixin
*/
export interface BelongsToGetAssociationMixinOptions extends FindOptions {
export interface BelongsToGetAssociationMixinOptions extends FindOptions<any> {
/**
* Apply a scope on the related model, or remove its default scope by passing false.
*/
......@@ -61,7 +61,7 @@ export type BelongsToGetAssociationMixin<TModel> = (options?: BelongsToGetAssoci
* The options for the setAssociation mixin of the belongsTo association.
* @see BelongsToSetAssociationMixin
*/
export interface BelongsToSetAssociationMixinOptions extends SaveOptions {
export interface BelongsToSetAssociationMixinOptions extends SaveOptions<any> {
/**
* Skip saving this after setting the foreign key if false.
*/
......@@ -95,7 +95,8 @@ export type BelongsToSetAssociationMixin<TModel, TPrimaryKey> = (
* The options for the createAssociation mixin of the belongsTo association.
* @see BelongsToCreateAssociationMixin
*/
export interface BelongsToCreateAssociationMixinOptions extends CreateOptions, BelongsToSetAssociationMixinOptions {}
export interface BelongsToCreateAssociationMixinOptions
extends CreateOptions<any>, BelongsToSetAssociationMixinOptions {}
/**
* The createAssociation mixin applied to models with belongsTo.
......
......@@ -36,7 +36,7 @@ export class HasMany<S extends Model = Model, T extends Model = Model> extends A
* The options for the getAssociations mixin of the hasMany association.
* @see HasManyGetAssociationsMixin
*/
export interface HasManyGetAssociationsMixinOptions extends FindOptions {
export interface HasManyGetAssociationsMixinOptions extends FindOptions<any> {
/**
* Apply a scope on the related model, or remove its default scope by passing false.
*/
......@@ -74,7 +74,7 @@ export type HasManyGetAssociationsMixin<TModel> = (options?: HasManyGetAssociati
* The options for the setAssociations mixin of the hasMany association.
* @see HasManySetAssociationsMixin
*/
export interface HasManySetAssociationsMixinOptions extends FindOptions, InstanceUpdateOptions {}
export interface HasManySetAssociationsMixinOptions extends FindOptions<any>, InstanceUpdateOptions<any> {}
/**
* The setAssociations mixin applied to models with hasMany.
......@@ -110,7 +110,7 @@ export type HasManySetAssociationsMixin<TModel, TModelPrimaryKey> = (
* The options for the addAssociations mixin of the hasMany association.
* @see HasManyAddAssociationsMixin
*/
export interface HasManyAddAssociationsMixinOptions extends InstanceUpdateOptions {}
export interface HasManyAddAssociationsMixinOptions extends InstanceUpdateOptions<any> {}
/**
* The addAssociations mixin applied to models with hasMany.
......@@ -146,7 +146,7 @@ export type HasManyAddAssociationsMixin<TModel, TModelPrimaryKey> = (
* The options for the addAssociation mixin of the hasMany association.
* @see HasManyAddAssociationMixin
*/
export interface HasManyAddAssociationMixinOptions extends InstanceUpdateOptions {}
export interface HasManyAddAssociationMixinOptions extends InstanceUpdateOptions<any> {}
/**
* The addAssociation mixin applied to models with hasMany.
......@@ -182,7 +182,7 @@ export type HasManyAddAssociationMixin<TModel, TModelPrimaryKey> = (
* The options for the createAssociation mixin of the hasMany association.
* @see HasManyCreateAssociationMixin
*/
export interface HasManyCreateAssociationMixinOptions extends CreateOptions {}
export interface HasManyCreateAssociationMixinOptions extends CreateOptions<any> {}
/**
* The createAssociation mixin applied to models with hasMany.
......@@ -218,7 +218,7 @@ export type HasManyCreateAssociationMixin<TModel> = (
* The options for the removeAssociation mixin of the hasMany association.
* @see HasManyRemoveAssociationMixin
*/
export interface HasManyRemoveAssociationMixinOptions extends InstanceUpdateOptions {}
export interface HasManyRemoveAssociationMixinOptions extends InstanceUpdateOptions<any> {}
/**
* The removeAssociation mixin applied to models with hasMany.
......@@ -254,7 +254,7 @@ export type HasManyRemoveAssociationMixin<TModel, TModelPrimaryKey> = (
* The options for the removeAssociations mixin of the hasMany association.
* @see HasManyRemoveAssociationsMixin
*/
export interface HasManyRemoveAssociationsMixinOptions extends InstanceUpdateOptions {}
export interface HasManyRemoveAssociationsMixinOptions extends InstanceUpdateOptions<any> {}
/**
* The removeAssociations mixin applied to models with hasMany.
......@@ -362,7 +362,7 @@ export type HasManyHasAssociationsMixin<TModel, TModelPrimaryKey> = (
* The options for the countAssociations mixin of the hasMany association.
* @see HasManyCountAssociationsMixin
*/
export interface HasManyCountAssociationsMixinOptions extends Transactionable, Filterable {
export interface HasManyCountAssociationsMixinOptions extends Transactionable, Filterable<any> {
/**
* Apply a scope on the related model, or remove its default scope by passing false.
*/
......
......@@ -28,7 +28,7 @@ export class HasOne<S extends Model = Model, T extends Model = Model> extends As
* The options for the getAssociation mixin of the hasOne association.
* @see HasOneGetAssociationMixin
*/
export interface HasOneGetAssociationMixinOptions extends FindOptions {
export interface HasOneGetAssociationMixinOptions extends FindOptions<any> {
/**
* Apply a scope on the related model, or remove its default scope by passing false.
*/
......@@ -59,7 +59,7 @@ export type HasOneGetAssociationMixin<TModel> = (options?: HasOneGetAssociationM
* The options for the setAssociation mixin of the hasOne association.
* @see HasOneSetAssociationMixin
*/
export interface HasOneSetAssociationMixinOptions extends HasOneGetAssociationMixinOptions, SaveOptions {
export interface HasOneSetAssociationMixinOptions extends HasOneGetAssociationMixinOptions, SaveOptions<any> {
/**
* Skip saving this after setting the foreign key if false.
*/
......@@ -93,7 +93,7 @@ export type HasOneSetAssociationMixin<TModel, TModelPrimaryKey> = (
* The options for the createAssociation mixin of the hasOne association.
* @see HasOneCreateAssociationMixin
*/
export interface HasOneCreateAssociationMixinOptions extends HasOneSetAssociationMixinOptions, CreateOptions {}
export interface HasOneCreateAssociationMixinOptions extends HasOneSetAssociationMixinOptions, CreateOptions<any> {}
/**
* The createAssociation mixin applied to models with hasOne.
......
......@@ -21,40 +21,50 @@ export type HookReturn = Promise<void> | void;
* Options for Model.init. We mostly duplicate the Hooks here, since there is no way to combine the two
* interfaces.
*/
export interface ModelHooks<M extends Model = Model> {
export interface ModelHooks<M extends Model = Model, TAttributes = any> {
beforeValidate(instance: M, options: ValidationOptions): HookReturn;
afterValidate(instance: M, options: ValidationOptions): HookReturn;
beforeCreate(attributes: M, options: CreateOptions): HookReturn;
afterCreate(attributes: M, options: CreateOptions): HookReturn;
beforeCreate(attributes: M, options: CreateOptions<TAttributes>): HookReturn;
afterCreate(attributes: M, options: CreateOptions<TAttributes>): HookReturn;
beforeDestroy(instance: M, options: InstanceDestroyOptions): HookReturn;
afterDestroy(instance: M, options: InstanceDestroyOptions): HookReturn;
beforeRestore(instance: M, options: InstanceRestoreOptions): HookReturn;
afterRestore(instance: M, options: InstanceRestoreOptions): HookReturn;
beforeUpdate(instance: M, options: InstanceUpdateOptions): HookReturn;
afterUpdate(instance: M, options: InstanceUpdateOptions): HookReturn;
beforeSave(instance: M, options: InstanceUpdateOptions | CreateOptions): HookReturn;
afterSave(instance: M, options: InstanceUpdateOptions | CreateOptions): HookReturn;
beforeBulkCreate(instances: M[], options: BulkCreateOptions): HookReturn;
afterBulkCreate(instances: M[], options: BulkCreateOptions): HookReturn;
beforeBulkDestroy(options: DestroyOptions): HookReturn;
afterBulkDestroy(options: DestroyOptions): HookReturn;
beforeBulkRestore(options: RestoreOptions): HookReturn;
afterBulkRestore(options: RestoreOptions): HookReturn;
beforeBulkUpdate(options: UpdateOptions): HookReturn;
afterBulkUpdate(options: UpdateOptions): HookReturn;
beforeFind(options: FindOptions): HookReturn;
beforeCount(options: CountOptions): HookReturn;
beforeFindAfterExpandIncludeAll(options: FindOptions): HookReturn;
beforeFindAfterOptions(options: FindOptions): HookReturn;
afterFind(instancesOrInstance: M[] | M | null, options: FindOptions): HookReturn;
beforeUpdate(instance: M, options: InstanceUpdateOptions<TAttributes>): HookReturn;
afterUpdate(instance: M, options: InstanceUpdateOptions<TAttributes>): HookReturn;
beforeSave(
instance: M,
options: InstanceUpdateOptions<TAttributes> | CreateOptions<TAttributes>
): HookReturn;
afterSave(
instance: M,
options: InstanceUpdateOptions<TAttributes> | CreateOptions<TAttributes>
): HookReturn;
beforeBulkCreate(instances: M[], options: BulkCreateOptions<TAttributes>): HookReturn;
afterBulkCreate(instances: M[], options: BulkCreateOptions<TAttributes>): HookReturn;
beforeBulkDestroy(options: DestroyOptions<TAttributes>): HookReturn;
afterBulkDestroy(options: DestroyOptions<TAttributes>): HookReturn;
beforeBulkRestore(options: RestoreOptions<TAttributes>): HookReturn;
afterBulkRestore(options: RestoreOptions<TAttributes>): HookReturn;
beforeBulkUpdate(options: UpdateOptions<TAttributes>): HookReturn;
afterBulkUpdate(options: UpdateOptions<TAttributes>): HookReturn;
beforeFind(options: FindOptions<TAttributes>): HookReturn;
beforeCount(options: CountOptions<TAttributes>): HookReturn;
beforeFindAfterExpandIncludeAll(options: FindOptions<TAttributes>): HookReturn;
beforeFindAfterOptions(options: FindOptions<TAttributes>): HookReturn;
afterFind(instancesOrInstance: M[] | M | null, options: FindOptions<TAttributes>): HookReturn;
beforeSync(options: SyncOptions): HookReturn;
afterSync(options: SyncOptions): HookReturn;
beforeBulkSync(options: SyncOptions): HookReturn;
afterBulkSync(options: SyncOptions): HookReturn;
}
export interface SequelizeHooks extends ModelHooks {
beforeDefine(attributes: ModelAttributes, options: ModelOptions<Model>): void;
export interface SequelizeHooks<
M extends Model<TAttributes, TCreationAttributes> = Model,
TAttributes = any,
TCreationAttributes = TAttributes
> extends ModelHooks<M, TAttributes> {
beforeDefine(attributes: ModelAttributes<M, TCreationAttributes>, options: ModelOptions<M>): void;
afterDefine(model: typeof Model): void;
beforeInit(config: Config, options: Options): void;
afterInit(sequelize: Sequelize): void;
......@@ -67,33 +77,72 @@ export interface SequelizeHooks extends ModelHooks {
/**
* Virtual class for deduplication
*/
export class Hooks {
export class Hooks<
M extends Model<TModelAttributes, TCreationAttributes> = Model,
TModelAttributes extends {} = any,
TCreationAttributes extends {} = TModelAttributes
> {
/**
* A dummy variable that doesn't exist on the real object. This exists so
* Typescript can infer the type of the attributes in static functions. Don't
* try to access this!
*/
_model: M;
/**
* A similar dummy variable that doesn't exist on the real object. Do not
* try to access this in real code.
*/
_attributes: TModelAttributes;
/**
* A similar dummy variable that doesn't exist on the real object. Do not
* try to access this in real code.
*/
_creationAttributes: TCreationAttributes;
/**
* Add a hook to the model
*
* @param name Provide a name for the hook function. It can be used to remove the hook later or to order
* hooks based on some sort of priority system in the future.
*/
public static addHook<C extends typeof Hooks, K extends keyof SequelizeHooks>(
public static addHook<
H extends Hooks,
K extends keyof SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>
>(
this: HooksStatic<H>,
hookType: K,
name: string,
fn: SequelizeHooks[K]
): C;
public static addHook<C extends typeof Hooks, K extends keyof SequelizeHooks>(
fn: SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>[K]
): HooksCtor<H>;
public static addHook<
H extends Hooks,
K extends keyof SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>
>(
this: HooksStatic<H>,
hookType: K,
fn: SequelizeHooks[K]
): C;
fn: SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>[K]
): HooksCtor<H>;
/**
* Remove hook from the model
*/
public static removeHook<C extends typeof Hooks, K extends keyof SequelizeHooks>(hookType: K, name: string): C;
public static removeHook<H extends Hooks>(
this: HooksStatic<H>,
hookType: keyof SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>,
name: string,
): HooksCtor<H>;
/**
* Check whether the mode has any hooks of this type
*/
public static hasHook<K extends keyof SequelizeHooks>(hookType: K): boolean;
public static hasHooks<K extends keyof SequelizeHooks>(hookType: K): boolean;
public static hasHook<H extends Hooks>(
this: HooksStatic<H>,
hookType: keyof SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>,
): boolean;
public static hasHooks<H extends Hooks>(
this: HooksStatic<H>,
hookType: keyof SequelizeHooks<H['_model'], H['_attributes'], H['_creationAttributes']>,
): boolean;
/**
* Add a hook to the model
......@@ -101,16 +150,28 @@ export class Hooks {
* @param name Provide a name for the hook function. It can be used to remove the hook later or to order
* hooks based on some sort of priority system in the future.
*/
public addHook<K extends keyof SequelizeHooks>(hookType: K, name: string, fn: SequelizeHooks[K]): this;
public addHook<K extends keyof SequelizeHooks>(hookType: K, fn: SequelizeHooks[K]): this;
public addHook<K extends keyof SequelizeHooks<M, TModelAttributes, TCreationAttributes>>(
hookType: K,
name: string,
fn: SequelizeHooks<Model, TModelAttributes, TCreationAttributes>[K]
): this;
public addHook<K extends keyof SequelizeHooks<M, TModelAttributes, TCreationAttributes>>(
hookType: K, fn: SequelizeHooks<M, TModelAttributes, TCreationAttributes>[K]): this;
/**
* Remove hook from the model
*/
public removeHook<K extends keyof SequelizeHooks>(hookType: K, name: string): this;
public removeHook<K extends keyof SequelizeHooks<M, TModelAttributes, TCreationAttributes>>(
hookType: K,
name: string
): this;
/**
* Check whether the mode has any hooks of this type
*/
public hasHook<K extends keyof SequelizeHooks>(hookType: K): boolean;
public hasHooks<K extends keyof SequelizeHooks>(hookType: K): boolean;
public hasHook<K extends keyof SequelizeHooks<M, TModelAttributes, TCreationAttributes>>(hookType: K): boolean;
public hasHooks<K extends keyof SequelizeHooks<M, TModelAttributes, TCreationAttributes>>(hookType: K): boolean;
}
export type HooksCtor<H extends Hooks> = typeof Hooks & { new(): H };
export type HooksStatic<H extends Hooks> = { new(): H };
......@@ -45,11 +45,11 @@ export interface SearchPathable {
searchPath?: string;
}
export interface Filterable {
export interface Filterable<TAttributes = any> {
/**
* Attribute has to be matched for rows to be selected for the given action.
*/
where?: WhereOptions;
where?: WhereOptions<TAttributes>;
}
export interface Projectable {
......@@ -109,7 +109,13 @@ export interface ScopeOptions {
/**
* The type accepted by every `where` option
*/
export type WhereOptions = WhereAttributeHash | AndOperator | OrOperator | Literal | Fn | Where;
export type WhereOptions<TAttributes = any> =
| WhereAttributeHash<TAttributes>
| AndOperator<TAttributes>
| OrOperator<TAttributes>
| Literal
| Fn
| Where;
/**
* Example: `[Op.any]: [2,3]` becomes `ANY ARRAY[2, 3]::INTEGER`
......@@ -304,13 +310,13 @@ export interface WhereOperators {
}
/** Example: `[Op.or]: [{a: 5}, {a: 6}]` becomes `(a = 5 OR a = 6)` */
export interface OrOperator {
[Op.or]: WhereOptions | WhereOptions[] | WhereValue | WhereValue[];
export interface OrOperator<TAttributes = any> {
[Op.or]: WhereOptions<TAttributes> | WhereOptions<TAttributes>[] | WhereValue<TAttributes> | WhereValue<TAttributes>[];
}
/** Example: `[Op.and]: {a: 5}` becomes `AND (a = 5)` */
export interface AndOperator {
[Op.and]: WhereOptions | WhereOptions[] | WhereValue | WhereValue[];
export interface AndOperator<TAttributes = any> {
[Op.and]: WhereOptions<TAttributes> | WhereOptions<TAttributes>[] | WhereValue<TAttributes> | WhereValue<TAttributes>[];
}
/**
......@@ -325,7 +331,7 @@ export interface WhereGeometryOptions {
* Used for the right hand side of WhereAttributeHash.
* WhereAttributeHash is in there for JSON columns.
*/
export type WhereValue =
export type WhereValue<TAttributes = any> =
| string // literal value
| number // literal value
| boolean // literal value
......@@ -333,20 +339,18 @@ export type WhereValue =
| Buffer // literal value
| null
| WhereOperators
| WhereAttributeHash // for JSON columns
| WhereAttributeHash<any> // for JSON columns
| Col // reference another column
| Fn
| OrOperator
| AndOperator
| OrOperator<TAttributes>
| AndOperator<TAttributes>
| WhereGeometryOptions
| (string | number | Buffer | WhereAttributeHash)[] // implicit [Op.or]
// allow optional values in where object types
// Sequelize will still throw when a value in the object has the value undefined
| undefined;
| (string | number | Buffer | WhereAttributeHash<TAttributes>)[]; // implicit [Op.or]
/**
* A hash of attributes to describe your search.
*/
export interface WhereAttributeHash {
export type WhereAttributeHash<TAttributes = any> = {
/**
* Possible key values:
* - A simple attribute name
......@@ -358,12 +362,12 @@ export interface WhereAttributeHash {
* }
* }
*/
[field: string]: WhereValue | WhereOptions;
[field in keyof TAttributes]?: WhereValue<TAttributes> | WhereOptions<TAttributes>;
}
/**
* Through options for Include Options
*/
export interface IncludeThroughOptions extends Filterable, Projectable {
export interface IncludeThroughOptions extends Filterable<any>, Projectable {
/**
* The alias of the relation, in case the model you want to eagerly load is aliassed. For `hasOne` /
* `belongsTo`, this should be the singular name, and for `hasMany`, it should be the plural
......@@ -379,7 +383,7 @@ export type Includeable = typeof Model | Association | IncludeOptions | { all: t
/**
* Complex include options
*/
export interface IncludeOptions extends Filterable, Projectable, Paranoid {
export interface IncludeOptions extends Filterable<any>, Projectable, Paranoid {
/**
* Mark the include as duplicating, will prevent a subquery from being used.
*/
......@@ -403,13 +407,13 @@ export interface IncludeOptions extends Filterable, Projectable, Paranoid {
/**
* Custom `on` clause, overrides default.
*/
on?: WhereOptions;
on?: WhereOptions<any>;
/**
* Note that this converts the eager load to an inner join,
* unless you explicitly set `required: false`
*/
where?: WhereOptions;
where?: WhereOptions<any>;
/**
* If true, converts to an inner join, which means that the parent model will only be loaded if it has any
......@@ -453,7 +457,7 @@ export interface IncludeOptions extends Filterable, Projectable, Paranoid {
subQuery?: boolean;
}
type OrderItemAssociation = Association | typeof Model | { model: typeof Model; as: string } | string
type OrderItemAssociation = Association | ModelStatic<Model> | { model: ModelStatic<Model>; as: string } | string
type OrderItemColumn = string | Col | Fn | Literal
export type OrderItem =
| string
......@@ -507,7 +511,9 @@ type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
*
* A hash of options to describe the scope of the search
*/
export interface FindOptions extends QueryOptions, Filterable, Projectable, Paranoid, IndexHintable {
export interface FindOptions<TAttributes = any>
extends QueryOptions, Filterable<TAttributes>, Projectable, Paranoid, IndexHintable
{
/**
* A list of associations to eagerly load using a left join (a single association is also supported). Supported is either
* `{ include: Model1 }`, `{ include: [ Model1, Model2, ...]}`, `{ include: [{ model: Model1, as: 'Alias' }]}` or
......@@ -547,7 +553,7 @@ export interface FindOptions extends QueryOptions, Filterable, Projectable, Para
*/
lock?:
| LOCK
| { level: LOCK; of: typeof Model }
| { level: LOCK; of: ModelStatic<Model> }
| boolean;
/**
* Skip locked rows. Only supported in Postgres.
......@@ -562,7 +568,7 @@ export interface FindOptions extends QueryOptions, Filterable, Projectable, Para
/**
* Select group rows after groups and aggregates are computed.
*/
having?: WhereOptions;
having?: WhereOptions<any>;
/**
* Use sub queries (internal)
......@@ -570,7 +576,7 @@ export interface FindOptions extends QueryOptions, Filterable, Projectable, Para
subQuery?: boolean;
}
export interface NonNullFindOptions extends FindOptions {
export interface NonNullFindOptions<TAttributes = any> extends FindOptions<TAttributes> {
/**
* Throw if nothing was found.
*/
......@@ -580,7 +586,9 @@ export interface NonNullFindOptions extends FindOptions {
/**
* Options for Model.count method
*/
export interface CountOptions extends Logging, Transactionable, Filterable, Projectable, Paranoid, Poolable {
export interface CountOptions<TAttributes = any>
extends Logging, Transactionable, Filterable<TAttributes>, Projectable, Paranoid, Poolable
{
/**
* Include options. See `find` for details
*/
......@@ -607,7 +615,7 @@ export interface CountOptions extends Logging, Transactionable, Filterable, Proj
/**
* Options for Model.count when GROUP BY is used
*/
export interface CountWithOptions extends CountOptions {
export interface CountWithOptions<TAttributes = any> extends CountOptions<TAttributes> {
/**
* GROUP BY in sql
* Used in conjunction with `attributes`.
......@@ -616,7 +624,7 @@ export interface CountWithOptions extends CountOptions {
group: GroupOption;
}
export interface FindAndCountOptions extends CountOptions, FindOptions { }
export interface FindAndCountOptions<TAttributes = any> extends CountOptions<TAttributes>, FindOptions<TAttributes> { }
/**
* Options for Model.build method
......@@ -652,11 +660,11 @@ export interface Silent {
/**
* Options for Model.create method
*/
export interface CreateOptions extends BuildOptions, Logging, Silent, Transactionable, Hookable {
export interface CreateOptions<TAttributes = any> extends BuildOptions, Logging, Silent, Transactionable, Hookable {
/**
* If set, only columns matching those in fields will be saved
*/
fields?: string[];
fields?: (keyof TAttributes)[];
/**
* On Duplicate
......@@ -685,28 +693,30 @@ export interface Hookable {
/**
* Options for Model.findOrCreate method
*/
export interface FindOrCreateOptions extends Filterable, Logging, Transactionable {
export interface FindOrCreateOptions<TAttributes = any, TCreationAttributes = TAttributes>
extends FindOptions<TAttributes>
{
/**
* The fields to insert / update. Defaults to all fields
*/
fields?: string[];
fields?: (keyof TAttributes)[];
/**
* Default values to use if building a new instance
*/
defaults?: object;
defaults?: TCreationAttributes;
}
/**
* Options for Model.upsert method
*/
export interface UpsertOptions extends Logging, Transactionable, SearchPathable, Hookable {
export interface UpsertOptions<TAttributes = any> extends Logging, Transactionable, SearchPathable, Hookable {
/**
* The fields to insert / update. Defaults to all fields
*/
fields?: string[];
fields?: (keyof TAttributes)[];
/**
* Return the affected rows
* Return the affected rows (only for postgres)
*/
returning?: boolean;
......@@ -719,11 +729,11 @@ export interface UpsertOptions extends Logging, Transactionable, SearchPathable,
/**
* Options for Model.bulkCreate method
*/
export interface BulkCreateOptions extends Logging, Transactionable, Hookable {
export interface BulkCreateOptions<TAttributes = any> extends Logging, Transactionable, Hookable {
/**
* Fields to insert (defaults to all fields)
*/
fields?: string[];
fields?: (keyof TAttributes)[];
/**
* Should each row be subject to validation before it is inserted. The whole insert will fail if one row
......@@ -748,7 +758,7 @@ export interface BulkCreateOptions extends Logging, Transactionable, Hookable {
* Fields to update if row key already exists (on duplicate key update)? (only supported by MySQL,
* MariaDB, SQLite >= 3.24.0 & Postgres >= 9.5). By default, all fields are updated.
*/
updateOnDuplicate?: string[];
updateOnDuplicate?: (keyof TAttributes)[];
/**
* Include options. See `find` for details
......@@ -758,13 +768,13 @@ export interface BulkCreateOptions extends Logging, Transactionable, Hookable {
/**
* Return all columns or only the specified columns for the affected rows (only for postgres)
*/
returning?: boolean | string[];
returning?: boolean | (keyof TAttributes)[];
}
/**
* The options passed to Model.destroy in addition to truncate
*/
export interface TruncateOptions extends Logging, Transactionable, Filterable, Hookable {
export interface TruncateOptions<TAttributes = any> extends Logging, Transactionable, Filterable<TAttributes>, Hookable {
/**
* Only used in conjuction with TRUNCATE. Truncates all tables that have foreign-key references to the
* named table, or to any tables added to the group due to CASCADE.
......@@ -799,7 +809,7 @@ export interface TruncateOptions extends Logging, Transactionable, Filterable, H
/**
* Options used for Model.destroy
*/
export interface DestroyOptions extends TruncateOptions {
export interface DestroyOptions<TAttributes = any> extends TruncateOptions<TAttributes> {
/**
* If set to true, dialects that support it will use TRUNCATE instead of DELETE FROM. If a table is
* truncated the where and limit options are ignored
......@@ -810,7 +820,7 @@ export interface DestroyOptions extends TruncateOptions {
/**
* Options for Model.restore
*/
export interface RestoreOptions extends Logging, Transactionable, Filterable, Hookable {
export interface RestoreOptions<TAttributes = any> extends Logging, Transactionable, Filterable<TAttributes>, Hookable {
/**
* If set to true, restore will find all records within the where parameter and will execute before / after
......@@ -827,16 +837,16 @@ export interface RestoreOptions extends Logging, Transactionable, Filterable, Ho
/**
* Options used for Model.update
*/
export interface UpdateOptions extends Logging, Transactionable, Paranoid, Hookable {
export interface UpdateOptions<TAttributes = any> extends Logging, Transactionable, Paranoid, Hookable {
/**
* Options to describe the scope of the search.
*/
where: WhereOptions;
where: WhereOptions<TAttributes>;
/**
* Fields to update (defaults to all fields)
*/
fields?: string[];
fields?: (keyof TAttributes)[];
/**
* Should each row be subject to validation before it is inserted. The whole insert will fail if one row
......@@ -880,7 +890,9 @@ export interface UpdateOptions extends Logging, Transactionable, Paranoid, Hooka
/**
* Options used for Model.aggregate
*/
export interface AggregateOptions<T extends DataType | unknown> extends QueryOptions, Filterable, Paranoid {
export interface AggregateOptions<T extends DataType | unknown, TAttributes = any>
extends QueryOptions, Filterable<TAttributes>, Paranoid
{
/**
* The type of the result. If `field` is a field in this Model, the default will be the type of that field,
* otherwise defaults to float.
......@@ -898,12 +910,13 @@ export interface AggregateOptions<T extends DataType | unknown> extends QueryOpt
/**
* Options used for Instance.increment method
*/
export interface IncrementDecrementOptions extends Logging, Transactionable, Silent, SearchPathable, Filterable { }
export interface IncrementDecrementOptions<TAttributes = any>
extends Logging, Transactionable, Silent, SearchPathable, Filterable<TAttributes> { }
/**
* Options used for Instance.increment method
*/
export interface IncrementDecrementOptionsWithBy extends IncrementDecrementOptions {
export interface IncrementDecrementOptionsWithBy<TAttributes = any> extends IncrementDecrementOptions<TAttributes> {
/**
* The number to increment by
*
......@@ -930,7 +943,8 @@ export interface InstanceDestroyOptions extends Logging, Transactionable {
/**
* Options used for Instance.update method
*/
export interface InstanceUpdateOptions extends SaveOptions, SetOptions, Filterable { }
export interface InstanceUpdateOptions<TAttributes = any> extends
SaveOptions<TAttributes>, SetOptions, Filterable<TAttributes> { }
/**
* Options used for Instance.set method
......@@ -950,12 +964,12 @@ export interface SetOptions {
/**
* Options used for Instance.save method
*/
export interface SaveOptions extends Logging, Transactionable, Silent {
export interface SaveOptions<TAttributes = any> extends Logging, Transactionable, Silent {
/**
* An optional array of strings, representing database columns. If fields is provided, only those columns
* will be validated and saved.
*/
fields?: string[];
fields?: (keyof TAttributes)[];
/**
* If false, validations won't be run.
......@@ -1191,11 +1205,11 @@ export interface ModelSetterOptions<M extends Model = Model> {
/**
* Interface for Define Scope Options
*/
export interface ModelScopeOptions {
export interface ModelScopeOptions<TAttributes = any> {
/**
* Name of the scope and it's query
*/
[scopeName: string]: FindOptions | ((...args: any[]) => FindOptions);
[scopeName: string]: FindOptions<TAttributes> | ((...args: any[]) => FindOptions<TAttributes>);
}
/**
......@@ -1338,11 +1352,11 @@ export interface ModelAttributeColumnOptions<M extends Model = Model> extends Co
/**
* Interface for Attributes provided for a column
*/
export interface ModelAttributes<M extends Model = Model> {
export type ModelAttributes<M extends Model = Model, TCreationAttributes = any> = {
/**
* The description of a database column
*/
[name: string]: DataType | ModelAttributeColumnOptions<M>;
[name in keyof TCreationAttributes]: DataType | ModelAttributeColumnOptions<M>;
}
/**
......@@ -1358,13 +1372,13 @@ export interface ModelOptions<M extends Model = Model> {
* Define the default search scope to use for this model. Scopes have the same form as the options passed to
* find / findAll.
*/
defaultScope?: FindOptions;
defaultScope?: FindOptions<M['_attributes']>;
/**
* More scopes, defined in the same way as defaultScope above. See `Model.scope` for more information about
* how scopes are defined, and what you can do with them
*/
scopes?: ModelScopeOptions;
scopes?: ModelScopeOptions<M['_attributes']>;
/**
* Don't persits null values. This means that all columns with null values will not be saved.
......@@ -1464,7 +1478,7 @@ export interface ModelOptions<M extends Model = Model> {
* See Hooks for more information about hook
* functions and their signatures. Each property can either be a function, or an array of functions.
*/
hooks?: Partial<ModelHooks<M>>;
hooks?: Partial<ModelHooks<M, M['_attributes']>>;
/**
* An object of model wide validations. Validations have access to all model values via `this`. If the
......@@ -1514,7 +1528,31 @@ export interface AddScopeOptions {
override: boolean;
}
export abstract class Model<T = any, T2 = any> extends Hooks {
export abstract class Model<TModelAttributes extends {} = any, TCreationAttributes extends {} = TModelAttributes>
extends Hooks<Model<TModelAttributes, TCreationAttributes>, TModelAttributes, TCreationAttributes>
{
/**
* A dummy variable that doesn't exist on the real object. This exists so
* Typescript can infer the type of the attributes in static functions. Don't
* try to access this!
*
* Before using these, I'd tried typing out the functions without them, but
* Typescript fails to infer `TAttributes` in signatures like the below.
*
* ```ts
* public static findOne<M extends Model<TAttributes>, TAttributes>(
* this: { new(): M },
* options: NonNullFindOptions<TAttributes>
* ): Promise<M>;
* ```
*/
_attributes: TModelAttributes;
/**
* A similar dummy variable that doesn't exist on the real object. Do not
* try to access this in real code.
*/
_creationAttributes: TCreationAttributes;
/** The name of the database table */
public static readonly tableName: string;
......@@ -1593,7 +1631,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param options These options are merged with the default define options provided to the Sequelize constructor
* @return Return the initialized model
*/
public static init<M extends Model = Model>(this: ModelCtor<M>, attributes: ModelAttributes<M>, options: InitOptions<M>): Model;
public static init<M extends Model>(
this: ModelStatic<M>,
attributes: ModelAttributes<M, M['_creationAttributes']>, options: InitOptions<M>
): Model;
/**
* Remove attribute from model definition
......@@ -1606,7 +1647,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Sync this Model to the DB, that is create the table. Upon success, the callback will be called with the
* model instance (this)
*/
public static sync(options?: SyncOptions): Promise<Model>;
public static sync<M extends Model>(options?: SyncOptions): Promise<M>;
/**
* Drop the table represented by this Model
......@@ -1625,7 +1666,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param options
*/
public static schema<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
schema: string,
options?: SchemaOptions
): { new(): M } & typeof Model;
......@@ -1694,10 +1735,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @return Model A reference to the model, with the scope(s) applied. Calling scope again on the returned
* model will clear the previous scope.
*/
public static scope<M extends { new(): Model }>(
this: M,
options?: string | ScopeOptions | (string | ScopeOptions)[] | WhereAttributeHash
): M;
public static scope<M extends Model>(
this: ModelStatic<M>,
options?: string | ScopeOptions | (string | ScopeOptions)[] | WhereAttributeHash<M>
): ModelCtor<M>;
/**
* Add a new scope to the model
......@@ -1707,8 +1748,18 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* error if a scope with that name already exists. Pass `override: true` in the options
* object to silence this error.
*/
public static addScope(name: string, scope: FindOptions, options?: AddScopeOptions): void;
public static addScope(name: string, scope: (...args: any[]) => FindOptions, options?: AddScopeOptions): void;
public static addScope<M extends Model>(
this: ModelStatic<M>,
name: string,
scope: FindOptions<M['_attributes']>,
options?: AddScopeOptions
): void;
public static addScope<M extends Model>(
this: ModelStatic<M>,
name: string,
scope: (...args: any[]) => FindOptions<M['_attributes']>,
options?: AddScopeOptions
): void;
/**
* Search for multiple instances.
......@@ -1772,30 +1823,35 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
*
* @see {Sequelize#query}
*/
public static findAll<M extends Model>(this: { new(): M } & typeof Model, options?: FindOptions): Promise<M[]>;
public static findAll<M extends Model>(
this: ModelStatic<M>,
options?: FindOptions<M['_attributes']>): Promise<M[]>;
/**
* Search for a single instance by its primary key. This applies LIMIT 1, so the listener will
* always be called with a single instance.
*/
public static findByPk<M extends Model>(
this: { new (): M } & typeof Model,
this: ModelStatic<M>,
identifier: Identifier,
options: Omit<NonNullFindOptions, 'where'>
options: Omit<NonNullFindOptions<M['_attributes']>, 'where'>
): Promise<M>;
public static findByPk<M extends Model>(
this: { new (): M } & typeof Model,
this: ModelStatic<M>,
identifier?: Identifier,
options?: Omit<FindOptions, 'where'>
options?: Omit<FindOptions<M['_attributes']>, 'where'>
): Promise<M | null>;
/**
* Search for a single instance. Returns the first instance found, or null if none can be found.
*/
public static findOne<M extends Model>(this: { new (): M } & typeof Model, options: NonNullFindOptions): Promise<M>;
public static findOne<M extends Model>(
this: { new(): M } & typeof Model,
options?: FindOptions
this: ModelStatic<M>,
options: NonNullFindOptions<M['_attributes']>
): Promise<M>;
public static findOne<M extends Model>(
this: ModelStatic<M>,
options?: FindOptions<M['_attributes']>
): Promise<M | null>;
/**
......@@ -1807,38 +1863,47 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @return Returns the aggregate result cast to `options.dataType`, unless `options.plain` is false, in
* which case the complete data result is returned.
*/
public static aggregate<M extends Model, T extends DataType | unknown>(
this: { new(): M } & typeof Model,
field: keyof M,
public static aggregate<T, M extends Model>(
this: ModelStatic<M>,
field: keyof M['_attributes'] | '*',
aggregateFunction: string,
options?: AggregateOptions<T>
options?: AggregateOptions<T, M['_attributes']>
): Promise<T>;
/**
* Count number of records if group by is used
*/
public static count(options: CountWithOptions): Promise<{ [key: string]: number }>;
public static count<M extends Model>(
this: ModelStatic<M>,
options: CountWithOptions<M['_attributes']>
): Promise<{ [key: string]: number }>;
/**
* Count the number of records matching the provided where clause.
*
* If you provide an `include` option, the number of matching associations will be counted instead.
*/
public static count(options?: CountOptions): Promise<number>;
public static count<M extends Model>(
this: ModelStatic<M>,
options?: CountOptions<M['_attributes']>
): Promise<number>;
/**
* Find all the rows matching your query, within a specified offset / limit, and get the total number of
* rows matching your query. This is very usefull for paging
*
* ```js
* const { rows, count } = await Model.findAndCountAll({
* Model.findAndCountAll({
* where: ...,
* limit: 12,
* offset: 12
* });
* }).then(result => {
* ...
* })
* ```
* In the above example, `rows` will contain rows 13 through 24, while `count` will return
* the total number of rows that matched your query.
* In the above example, `result.rows` will contain rows 13 through 24, while `result.count` will return
* the
* total number of rows that matched your query.
*
* When you add includes, only those which are required (either because they have a where clause, or
* because
......@@ -1859,43 +1924,43 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* profiles will be counted
*/
public static findAndCountAll<M extends Model>(
this: { new(): M } & typeof Model,
options?: FindAndCountOptions
this: ModelStatic<M>,
options?: FindAndCountOptions<M['_attributes']>
): Promise<{ rows: M[]; count: number }>;
/**
* Find the maximum value of field
*/
public static max<M extends Model, T extends DataType | unknown>(
this: { new(): M } & typeof Model,
field: keyof M,
options?: AggregateOptions<T>
public static max<T extends DataType | unknown, M extends Model>(
this: ModelStatic<M>,
field: keyof M['_attributes'],
options?: AggregateOptions<T, M['_attributes']>
): Promise<T>;
/**
* Find the minimum value of field
*/
public static min<M extends Model, T extends DataType | unknown>(
this: { new(): M } & typeof Model,
field: keyof M,
options?: AggregateOptions<T>
public static min<T extends DataType | unknown, M extends Model>(
this: ModelStatic<M>,
field: keyof M['_attributes'],
options?: AggregateOptions<T, M['_attributes']>
): Promise<T>;
/**
* Find the sum of field
*/
public static sum<M extends Model, T extends DataType | unknown>(
this: { new(): M } & typeof Model,
field: keyof M,
options?: AggregateOptions<T>
public static sum<T extends DataType | unknown, M extends Model>(
this: ModelStatic<M>,
field: keyof M['_attributes'],
options?: AggregateOptions<T, M['_attributes']>
): Promise<number>;
/**
* Builds a new model instance. Values is an object of key value pairs, must be defined but can be empty.
*/
public static build<M extends Model>(
this: { new(): M } & typeof Model,
record?: object,
this: ModelStatic<M>,
record?: M['_creationAttributes'],
options?: BuildOptions
): M;
......@@ -1903,8 +1968,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Undocumented bulkBuild
*/
public static bulkBuild<M extends Model>(
this: { new(): M } & typeof Model,
records: object[],
this: ModelStatic<M>,
records: (M['_creationAttributes'])[],
options?: BuildOptions
): M[];
......@@ -1912,24 +1977,28 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Builds a new model instance and calls save on it.
*/
public static create<M extends Model>(
this: { new(): M } & typeof Model,
values?: object,
options?: CreateOptions
this: ModelStatic<M>,
values?: M['_creationAttributes'],
options?: CreateOptions<M['_attributes']>
): Promise<M>;
public static create(values: object, options: CreateOptions & { returning: false }): Promise<void>;
public static create<M extends Model>(
this: ModelStatic<M>,
values: M['_creationAttributes'],
options: CreateOptions<M['_attributes']> & { returning: false }
): Promise<void>;
/**
* Find a row that matches the query, or build (but don't save) the row if none is found.
* The successful result of the promise will be [instance, initialized] - Make sure to use destructuring such as `const [instance, wasBuilt] = ...`
* The successfull result of the promise will be (instance, initialized) - Make sure to use `.then(([...]))`
*/
public static findOrBuild<M extends Model>(
this: { new(): M } & typeof Model,
options: FindOrCreateOptions
this: ModelStatic<M>,
options: FindOrCreateOptions<M['_attributes'], M['_creationAttributes']>
): Promise<[M, boolean]>;
/**
* Find a row that matches the query, or build and save the row if none is found
* The successful result of the promise will be [instance, created] - Make sure to use destructuring such as `const [instance, wasCreated] = ...`
* The successful result of the promise will be (instance, created) - Make sure to use `.then(([...]))`
*
* If no transaction is passed in the `options` object, a new transaction will be created internally, to
* prevent the race condition where a matching row is created by another connection after the find but
......@@ -1939,8 +2008,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* will be created instead, and any unique constraint violation will be handled internally.
*/
public static findOrCreate<M extends Model>(
this: { new(): M } & typeof Model,
options: FindOrCreateOptions
this: ModelStatic<M>,
options: FindOrCreateOptions<M['_attributes'], M['_creationAttributes']>
): Promise<[M, boolean]>;
/**
......@@ -1948,8 +2017,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Will execute a find call, if empty then attempt to create, if unique constraint then attempt to find again
*/
public static findCreateFind<M extends Model>(
this: { new(): M } & typeof Model,
options: FindOrCreateOptions
this: ModelStatic<M>,
options: FindOrCreateOptions<M['_attributes'], M['_creationAttributes']>
): Promise<[M, boolean]>;
/**
......@@ -1960,17 +2029,21 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
*
* **Implementation details:**
*
* * MySQL - Implemented with ON DUPLICATE KEY UPDATE
* * PostgreSQL - Implemented with ON CONFLICT DO UPDATE
* * SQLite - Implemented with ON CONFLICT DO UPDATE
* * MSSQL - Implemented with MERGE statement
* * MySQL - Implemented as a single query `INSERT values ON DUPLICATE KEY UPDATE values`
* * PostgreSQL - Implemented as a temporary function with exception handling: INSERT EXCEPTION WHEN
* unique_constraint UPDATE
* * SQLite - Implemented as two queries `INSERT; UPDATE`. This means that the update is executed
* regardless
* of whether the row already existed or not
*
* **Note** that PostgreSQL/SQLite returns null for created, no matter if the row was created or updated.
* **Note** that SQLite returns null for created, no matter if the row was created or updated. This is
* because SQLite always runs INSERT OR IGNORE + UPDATE, in a single query, so there is no way to know
* whether the row was inserted or not.
*/
public static upsert<M extends Model>(
this: { new(): M } & typeof Model,
values: object,
options?: UpsertOptions
this: ModelStatic<M>,
values: M['_creationAttributes'],
options?: UpsertOptions<M['_attributes']>
): Promise<[M, boolean | null]>;
/**
......@@ -1985,27 +2058,36 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param records List of objects (key/value pairs) to create instances from
*/
public static bulkCreate<M extends Model>(
this: { new(): M } & typeof Model,
records: object[],
options?: BulkCreateOptions
this: ModelStatic<M>,
records: (M['_creationAttributes'])[],
options?: BulkCreateOptions<M['_attributes']>
): Promise<M[]>;
/**
* Truncate all instances of the model. This is a convenient method for Model.destroy({ truncate: true }).
*/
public static truncate(options?: TruncateOptions): Promise<void>;
public static truncate<M extends Model>(
this: ModelStatic<M>,
options?: TruncateOptions<M['_attributes']>
): Promise<void>;
/**
* Delete multiple instances, or set their deletedAt timestamp to the current time if `paranoid` is enabled.
*
* @return Promise<number> The number of destroyed rows
*/
public static destroy(options?: DestroyOptions): Promise<number>;
public static destroy<M extends Model>(
this: ModelStatic<M>,
options?: DestroyOptions<M['_attributes']>
): Promise<number>;
/**
* Restore multiple instances if `paranoid` is enabled.
*/
public static restore(options?: RestoreOptions): Promise<void>;
public static restore<M extends Model>(
this: ModelStatic<M>,
options?: RestoreOptions<M['_attributes']>
): Promise<void>;
/**
* Update multiple instances that match the where options. The promise returns an array with one or two
......@@ -2013,36 +2095,36 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* affected rows (only supported in postgres and mssql with `options.returning` true.)
*/
public static update<M extends Model>(
this: { new(): M } & typeof Model,
values: object,
options: UpdateOptions
this: ModelStatic<M>,
values: Partial<M['_attributes']>,
options: UpdateOptions<M['_attributes']>
): Promise<[number, M[]]>;
/**
* Increments a single field.
*/
public static increment<M extends Model, K extends keyof M>(
this: { new(): M },
field: K,
options: IncrementDecrementOptionsWithBy
public static increment<M extends Model>(
this: ModelStatic<M>,
field: keyof M['_attributes'],
options: IncrementDecrementOptionsWithBy<M['_attributes']>
): Promise<M>;
/**
* Increments multiple fields by the same value.
*/
public static increment<M extends Model, K extends keyof M>(
this: { new(): M },
fields: K[],
options: IncrementDecrementOptionsWithBy
public static increment<M extends Model>(
this: ModelStatic<M>,
fields: (keyof M['_attributes'])[],
options: IncrementDecrementOptionsWithBy<M['_attributes']>
): Promise<M>;
/**
* Increments multiple fields by different values.
*/
public static increment<M extends Model, K extends keyof M>(
this: { new(): M },
fields: { [key in K]?: number },
options: IncrementDecrementOptions
public static increment<M extends Model>(
this: ModelStatic<M>,
fields: { [key in keyof M['_attributes']]?: number },
options: IncrementDecrementOptions<M['_attributes']>
): Promise<M>;
/**
......@@ -2063,12 +2145,12 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static beforeValidate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
public static beforeValidate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
......@@ -2079,12 +2161,12 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static afterValidate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
public static afterValidate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
fn: (instance: M, options: ValidationOptions) => HookReturn
): void;
......@@ -2095,13 +2177,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with attributes, options
*/
public static beforeCreate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (attributes: M, options: CreateOptions) => HookReturn
fn: (instance: M, options: CreateOptions<M['_attributes']>) => HookReturn
): void;
public static beforeCreate<M extends Model>(
this: { new(): M } & typeof Model,
fn: (attributes: M, options: CreateOptions) => HookReturn
this: ModelStatic<M>,
fn: (instance: M, options: CreateOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2111,13 +2193,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with attributes, options
*/
public static afterCreate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (attributes: M, options: CreateOptions) => HookReturn
fn: (instance: M, options: CreateOptions<M['_attributes']>) => HookReturn
): void;
public static afterCreate<M extends Model>(
this: { new(): M } & typeof Model,
fn: (attributes: M, options: CreateOptions) => HookReturn
this: ModelStatic<M>,
fn: (instance: M, options: CreateOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2127,12 +2209,12 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static beforeDestroy<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
public static beforeDestroy<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
......@@ -2143,12 +2225,12 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static afterDestroy<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
public static afterDestroy<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
fn: (instance: M, options: InstanceDestroyOptions) => HookReturn
): void;
......@@ -2159,13 +2241,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static beforeUpdate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: UpdateOptions) => HookReturn
fn: (instance: M, options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
public static beforeUpdate<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instance: M, options: UpdateOptions) => HookReturn
this: ModelStatic<M>,
fn: (instance: M, options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2175,13 +2257,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static afterUpdate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: UpdateOptions) => HookReturn
fn: (instance: M, options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
public static afterUpdate<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instance: M, options: UpdateOptions) => HookReturn
this: ModelStatic<M>,
fn: (instance: M, options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2191,13 +2273,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static beforeSave<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
fn: (instance: M, options: UpdateOptions<M['_attributes']> | SaveOptions<M['_attributes']>) => HookReturn
): void;
public static beforeSave<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
this: ModelStatic<M>,
fn: (instance: M, options: UpdateOptions<M['_attributes']> | SaveOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2207,13 +2289,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance, options
*/
public static afterSave<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
fn: (instance: M, options: UpdateOptions<M['_attributes']> | SaveOptions<M['_attributes']>) => HookReturn
): void;
public static afterSave<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instance: M, options: UpdateOptions | SaveOptions) => HookReturn
this: ModelStatic<M>,
fn: (instance: M, options: UpdateOptions<M['_attributes']> | SaveOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2223,13 +2305,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instances, options
*/
public static beforeBulkCreate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
fn: (instances: M[], options: BulkCreateOptions<M['_attributes']>) => HookReturn
): void;
public static beforeBulkCreate<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
this: ModelStatic<M>,
fn: (instances: M[], options: BulkCreateOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2239,13 +2321,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instances, options
*/
public static afterBulkCreate<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
fn: (instances: M[], options: BulkCreateOptions<M['_attributes']>) => HookReturn
): void;
public static afterBulkCreate<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instances: M[], options: BulkCreateOptions) => HookReturn
this: ModelStatic<M>,
fn: (instances: M[], options: BulkCreateOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2254,8 +2336,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions) => HookReturn): void;
public static beforeBulkDestroy(fn: (options: BulkCreateOptions) => HookReturn): void;
public static beforeBulkDestroy<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: BulkCreateOptions<M['_attributes']>) => HookReturn): void;
public static beforeBulkDestroy<M extends Model>(
this: ModelStatic<M>,
fn: (options: BulkCreateOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run after destroying instances in bulk
......@@ -2263,8 +2350,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkDestroy(name: string, fn: (options: DestroyOptions) => HookReturn): void;
public static afterBulkDestroy(fn: (options: DestroyOptions) => HookReturn): void;
public static afterBulkDestroy<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: DestroyOptions<M['_attributes']>) => HookReturn
): void;
public static afterBulkDestroy<M extends Model>(
this: ModelStatic<M>,
fn: (options: DestroyOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run after updating instances in bulk
......@@ -2272,8 +2365,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkUpdate(name: string, fn: (options: UpdateOptions) => HookReturn): void;
public static beforeBulkUpdate(fn: (options: UpdateOptions) => HookReturn): void;
public static beforeBulkUpdate<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
public static beforeBulkUpdate<M extends Model>(
this: ModelStatic<M>,
fn: (options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run after updating instances in bulk
......@@ -2281,8 +2380,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkUpdate(name: string, fn: (options: UpdateOptions) => HookReturn): void;
public static afterBulkUpdate(fn: (options: UpdateOptions) => HookReturn): void;
public static afterBulkUpdate<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
public static afterBulkUpdate<M extends Model>(
this: ModelStatic<M>,
fn: (options: UpdateOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run before a find (select) query
......@@ -2290,8 +2395,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFind(name: string, fn: (options: FindOptions) => HookReturn): void;
public static beforeFind(fn: (options: FindOptions) => HookReturn): void;
public static beforeFind<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: FindOptions<M['_attributes']>) => HookReturn
): void;
public static beforeFind<M extends Model>(
this: ModelStatic<M>,
fn: (options: FindOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run before a count query
......@@ -2299,8 +2410,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeCount(name: string, fn: (options: CountOptions) => HookReturn): void;
public static beforeCount(fn: (options: CountOptions) => HookReturn): void;
public static beforeCount<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: CountOptions<M['_attributes']>) => HookReturn
): void;
public static beforeCount<M extends Model>(
this: ModelStatic<M>,
fn: (options: CountOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
......@@ -2308,8 +2425,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions) => HookReturn): void;
public static beforeFindAfterExpandIncludeAll(fn: (options: FindOptions) => HookReturn): void;
public static beforeFindAfterExpandIncludeAll<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: FindOptions<M['_attributes']>) => HookReturn
): void;
public static beforeFindAfterExpandIncludeAll<M extends Model>(
this: ModelStatic<M>,
fn: (options: FindOptions<M['_attributes']>) => HookReturn
): void;
/**
* A hook that is run before a find (select) query, after all option parsing is complete
......@@ -2317,8 +2440,14 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterOptions(name: string, fn: (options: FindOptions) => HookReturn): void;
public static beforeFindAfterOptions(fn: (options: FindOptions) => void): HookReturn;
public static beforeFindAfterOptions<M extends Model>(
this: ModelStatic<M>,
name: string, fn: (options: FindOptions<M['_attributes']>) => HookReturn
): void;
public static beforeFindAfterOptions<M extends Model>(
this: ModelStatic<M>,
fn: (options: FindOptions<M['_attributes']>) => void
): HookReturn;
/**
* A hook that is run after a find (select) query
......@@ -2327,13 +2456,13 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param fn A callback function that is called with instance(s), options
*/
public static afterFind<M extends Model>(
this: { new(): M } & typeof Model,
this: ModelStatic<M>,
name: string,
fn: (instancesOrInstance: M[] | M | null, options: FindOptions) => HookReturn
fn: (instancesOrInstance: M[] | M | null, options: FindOptions<M['_attributes']>) => HookReturn
): void;
public static afterFind<M extends Model>(
this: { new(): M } & typeof Model,
fn: (instancesOrInstance: M[] | M | null, options: FindOptions) => HookReturn
this: ModelStatic<M>,
fn: (instancesOrInstance: M[] | M | null, options: FindOptions<M['_attributes']>) => HookReturn
): void;
/**
......@@ -2374,7 +2503,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param options Options for the association
*/
public static hasOne<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options?: HasOneOptions
this: ModelStatic<M>, target: ModelStatic<T>, options?: HasOneOptions
): HasOne<M, T>;
/**
......@@ -2387,7 +2516,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param options Options for the association
*/
public static belongsTo<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options?: BelongsToOptions
this: ModelStatic<M>, target: ModelStatic<T>, options?: BelongsToOptions
): BelongsTo<M, T>;
/**
......@@ -2434,16 +2563,17 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Similarily, 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?
* user.getProjects().then(projects => {
* const p1 = projects[0]
* p1.userprojects.started // Is this project started yet?
* })
* ```
*
* @param target The model that will be associated with hasOne relationship
* @param options Options for the association
*/
public static hasMany<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options?: HasManyOptions
this: ModelStatic<M>, target: ModelStatic<T>, options?: HasManyOptions
): HasMany<M, T>;
/**
......@@ -2485,9 +2615,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Similarily, 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 porjects = await user.getProjects();
* const p1 = projects[0];
* p1.userprojects.started // Is this project started yet?
* user.getProjects().then(projects => {
* const p1 = projects[0]
* p1.userprojects.started // Is this project started yet?
* })
* ```
*
* @param target The model that will be associated with hasOne relationship
......@@ -2495,7 +2626,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
*
*/
public static belongsToMany<M extends Model, T extends Model>(
this: ModelCtor<M>, target: ModelCtor<T>, options: BelongsToManyOptions
this: ModelStatic<M>, target: ModelStatic<T>, options: BelongsToManyOptions
): BelongsToMany<M, T>;
/**
......@@ -2512,7 +2643,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* Builds a new model instance.
* @param values an object of key value pairs
*/
constructor(values?: object, options?: BuildOptions);
constructor(values?: TCreationAttributes, options?: BuildOptions);
/**
* Get an object representing the query for this instance, use with `options.where`
......@@ -2522,12 +2653,12 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
/**
* Get the value of the underlying data value
*/
public getDataValue<K extends keyof this>(key: K): this[K];
public getDataValue<K extends keyof TModelAttributes>(key: K): TModelAttributes[K];
/**
* Update the underlying data value
*/
public setDataValue<K extends keyof this>(key: K, value: this[K]): void;
public setDataValue<K extends keyof TModelAttributes>(key: K, value: TModelAttributes[K]): void;
/**
* If no key is given, returns all values of the instance, also invoking virtual getters.
......@@ -2537,7 +2668,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
*
* @param options.plain If set to true, included instances will be returned as plain objects
*/
public get(options?: { plain?: boolean; clone?: boolean }): object;
public get(options?: { plain?: boolean; clone?: boolean }): TModelAttributes;
public get<K extends keyof this>(key: K, options?: { plain?: boolean; clone?: boolean }): this[K];
public get(key: string, options?: { plain?: boolean; clone?: boolean }): unknown;
......@@ -2565,10 +2696,10 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* @param options.raw If set to true, field and virtual setters will be ignored
* @param options.reset Clear all previously set data values
*/
public set<K extends keyof this>(key: K, value: this[K], options?: SetOptions): this;
public set(keys: Partial<this>, options?: SetOptions): this;
public setAttributes<K extends keyof this>(key: K, value: this[K], options?: SetOptions): this;
public setAttributes(keys: object, options?: SetOptions): this;
public set<K extends keyof TModelAttributes>(key: K, value: TModelAttributes[K], options?: SetOptions): this;
public set(keys: Partial<TModelAttributes>, options?: SetOptions): this;
public setAttributes<K extends keyof TModelAttributes>(key: K, value: TModelAttributes[K], options?: SetOptions): this;
public setAttributes(keys: Partial<TModelAttributes>, options?: SetOptions): this;
/**
* If changed is called with a string it will return a boolean indicating whether the value of that key in
......@@ -2598,7 +2729,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
*
* This method is not aware of eager loaded associations. In other words, if some other model instance (child) was eager loaded with this instance (parent), and you change something in the child, calling `save()` will simply ignore the change that happened on the child.
*/
public save(options?: SaveOptions): Promise<this>;
public save(options?: SaveOptions<TModelAttributes>): Promise<this>;
/**
* Refresh the current instance in-place, i.e. update the object with current data from the DB and return
......@@ -2606,7 +2737,7 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* return a new instance. With this method, all references to the Instance are updated with the new data
* and no new objects are created.
*/
public reload(options?: FindOptions): Promise<this>;
public reload(options?: FindOptions<TModelAttributes>): Promise<this>;
/**
* Validate the attribute of this instance according to validation rules set in the model definition.
......@@ -2621,8 +2752,8 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
/**
* This is the same as calling `set` and then calling `save`.
*/
public update<K extends keyof this>(key: K, value: this[K], options?: InstanceUpdateOptions): Promise<this>;
public update(keys: object, options?: InstanceUpdateOptions): Promise<this>;
public update<K extends keyof this>(key: K, value: this[K], options?: InstanceUpdateOptions<TModelAttributes>): Promise<this>;
public update(keys: object, options?: InstanceUpdateOptions<TModelAttributes>): Promise<this>;
/**
* Destroy the row corresponding to this instance. Depending on your setting for paranoid, the row will
......@@ -2655,9 +2786,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* If an array is provided, the same is true for each column.
* If and object is provided, each column is incremented by the value given.
*/
public increment<K extends keyof this>(
fields: K | K[] | Partial<this>,
options?: IncrementDecrementOptionsWithBy
public increment<K extends keyof TModelAttributes>(
fields: K | K[] | Partial<TModelAttributes>,
options?: IncrementDecrementOptionsWithBy<TModelAttributes>
): Promise<this>;
/**
......@@ -2680,9 +2811,9 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
* If an array is provided, the same is true for each column.
* If and object is provided, each column is decremented by the value given
*/
public decrement<K extends keyof this>(
fields: K | K[] | Partial<this>,
options?: IncrementDecrementOptionsWithBy
public decrement<K extends keyof TModelAttributes>(
fields: K | K[] | Partial<TModelAttributes>,
options?: IncrementDecrementOptionsWithBy<TModelAttributes>
): Promise<this>;
/**
......@@ -2713,6 +2844,11 @@ export abstract class Model<T = any, T2 = any> extends Hooks {
export type ModelType = typeof Model;
export type ModelCtor<M extends Model> = { new(): M } & ModelType;
// Do not switch the order of `typeof Model` and `{ new(): M }`. For
// instances created by `sequelize.define` to typecheck well, `typeof Model`
// must come first for unknown reasons.
export type ModelCtor<M extends Model> = typeof Model & { new(): M };
export type ModelStatic<M extends Model> = { new(): M };
export default Model;
import { DataType } from './data-types';
import { Logging, Model, ModelAttributeColumnOptions, ModelAttributes, Transactionable, WhereOptions, Filterable, Poolable } from './model';
import {
Logging,
Model,
ModelAttributeColumnOptions,
ModelAttributes,
Transactionable,
WhereOptions,
Filterable,
Poolable,
ModelCtor, ModelStatic
} from './model';
import QueryTypes = require('./query-types');
import { Sequelize, RetryOptions } from './sequelize';
import { Transaction } from './transaction';
......@@ -71,15 +81,15 @@ export interface QueryOptions extends Logging, Transactionable, Poolable {
fieldMap?: FieldMap;
}
export interface QueryOptionsWithWhere extends QueryOptions, Filterable {
export interface QueryOptionsWithWhere extends QueryOptions, Filterable<any> {
}
export interface QueryOptionsWithModel extends QueryOptions {
export interface QueryOptionsWithModel<M extends Model> extends QueryOptions {
/**
* A sequelize model used to build the returned model instances (used to be called callee)
*/
model: typeof Model;
model: ModelStatic<M>;
}
export interface QueryOptionsWithType<T extends QueryTypes> extends QueryOptions {
......@@ -189,7 +199,7 @@ export interface IndexesOptions {
/**
* Optional where parameter for index. Can be used to limit the index to certain rows.
*/
where?: WhereOptions;
where?: WhereOptions<any>;
/**
* Prefix to append to the index name.
......@@ -215,7 +225,7 @@ export interface AddDefaultConstraintOptions extends BaseConstraintOptions {
export interface AddCheckConstraintOptions extends BaseConstraintOptions {
type: 'check';
where?: WhereOptions;
where?: WhereOptions<any>;
}
export interface AddPrimaryKeyConstraintOptions extends BaseConstraintOptions {
......@@ -321,9 +331,9 @@ export class QueryInterface {
* @param attributes Hash of attributes, key is attribute name, value is data type
* @param options Table options.
*/
public createTable(
public createTable<M extends Model>(
tableName: string | { schema?: string; tableName?: string },
attributes: ModelAttributes,
attributes: ModelAttributes<M, M['_creationAttributes']>,
options?: QueryInterfaceCreateTableOptions
): Promise<void>;
......@@ -490,11 +500,11 @@ export class QueryInterface {
/**
* Updates a row
*/
public update(
instance: Model,
public update<M extends Model>(
instance: M,
tableName: TableName,
values: object,
identifier: WhereOptions,
identifier: WhereOptions<M['_attributes']>,
options?: QueryOptions
): Promise<object>;
......@@ -504,7 +514,7 @@ export class QueryInterface {
public bulkUpdate(
tableName: TableName,
values: object,
identifier: WhereOptions,
identifier: WhereOptions<any>,
options?: QueryOptions,
attributes?: string[] | string
): Promise<object>;
......@@ -512,14 +522,19 @@ export class QueryInterface {
/**
* Deletes a row
*/
public delete(instance: Model | null, tableName: TableName, identifier: WhereOptions, options?: QueryOptions): Promise<object>;
public delete(
instance: Model | null,
tableName: TableName,
identifier: WhereOptions<any>,
options?: QueryOptions
): Promise<object>;
/**
* Deletes multiple rows at once
*/
public bulkDelete(
tableName: TableName,
identifier: WhereOptions,
identifier: WhereOptions<any>,
options?: QueryOptions,
model?: typeof Model
): Promise<object>;
......@@ -532,11 +547,11 @@ export class QueryInterface {
/**
* Increments a row value
*/
public increment(
public increment<M extends Model>(
instance: Model,
tableName: TableName,
values: object,
identifier: WhereOptions,
identifier: WhereOptions<M['_attributes']>,
options?: QueryOptions
): Promise<object>;
......
......@@ -371,7 +371,7 @@ export interface Options extends Logging {
/**
* Sets global permanent hooks.
*/
hooks?: Partial<SequelizeHooks>;
hooks?: Partial<SequelizeHooks<Model, any, any>>;
/**
* Set to `true` to automatically minify aliases generated by sequelize.
......@@ -517,8 +517,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static beforeCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public static beforeCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
public static beforeCreate(name: string, fn: (attributes: Model, options: CreateOptions<any>) => void): void;
public static beforeCreate(fn: (attributes: Model, options: CreateOptions<any>) => void): void;
/**
* A hook that is run after creating a single instance
......@@ -526,8 +526,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with attributes, options
*/
public static afterCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public static afterCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
public static afterCreate(name: string, fn: (attributes: Model, options: CreateOptions<any>) => void): void;
public static afterCreate(fn: (attributes: Model, options: CreateOptions<any>) => void): void;
/**
* A hook that is run before destroying a single instance
......@@ -553,8 +553,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public static beforeUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
public static beforeUpdate(name: string, fn: (instance: Model, options: UpdateOptions<any>) => void): void;
public static beforeUpdate(fn: (instance: Model, options: UpdateOptions<any>) => void): void;
/**
* A hook that is run after updating a single instance
......@@ -562,8 +562,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public static afterUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
public static afterUpdate(name: string, fn: (instance: Model, options: UpdateOptions<any>) => void): void;
public static afterUpdate(fn: (instance: Model, options: UpdateOptions<any>) => void): void;
/**
* A hook that is run before creating or updating a single instance, It proxies `beforeCreate` and `beforeUpdate`
......@@ -571,8 +571,11 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instance, options
*/
public static beforeSave(name: string, fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
public static beforeSave(fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
public static beforeSave(
name: string,
fn: (instance: Model, options: UpdateOptions<any> | CreateOptions<any>) => void
): void;
public static beforeSave(fn: (instance: Model, options: UpdateOptions<any> | CreateOptions<any>) => void): void;
/**
* A hook that is run after creating or updating a single instance, It proxies `afterCreate` and `afterUpdate`
......@@ -580,8 +583,13 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instance, options
*/
public static afterSave(name: string, fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
public static afterSave(fn: (instance: Model, options: UpdateOptions | CreateOptions) => void): void;
public static afterSave(
name: string,
fn: (instance: Model, options: UpdateOptions<any> | CreateOptions<any>) => void
): void;
public static afterSave(
fn: (instance: Model, options: UpdateOptions<any> | CreateOptions<any>) => void
): void;
/**
* A hook that is run before creating instances in bulk
......@@ -589,8 +597,11 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instances, options
*/
public static beforeBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public static beforeBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public static beforeBulkCreate(
name: string,
fn: (instances: Model[], options: BulkCreateOptions<any>) => void
): void;
public static beforeBulkCreate(fn: (instances: Model[], options: BulkCreateOptions<any>) => void): void;
/**
* A hook that is run after creating instances in bulk
......@@ -598,8 +609,10 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instances, options
*/
public static afterBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public static afterBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public static afterBulkCreate(
name: string, fn: (instances: Model[], options: BulkCreateOptions<any>) => void
): void;
public static afterBulkCreate(fn: (instances: Model[], options: BulkCreateOptions<any>) => void): void;
/**
* A hook that is run before destroying instances in bulk
......@@ -607,8 +620,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions) => void): void;
public static beforeBulkDestroy(fn: (options: BulkCreateOptions) => void): void;
public static beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions<any>) => void): void;
public static beforeBulkDestroy(fn: (options: BulkCreateOptions<any>) => void): void;
/**
* A hook that is run after destroying instances in bulk
......@@ -616,8 +629,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkDestroy(name: string, fn: (options: DestroyOptions) => void): void;
public static afterBulkDestroy(fn: (options: DestroyOptions) => void): void;
public static afterBulkDestroy(name: string, fn: (options: DestroyOptions<any>) => void): void;
public static afterBulkDestroy(fn: (options: DestroyOptions<any>) => void): void;
/**
* A hook that is run after updating instances in bulk
......@@ -625,8 +638,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public static beforeBulkUpdate(fn: (options: UpdateOptions) => void): void;
public static beforeBulkUpdate(name: string, fn: (options: UpdateOptions<any>) => void): void;
public static beforeBulkUpdate(fn: (options: UpdateOptions<any>) => void): void;
/**
* A hook that is run after updating instances in bulk
......@@ -634,8 +647,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static afterBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public static afterBulkUpdate(fn: (options: UpdateOptions) => void): void;
public static afterBulkUpdate(name: string, fn: (options: UpdateOptions<any>) => void): void;
public static afterBulkUpdate(fn: (options: UpdateOptions<any>) => void): void;
/**
* A hook that is run before a find (select) query
......@@ -643,8 +656,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFind(name: string, fn: (options: FindOptions) => void): void;
public static beforeFind(fn: (options: FindOptions) => void): void;
public static beforeFind(name: string, fn: (options: FindOptions<any>) => void): void;
public static beforeFind(fn: (options: FindOptions<any>) => void): void;
/**
* A hook that is run before a connection is established
......@@ -688,8 +701,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions) => void): void;
public static beforeFindAfterExpandIncludeAll(fn: (options: FindOptions) => void): void;
public static beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions<any>) => void): void;
public static beforeFindAfterExpandIncludeAll(fn: (options: FindOptions<any>) => void): void;
/**
* A hook that is run before a find (select) query, after all option parsing is complete
......@@ -697,8 +710,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public static beforeFindAfterOptions(name: string, fn: (options: FindOptions) => void): void;
public static beforeFindAfterOptions(fn: (options: FindOptions) => void): void;
public static beforeFindAfterOptions(name: string, fn: (options: FindOptions<any>) => void): void;
public static beforeFindAfterOptions(fn: (options: FindOptions<any>) => void): void;
/**
* A hook that is run after a find (select) query
......@@ -708,10 +721,10 @@ export class Sequelize extends Hooks {
*/
public static afterFind(
name: string,
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions<any>) => void
): void;
public static afterFind(
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions<any>) => void
): void;
/**
......@@ -722,10 +735,10 @@ export class Sequelize extends Hooks {
*/
public static beforeDefine<M extends Model>(
name: string,
fn: (attributes: ModelAttributes, options: ModelOptions<M>) => void
fn: (attributes: ModelAttributes<M, M['_creationAttributes']>, options: ModelOptions<M>) => void
): void;
public static beforeDefine<M extends Model>(
fn: (attributes: ModelAttributes, options: ModelOptions<M>) => void
fn: (attributes: ModelAttributes<M, M['_creationAttributes']>, options: ModelOptions<M>) => void
): void;
/**
......@@ -877,8 +890,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with attributes, options
*/
public beforeCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public beforeCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
public beforeCreate(name: string, fn: (attributes: Model, options: CreateOptions<any>) => void): void;
public beforeCreate(fn: (attributes: Model, options: CreateOptions<any>) => void): void;
/**
* A hook that is run after creating a single instance
......@@ -886,8 +899,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with attributes, options
*/
public afterCreate(name: string, fn: (attributes: Model, options: CreateOptions) => void): void;
public afterCreate(fn: (attributes: Model, options: CreateOptions) => void): void;
public afterCreate(name: string, fn: (attributes: Model, options: CreateOptions<any>) => void): void;
public afterCreate(fn: (attributes: Model, options: CreateOptions<any>) => void): void;
/**
* A hook that is run before destroying a single instance
......@@ -913,8 +926,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instance, options
*/
public beforeUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public beforeUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
public beforeUpdate(name: string, fn: (instance: Model, options: UpdateOptions<any>) => void): void;
public beforeUpdate(fn: (instance: Model, options: UpdateOptions<any>) => void): void;
/**
* A hook that is run after updating a single instance
......@@ -922,8 +935,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instance, options
*/
public afterUpdate(name: string, fn: (instance: Model, options: UpdateOptions) => void): void;
public afterUpdate(fn: (instance: Model, options: UpdateOptions) => void): void;
public afterUpdate(name: string, fn: (instance: Model, options: UpdateOptions<any>) => void): void;
public afterUpdate(fn: (instance: Model, options: UpdateOptions<any>) => void): void;
/**
* A hook that is run before creating instances in bulk
......@@ -931,8 +944,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instances, options
*/
public beforeBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public beforeBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public beforeBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions<any>) => void): void;
public beforeBulkCreate(fn: (instances: Model[], options: BulkCreateOptions<any>) => void): void;
/**
* A hook that is run after creating instances in bulk
......@@ -940,8 +953,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with instances, options
*/
public afterBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public afterBulkCreate(fn: (instances: Model[], options: BulkCreateOptions) => void): void;
public afterBulkCreate(name: string, fn: (instances: Model[], options: BulkCreateOptions<any>) => void): void;
public afterBulkCreate(fn: (instances: Model[], options: BulkCreateOptions<any>) => void): void;
/**
* A hook that is run before destroying instances in bulk
......@@ -949,8 +962,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions) => void): void;
public beforeBulkDestroy(fn: (options: BulkCreateOptions) => void): void;
public beforeBulkDestroy(name: string, fn: (options: BulkCreateOptions<any>) => void): void;
public beforeBulkDestroy(fn: (options: BulkCreateOptions<any>) => void): void;
/**
* A hook that is run after destroying instances in bulk
......@@ -958,8 +971,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public afterBulkDestroy(name: string, fn: (options: DestroyOptions) => void): void;
public afterBulkDestroy(fn: (options: DestroyOptions) => void): void;
public afterBulkDestroy(name: string, fn: (options: DestroyOptions<any>) => void): void;
public afterBulkDestroy(fn: (options: DestroyOptions<any>) => void): void;
/**
* A hook that is run after updating instances in bulk
......@@ -967,8 +980,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public beforeBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public beforeBulkUpdate(fn: (options: UpdateOptions) => void): void;
public beforeBulkUpdate(name: string, fn: (options: UpdateOptions<any>) => void): void;
public beforeBulkUpdate(fn: (options: UpdateOptions<any>) => void): void;
/**
* A hook that is run after updating instances in bulk
......@@ -976,8 +989,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public afterBulkUpdate(name: string, fn: (options: UpdateOptions) => void): void;
public afterBulkUpdate(fn: (options: UpdateOptions) => void): void;
public afterBulkUpdate(name: string, fn: (options: UpdateOptions<any>) => void): void;
public afterBulkUpdate(fn: (options: UpdateOptions<any>) => void): void;
/**
* A hook that is run before a find (select) query
......@@ -985,8 +998,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public beforeFind(name: string, fn: (options: FindOptions) => void): void;
public beforeFind(fn: (options: FindOptions) => void): void;
public beforeFind(name: string, fn: (options: FindOptions<any>) => void): void;
public beforeFind(fn: (options: FindOptions<any>) => void): void;
/**
* A hook that is run before a find (select) query, after any { include: {all: ...} } options are expanded
......@@ -994,8 +1007,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions) => void): void;
public beforeFindAfterExpandIncludeAll(fn: (options: FindOptions) => void): void;
public beforeFindAfterExpandIncludeAll(name: string, fn: (options: FindOptions<any>) => void): void;
public beforeFindAfterExpandIncludeAll(fn: (options: FindOptions<any>) => void): void;
/**
* A hook that is run before a find (select) query, after all option parsing is complete
......@@ -1003,8 +1016,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with options
*/
public beforeFindAfterOptions(name: string, fn: (options: FindOptions) => void): void;
public beforeFindAfterOptions(fn: (options: FindOptions) => void): void;
public beforeFindAfterOptions(name: string, fn: (options: FindOptions<any>) => void): void;
public beforeFindAfterOptions(fn: (options: FindOptions<any>) => void): void;
/**
* A hook that is run after a find (select) query
......@@ -1014,9 +1027,9 @@ export class Sequelize extends Hooks {
*/
public afterFind(
name: string,
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void
fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions<any>) => void
): void;
public afterFind(fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions) => void): void;
public afterFind(fn: (instancesOrInstance: Model[] | Model | null, options: FindOptions<any>) => void): void;
/**
* A hook that is run before a define call
......@@ -1024,8 +1037,8 @@ export class Sequelize extends Hooks {
* @param name
* @param fn A callback function that is called with attributes, options
*/
public beforeDefine(name: string, fn: (attributes: ModelAttributes, options: ModelOptions) => void): void;
public beforeDefine(fn: (attributes: ModelAttributes, options: ModelOptions) => void): void;
public beforeDefine(name: string, fn: (attributes: ModelAttributes<Model, any>, options: ModelOptions) => void): void;
public beforeDefine(fn: (attributes: ModelAttributes<Model, any>, options: ModelOptions) => void): void;
/**
* A hook that is run after a define call
......@@ -1151,7 +1164,11 @@ export class Sequelize extends Hooks {
* @param options These options are merged with the default define options provided to the Sequelize
* constructor
*/
public define(modelName: string, attributes: ModelAttributes, options?: ModelOptions): typeof Model;
public define<M extends Model, TCreationAttributes = M['_creationAttributes']>(
modelName: string,
attributes: ModelAttributes<M, TCreationAttributes>,
options?: ModelOptions
): ModelCtor<M>;
/**
* Fetch a Model which is already defined
......@@ -1216,7 +1233,7 @@ export class Sequelize extends Hooks {
public query(sql: string | { query: string; values: unknown[] }, options: QueryOptionsWithType<QueryTypes.DESCRIBE>): Promise<ColumnsDescription>;
public query<M extends Model>(
sql: string | { query: string; values: unknown[] },
options: QueryOptionsWithModel
options: QueryOptionsWithModel<M>
): Promise<M[]>;
public query<T extends object>(sql: string | { query: string; values: unknown[] }, options: QueryOptionsWithType<QueryTypes.SELECT> & { plain: true }): Promise<T>;
public query<T extends object>(sql: string | { query: string; values: unknown[] }, options: QueryOptionsWithType<QueryTypes.SELECT>): Promise<T[]>;
......@@ -1305,7 +1322,7 @@ export class Sequelize extends Hooks {
*
* @param [options] The options passed to Model.destroy in addition to truncate
*/
public truncate(options?: DestroyOptions): Promise<unknown[]>;
public truncate(options?: DestroyOptions<any>): Promise<unknown[]>;
/**
* Drop all tables defined through this sequelize instance. This is done by calling Model.drop on each model
......@@ -1435,14 +1452,14 @@ export function literal(val: string): Literal;
*
* @param args Each argument will be joined by AND
*/
export function and(...args: (WhereOperators | WhereAttributeHash | Where)[]): AndOperator;
export function and(...args: (WhereOperators | WhereAttributeHash<any> | Where)[]): AndOperator<any>;
/**
* An OR query
*
* @param args Each argument will be joined by OR
*/
export function or(...args: (WhereOperators | WhereAttributeHash | Where)[]): OrOperator;
export function or(...args: (WhereOperators | WhereAttributeHash<any> | Where)[]): OrOperator<any>;
/**
* Creates an object representing nested where conditions for postgres's json data-type.
......@@ -1455,7 +1472,7 @@ export function or(...args: (WhereOperators | WhereAttributeHash | Where)[]): Or
export function json(conditionsOrPath: string | object, value?: string | number | boolean): Json;
export type AttributeType = Fn | Col | Literal | ModelAttributeColumnOptions | string;
export type LogicType = Fn | Col | Literal | OrOperator | AndOperator | WhereOperators | string | symbol | null;
export type LogicType = Fn | Col | Literal | OrOperator<any> | AndOperator<any> | WhereOperators | string | symbol | null;
/**
* A way of specifying attr = condition.
......
import { DataType } from './data-types';
import { Model, WhereOptions } from './model';
import { Model, ModelCtor, WhereOptions } from './model';
export type Primitive = 'string' | 'number' | 'boolean';
......@@ -24,16 +24,21 @@ export function formatNamedParameters(sql: string, parameters: {
}, dialect: string): string;
export function cloneDeep<T>(obj: T, fn?: (el: unknown) => unknown): T;
export interface OptionsForMapping {
export interface OptionsForMapping<TAttributes> {
attributes?: string[];
where?: WhereOptions;
where?: WhereOptions<TAttributes>;
}
/** Expand and normalize finder options */
export function mapFinderOptions<T extends OptionsForMapping>(options: T, model: typeof Model): T;
export function mapFinderOptions<M extends Model, T extends OptionsForMapping<M['_attributes']>>(
options: T,
model: ModelCtor<M>
): T;
/* Used to map field names in attributes and where conditions */
export function mapOptionFieldNames<T extends OptionsForMapping>(options: T, model: typeof Model): T;
export function mapOptionFieldNames<M extends Model, T extends OptionsForMapping<M['_attributes']>>(
options: T, model: ModelCtor<M>
): T;
export function mapWhereFieldNames(attributes: object, model: typeof Model): object;
/** Used to map field names in values */
......
import { DataTypes, Model } from 'sequelize';
import { BuildOptions, DataTypes, Model } from 'sequelize';
import { sequelize } from './connection';
// I really wouldn't recommend this, but if you want you can still use define() and interfaces
interface User extends Model {
id: number;
username: string;
firstName: string;
lastName: string;
createdAt: Date;
updatedAt: Date;
interface UserAttributes {
id: number;
username: string;
firstName: string;
lastName: string;
createdAt: Date;
updatedAt: Date;
}
type UserModel = {
new (): User
customStaticMethod(): unknown
} & typeof Model;
interface UserCreationAttributes extends Partial<UserAttributes> {}
const User = sequelize.define('User', { firstName: DataTypes.STRING }, { tableName: 'users' }) as UserModel;
interface UserModel extends Model<UserAttributes, UserCreationAttributes>, UserAttributes {}
async function test() {
User.customStaticMethod();
const User = sequelize.define<UserModel>(
'User', { firstName: DataTypes.STRING }, { tableName: 'users' });
const user: User = new User();
async function test() {
const user: UserModel = new User() as UserModel;
const user2: User = (await User.findOne()) as User;
const user2: UserModel | null = await User.findOne();
if (!user2) return;
user2.firstName = 'John';
await user2.save();
}
// The below doesn't define Attribute types, but should still work
interface UntypedUserModel extends Model, UserAttributes {}
type UntypedUserModelStatic = typeof Model & {
new (values?: keyof any, options?: BuildOptions): UntypedUserModel;
customStaticMethod(): unknown;
}
const UntypedUser = sequelize.define<UntypedUserModel>(
'User', { firstName: DataTypes.STRING }, { tableName: 'users' }) as UntypedUserModelStatic;
UntypedUser.customStaticMethod = () => {};
async function testUntyped() {
UntypedUser.customStaticMethod();
const user: UntypedUserModel = new UntypedUser() as UntypedUserModel;
const user2: UntypedUserModel | null = await UntypedUser.findOne();
if (!user2) return;
user2.firstName = 'John';
await user2.save();
}
// This file is used as example.
import {BuildOptions, DataTypes, Model, Sequelize} from 'sequelize';
import { BuildOptions, DataTypes, Model, Sequelize } from 'sequelize';
import {
Association,
HasManyAddAssociationMixin,
......
......@@ -5,7 +5,7 @@ import { OptimisticLockError } from '../lib/errors';
async function test() {
try {
await User.create({ username: 'john_doe' });
await User.create({ username: 'john_doe', firstName: 'John' });
} catch (e) {
if (e instanceof UniqueConstraintError) {
throw new Error((e as UniqueConstraintError).sql);
......
import { User } from "./models/User";
User.findOne({ where: { firstName: 'John' }});
// The below line should be an error if uncommented, thanks to the new
// TAttributes-based typechecking
// User.findOne({ where: { blah: 'blah2' }});
......@@ -7,11 +7,26 @@ import {
FindOptions,
Model,
ModelCtor,
Op
Op,
Optional
} from 'sequelize';
import { sequelize } from '../connection';
export class User extends Model {
export interface UserAttributes {
id: number;
username: string;
firstName: string;
lastName: string;
groupId: number;
}
/**
* In this case, we make every single field optional. In real cases, only
* fields that have default/autoincrement values should be made optional.
*/
export interface UserCreationAttributes extends Optional<UserAttributes, 'id' | 'username' | 'lastName' | 'groupId'> {}
export class User extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
public static associations: {
group: BelongsTo<User, UserGroup>;
};
......@@ -20,11 +35,11 @@ export class User extends Model {
public username!: string;
public firstName!: string;
public lastName!: string;
public groupId!: number;
public createdAt!: Date;
public updatedAt!: Date;
// mixins for association (optional)
public groupId!: number;
public group?: UserGroup;
public getGroup!: BelongsToGetAssociationMixin<UserGroup>;
public setGroup!: BelongsToSetAssociationMixin<UserGroup, number>;
......@@ -36,6 +51,7 @@ User.init(
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
username: DataTypes.STRING,
groupId: DataTypes.NUMBER,
},
{
version: true,
......@@ -86,7 +102,7 @@ User.afterFind((users, options) => {
});
// TODO: VSCode shows the typing being correctly narrowed but doesn't do it correctly
User.addHook('beforeFind', 'test', (options: FindOptions) => {
User.addHook('beforeFind', 'test', (options: FindOptions<UserAttributes>) => {
return undefined;
});
......
......@@ -14,6 +14,8 @@ import {
} from 'sequelize';
import { sequelize } from '../connection';
// This class doesn't extend the generic Model<TAttributes>, but should still
// function just fine, with a bit less safe type-checking
export class UserGroup extends Model {
public static associations: {
users: HasMany<UserGroup, User>
......
import { Config, Sequelize, Model, QueryTypes } from 'sequelize';
import { Config, Sequelize, Model, QueryTypes, ModelCtor } from 'sequelize';
import { Fn } from '../lib/utils';
Sequelize.useCLS({
......@@ -6,7 +6,7 @@ Sequelize.useCLS({
export const sequelize = new Sequelize({
hooks: {
afterConnect: (connection, config: Config) => {
afterConnect: (connection: unknown, config: Config) => {
// noop
}
},
......@@ -56,7 +56,7 @@ const rnd: Fn = sequelize.random();
class Model1 extends Model{}
class Model2 extends Model{}
const myModel: typeof Model1 = sequelize.models.asd;
const myModel: ModelCtor<Model1> = sequelize.models.asd;
myModel.hasOne(Model2)
myModel.findAll();
......
......@@ -8,7 +8,7 @@ async function trans() {
transaction.afterCommit(() => console.log('transaction complete'));
User.create(
{
data: 123,
firstName: 'John',
},
{
transaction,
......
......@@ -25,7 +25,7 @@ where = {
date: new Date()
};
// Optional values
// Optional values
let whereWithOptionals: { needed: number; optional?: number } = { needed: 2 };
where = whereWithOptionals;
......@@ -39,10 +39,16 @@ where = whereWithOptionals;
const and: AndOperator = {
[Op.and]: { a: 5 }, // AND (a = 5)
};
const typedAnd: AndOperator<{ a: number }> = {
[Op.and]: { a: 5 }, // AND (a = 5)
};
const or: OrOperator = {
[Op.or]: [{ a: 5 }, { a: 6 }], // (a = 5 OR a = 6)
};
const typedOr: OrOperator<{ a: number }> = {
[Op.or]: [{ a: 5 }, { a: 6 }], // (a = 5 OR a = 6)
};
let operators: WhereOperators = {
[Op.gt]: 6, // > 6
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!