From ab6a8f4a29248decee029994129bc83d0c5d3e31 Mon Sep 17 00:00:00 2001 From: Ali Taheri Date: Sat, 10 Oct 2015 16:42:08 +0330 Subject: [PATCH] Added belongsToMany associations and tests --- sequelize/sequelize-tests.ts | 154 ++++++++++-- sequelize/sequelize.d.ts | 469 ++++++++++++++++++++++++++++++++++- 2 files changed, 603 insertions(+), 20 deletions(-) diff --git a/sequelize/sequelize-tests.ts b/sequelize/sequelize-tests.ts index 1b3ee4fce..cda4aff11 100644 --- a/sequelize/sequelize-tests.ts +++ b/sequelize/sequelize-tests.ts @@ -227,20 +227,20 @@ product.createWarehouse({ id: 1 }, { save: true, silent: true }).then(() => { }) // hasMany warehouse.getProducts(); -warehouse.getProducts({where: {}, scope: false}); -warehouse.getProducts({where: {}, scope: false}).then((products) => products[0].id); +warehouse.getProducts({ where: {}, scope: false }); +warehouse.getProducts({ where: {}, scope: false }).then((products) => products[0].id); warehouse.setProducts(); warehouse.setProducts([product]); -warehouse.setProducts([product], { validate: true }).then(() => {}); +warehouse.setProducts([product], { validate: true }).then(() => { }); warehouse.addProducts(); warehouse.addProducts([product]); -warehouse.addProducts([product, 2], { validate: false }).then(() => {}); +warehouse.addProducts([product, 2], { validate: false }).then(() => { }); warehouse.addProduct(); warehouse.addProduct(product); -warehouse.addProduct(2, { validate: true }).then(() => {}); +warehouse.addProduct(2, { validate: true }).then(() => { }); warehouse.createProduct(); warehouse.createProduct({ id: 1, name: 'baz' }); @@ -248,24 +248,98 @@ warehouse.createProduct({ id: 1 }, { silent: true }).then(() => { }); warehouse.removeProducts(); warehouse.removeProducts([product]); -warehouse.removeProducts([product, 2], { validate: false }).then(() => {}); +warehouse.removeProducts([product, 2], { validate: false }).then(() => { }); warehouse.removeProduct(); warehouse.removeProduct(product); -warehouse.removeProduct(2, { validate: true }).then(() => {}); +warehouse.removeProduct(2, { validate: true }).then(() => { }); warehouse.hasProducts([product]); -warehouse.hasProducts([product, 2], { scope: 'bar' }).then((result:boolean) => {}); +warehouse.hasProducts([product, 2], { scope: 'bar' }).then((result: boolean) => { }); warehouse.hasProduct(product); -warehouse.hasProduct(2, { scope: 'baz' }).then((result:boolean) => {}); +warehouse.hasProduct(2, { scope: 'baz' }).then((result: boolean) => { }); warehouse.countProducts(); -warehouse.countProducts({ scope: 'baz' }).then((result:number) => {}); +warehouse.countProducts({ scope: 'baz' }).then((result: number) => { }); + +// belongsToMany +warehouse.getBranches(); +warehouse.getBranches({ where: {} }); +warehouse.getBranches({ where: {} }).then((branches) => branches[0].rank); + +warehouse.setBranches(); +warehouse.setBranches([branch]); +warehouse.setBranches([branch, 2], { validate: true, distance: 1 }).then(() => { }); + +warehouse.addBranches(); +warehouse.addBranches([branch]); +warehouse.addBranches([branch, 2], { validate: false, distance: 1 }).then(() => { }); + +warehouse.addBranch(); +warehouse.addBranch(branch); +warehouse.addBranch(2, { validate: true, distance: 1 }).then(() => { }); + +warehouse.createBranch(); +warehouse.createBranch({ id: 1, address: 'baz' }); +warehouse.createBranch({ id: 1 }, { silent: true, distance: 1 }).then(() => { }); + +warehouse.removeBranches(); +warehouse.removeBranches([branch]); +warehouse.removeBranches([branch, 2], { validate: false }).then(() => { }); + +warehouse.removeBranch(); +warehouse.removeBranch(branch); +warehouse.removeBranch(2, { validate: true }).then(() => { }); + +warehouse.hasBranches([branch]); +warehouse.hasBranches([branch, 2], { scope: 'bar' }).then((result: boolean) => { }); + +warehouse.hasBranch(branch); +warehouse.hasBranch(2, { scope: 'baz' }).then((result: boolean) => { }); + +warehouse.countBranches(); +warehouse.countBranches({ scope: 'baz' }).then((result: number) => { }); + +// belongsToMany +customer.getBranches(); +customer.getBranches({ where: {} }); +customer.getBranches({ where: {} }).then((branches) => branches[0].rank); + +customer.setBranches(); +customer.setBranches([branch]); +customer.setBranches([branch, 2], { validate: true }).then(() => { }); + +customer.addBranches(); +customer.addBranches([branch]); +customer.addBranches([branch, 2], { validate: false }).then(() => { }); + +customer.addBranch(); +customer.addBranch(branch); +customer.addBranch(2, { validate: true }).then(() => { }); + +customer.createBranch(); +customer.createBranch({ id: 1, address: 'baz' }); +customer.createBranch({ id: 1 }, { silent: true }).then(() => { }); + +customer.removeBranches(); +customer.removeBranches([branch]); +customer.removeBranches([branch, 2], { validate: false }).then(() => { }); + +customer.removeBranch(); +customer.removeBranch(branch); +customer.removeBranch(2, { validate: true }).then(() => { }); + +customer.hasBranches([branch]); +customer.hasBranches([branch, 2], { scope: 'bar' }).then((result: boolean) => { }); + +customer.hasBranch(branch); +customer.hasBranch(2, { scope: 'baz' }).then((result: boolean) => { }); + +customer.countBranches(); +customer.countBranches({ scope: 'baz' }).then((result: number) => { }); -// TODO: belongsToMany -// TODO: belongsToMany interface ProductAttributes { id?: number; @@ -316,28 +390,76 @@ interface WarehouseInstance extends Sequelize.Instance; hasProducts: Sequelize.HasManyHasAssociationsMixin; countProducts: Sequelize.HasManyCountAssociationsMixin; + + // belongsToMany association mixins: + getBranches: Sequelize.BelongsToManyGetAssociationsMixin; + setBranches: Sequelize.BelongsToManySetAssociationsMixin; + addBranches: Sequelize.BelongsToManyAddAssociationsMixin; + addBranch: Sequelize.BelongsToManyAddAssociationMixin; + createBranch: Sequelize.BelongsToManyCreateAssociationMixin; + removeBranch: Sequelize.BelongsToManyRemoveAssociationMixin; + removeBranches: Sequelize.BelongsToManyRemoveAssociationsMixin; + hasBranch: Sequelize.BelongsToManyHasAssociationMixin; + hasBranches: Sequelize.BelongsToManyHasAssociationsMixin; + countBranches: Sequelize.BelongsToManyCountAssociationsMixin; }; interface BranchAttributes { - + id?: number; + address?: string; + rank?: number; }; interface BranchInstance extends Sequelize.Instance, BranchAttributes { + // belongsToMany association mixins: + getWarehouses: Sequelize.BelongsToManyGetAssociationsMixin; + setWarehouses: Sequelize.BelongsToManySetAssociationsMixin; + addWarehouses: Sequelize.BelongsToManyAddAssociationsMixin; + addWarehouse: Sequelize.BelongsToManyAddAssociationMixin; + createWarehouse: Sequelize.BelongsToManyCreateAssociationMixin; + removeWarehouse: Sequelize.BelongsToManyRemoveAssociationMixin; + removeWarehouses: Sequelize.BelongsToManyRemoveAssociationsMixin; + hasWarehouse: Sequelize.BelongsToManyHasAssociationMixin; + hasWarehouses: Sequelize.BelongsToManyHasAssociationsMixin; + countWarehouses: Sequelize.BelongsToManyCountAssociationsMixin; + // belongsToMany association mixins: + getCustomers: Sequelize.BelongsToManyGetAssociationsMixin; + setCustomers: Sequelize.BelongsToManySetAssociationsMixin; + addCustomers: Sequelize.BelongsToManyAddAssociationsMixin; + addCustomer: Sequelize.BelongsToManyAddAssociationMixin; + createCustomer: Sequelize.BelongsToManyCreateAssociationMixin; + removeCustomer: Sequelize.BelongsToManyRemoveAssociationMixin; + removeCustomers: Sequelize.BelongsToManyRemoveAssociationsMixin; + hasCustomer: Sequelize.BelongsToManyHasAssociationMixin; + hasCustomers: Sequelize.BelongsToManyHasAssociationsMixin; + countCustomers: Sequelize.BelongsToManyCountAssociationsMixin; }; interface WarehouseBranchAttributes { - + distance?: number; }; interface WarehouseBranchInstance extends Sequelize.Instance, WarehouseBranchAttributes { }; interface CustomerAttributes { - + id?: number; + fullname?: string; + credit?: number; }; interface CustomerInstance extends Sequelize.Instance, CustomerAttributes { - + // belongsToMany association mixins: + getBranches: Sequelize.BelongsToManyGetAssociationsMixin; + setBranches: Sequelize.BelongsToManySetAssociationsMixin; + addBranches: Sequelize.BelongsToManyAddAssociationsMixin; + addBranch: Sequelize.BelongsToManyAddAssociationMixin; + createBranch: Sequelize.BelongsToManyCreateAssociationMixin; + removeBranch: Sequelize.BelongsToManyRemoveAssociationMixin; + removeBranches: Sequelize.BelongsToManyRemoveAssociationsMixin; + hasBranch: Sequelize.BelongsToManyHasAssociationMixin; + hasBranches: Sequelize.BelongsToManyHasAssociationsMixin; + countBranches: Sequelize.BelongsToManyCountAssociationsMixin; }; // diff --git a/sequelize/sequelize.d.ts b/sequelize/sequelize.d.ts index 2b6b4178e..a0a567eca 100644 --- a/sequelize/sequelize.d.ts +++ b/sequelize/sequelize.d.ts @@ -341,7 +341,7 @@ declare module "sequelize" { * Set the associated models by passing an array of instances or their primary keys. * Everything that it not in the passed array will be un-associated. * @param newAssociations An array of instances or primary key of instances to associate with this. Pass null or undefined to remove all associations. - * @param Options passed to `target.findAll` and `update`. + * @param options The options passed to `target.findAll` and `update`. */ ( newAssociations?: Array, @@ -390,7 +390,7 @@ declare module "sequelize" { /** * Associate several instances with this. * @param newAssociations An array of instances or primary key of instances to associate with this. - * @param options The pptions passed to `target.update`. + * @param options The options passed to `target.update`. */ ( newAssociations?: Array, @@ -439,7 +439,7 @@ declare module "sequelize" { /** * Associate an instance with this. * @param newAssociation An instance or the primary key of an instance to associate with this. - * @param Options passed to `target.update`. + * @param options The options passed to `target.update`. */ ( newAssociation?: TInstance | TInstancePrimaryKey, @@ -712,7 +712,468 @@ declare module "sequelize" { (options?: HasManyCountAssociationsMixinOptions): Promise } - // TODO: BelongsToMany Associations + /** + * The options for the getAssociations mixin of the belongsToMany association. + * @see BelongsToManyGetAssociationsMixin + */ + interface BelongsToManyGetAssociationsMixinOptions { + + /** + * An optional where clause to limit the associated models. + */ + where?: WhereOptions; + + /** + * Apply a scope on the related model, or remove its default scope by passing false. + */ + scope?: string | boolean; + } + + /** + * The getAssociations mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * getRoles: Sequelize.BelongsToManyGetAssociationsMixin; + * // setRoles... + * // addRoles... + * // addRole... + * // createRole... + * // removeRole... + * // removeRoles... + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyGetAssociationsMixin { + /** + * Get everything currently associated with this, using an optional where clause. + * @param options The options to use when getting the associations. + */ + (options?: BelongsToManyGetAssociationsMixinOptions): Promise + } + + /** + * The options for the setAssociations mixin of the belongsToMany association. + * @see BelongsToManySetAssociationsMixin + */ + interface BelongsToManySetAssociationsMixinOptions { + + /** + * Run validation for the join model. + */ + validate?: boolean; + } + + /** + * The setAssociations mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * setRoles: Sequelize.BelongsToManySetAssociationsMixin; + * // addRoles... + * // addRole... + * // createRole... + * // removeRole... + * // removeRoles... + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManySetAssociationsMixin { + /** + * Set the associated models by passing an array of instances or their primary keys. + * Everything that it not in the passed array will be un-associated. + * @param newAssociations An array of instances or primary key of instances to associate with this. Pass null or undefined to remove all associations. + * @param options The options passed to `through.findAll`, `bulkCreate`, `update` and `destroy`. Can also hold additional attributes for the join table. + */ + ( + newAssociations?: Array, + options?: BelongsToManySetAssociationsMixinOptions | FindOptions | BulkCreateOptions | InstanceUpdateOptions | InstanceDestroyOptions | TJoinTableAttributes + ): Promise + } + + /** + * The options for the addAssociations mixin of the belongsToMany association. + * @see BelongsToManyAddAssociationsMixin + */ + interface BelongsToManyAddAssociationsMixinOptions { + + /** + * Run validation for the join model. + */ + validate?: boolean; + } + + /** + * The addAssociations mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * addRoles: Sequelize.BelongsToManyAddAssociationsMixin; + * // addRole... + * // createRole... + * // removeRole... + * // removeRoles... + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyAddAssociationsMixin { + /** + * Associate several instances with this. + * @param newAssociations An array of instances or primary key of instances to associate with this. + * @param options The options passed to `through.findAll`, `bulkCreate`, `update` and `destroy`. Can also hold additional attributes for the join table. + */ + ( + newAssociations?: Array, + options?: BelongsToManyAddAssociationsMixinOptions | FindOptions | BulkCreateOptions | InstanceUpdateOptions | InstanceDestroyOptions | TJoinTableAttributes + ): Promise + } + + /** + * The options for the addAssociation mixin of the belongsToMany association. + * @see BelongsToManyAddAssociationMixin + */ + interface BelongsToManyAddAssociationMixinOptions { + + /** + * Run validation for the join model. + */ + validate?: boolean; + } + + /** + * The addAssociation mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * addRole: Sequelize.BelongsToManyAddAssociationMixin; + * // createRole... + * // removeRole... + * // removeRoles... + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyAddAssociationMixin { + /** + * Associate an instance with this. + * @param newAssociation An instance or the primary key of an instance to associate with this. + * @param options The options passed to `through.findAll`, `bulkCreate`, `update` and `destroy`. Can also hold additional attributes for the join table. + */ + ( + newAssociation?: TInstance | TInstancePrimaryKey, + options?: BelongsToManyAddAssociationMixinOptions | FindOptions | BulkCreateOptions | InstanceUpdateOptions | InstanceDestroyOptions | TJoinTableAttributes + ): Promise + } + + /** + * The options for the createAssociation mixin of the belongsToMany association. + * @see BelongsToManyCreateAssociationMixin + */ + interface BelongsToManyCreateAssociationMixinOptions { } + + /** + * The createAssociation mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * // addRole... + * createRole: Sequelize.BelongsToManyCreateAssociationMixin; + * // removeRole... + * // removeRoles... + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyCreateAssociationMixin { + /** + * Create a new instance of the associated model and associate it with this. + * @param values The values used to create the association. + * @param options Options passed to `create` and `add`. Can also hold additional attributes for the join table. + */ + ( + values?: TAttributes, + options?: BelongsToManyCreateAssociationMixinOptions | CreateOptions | TJoinTableAttributes + ): Promise + } + + /** + * The options for the removeAssociation mixin of the belongsToMany association. + * @see BelongsToManyRemoveAssociationMixin + */ + interface BelongsToManyRemoveAssociationMixinOptions { } + + /** + * The removeAssociation mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * // addRole... + * // createRole... + * removeRole: Sequelize.BelongsToManyRemoveAssociationMixin; + * // removeRoles... + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyRemoveAssociationMixin { + /** + * Un-associate the instance. + * @param oldAssociated The instance or the primary key of the instance to un-associate. + * @param options The options passed to `through.destroy`. + */ + ( + oldAssociated?: TInstance | TInstancePrimaryKey, + options?: BelongsToManyRemoveAssociationMixinOptions | InstanceDestroyOptions + ): Promise + } + + /** + * The options for the removeAssociations mixin of the belongsToMany association. + * @see BelongsToManyRemoveAssociationsMixin + */ + interface BelongsToManyRemoveAssociationsMixinOptions { } + + /** + * The removeAssociations mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * // addRole... + * // createRole... + * // removeRole... + * removeRoles: Sequelize.BelongsToManyRemoveAssociationsMixin; + * // hasRole... + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyRemoveAssociationsMixin { + /** + * Un-associate several instances. + * @param oldAssociated An array of instances or primary key of instances to un-associate. + * @param options The options passed to `through.destroy`. + */ + ( + oldAssociateds?: Array, + options?: BelongsToManyRemoveAssociationsMixinOptions | InstanceDestroyOptions + ): Promise + } + + /** + * The options for the hasAssociation mixin of the belongsToMany association. + * @see BelongsToManyHasAssociationMixin + */ + interface BelongsToManyHasAssociationMixinOptions { } + + /** + * The hasAssociation mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * // addRole... + * // createRole... + * // removeRole... + * // removeRoles... + * hasRole: Sequelize.BelongsToManyHasAssociationMixin; + * // hasRoles... + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyHasAssociationMixin { + /** + * Check if an instance is associated with this. + * @param target The instance or the primary key of the instance to check. + * @param options The options passed to `getAssociations`. + */ + ( + target: TInstance | TInstancePrimaryKey, + options?: BelongsToManyHasAssociationMixinOptions | BelongsToManyGetAssociationsMixinOptions + ): Promise + } + + /** + * The options for the hasAssociations mixin of the belongsToMany association. + * @see BelongsToManyHasAssociationsMixin + */ + interface BelongsToManyHasAssociationsMixinOptions { } + + /** + * The removeAssociations mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * // addRole... + * // createRole... + * // removeRole... + * // removeRoles + * // hasRole... + * hasRoles: Sequelize.BelongsToManyHasAssociationsMixin; + * // countRoles... + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyHasAssociationsMixin { + /** + * Check if all instances are associated with this. + * @param targets An array of instances or primary key of instances to check. + * @param options The options passed to `getAssociations`. + */ + ( + targets: Array, + options?: BelongsToManyHasAssociationsMixinOptions | BelongsToManyGetAssociationsMixinOptions + ): Promise + } + + /** + * The options for the countAssociations mixin of the belongsToMany association. + * @see BelongsToManyCountAssociationsMixin + */ + interface BelongsToManyCountAssociationsMixinOptions { + + /** + * An optional where clause to limit the associated models. + */ + where?: WhereOptions; + + /** + * Apply a scope on the related model, or remove its default scope by passing false. + */ + scope?: string | boolean; + } + + /** + * The countAssociations mixin applied to models with belongsToMany. + * An example of usage is as follows: + * + * ```js + * + * User.belongsToMany(Role, { through: UserRole }); + * + * interface UserInstance extends Sequelize.Instance, UserAttributes { + * // getRoles... + * // setRoles... + * // addRoles... + * // addRole... + * // createRole... + * // removeRole... + * // removeRoles... + * // hasRole... + * // hasRoles... + * countRoles: Sequelize.BelongsToManyCountAssociationsMixin; + * } + * ``` + * + * @see http://docs.sequelizejs.com/en/latest/api/associations/belongs-to-many/ + * @see Instance + */ + interface BelongsToManyCountAssociationsMixin { + /** + * Count everything currently associated with this, using an optional where clause. + * @param options The options to use when counting the associations. + */ + (options?: BelongsToManyCountAssociationsMixinOptions): Promise + } /** * Foreign Key Options