diff --git a/src/sscce-sequelize-7.ts b/src/sscce-sequelize-7.ts index 603cb219c..8a38bb0a3 100644 --- a/src/sscce-sequelize-7.ts +++ b/src/sscce-sequelize-7.ts @@ -1,43 +1,251 @@ -import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from '@sequelize/core'; -import { Attribute, NotNull } from '@sequelize/core/decorators-legacy'; -import { createSequelize7Instance } from '../dev/create-sequelize-instance'; -import { expect } from 'chai'; -import sinon from 'sinon'; +import { + CreationOptional, + DataTypes, + InferAttributes, + InferCreationAttributes, + Model, +} from "@sequelize/core"; +import { createSequelize7Instance } from "../dev/create-sequelize-instance"; +import { expect } from "chai"; // if your issue is dialect specific, remove the dialects you don't need to test on. -export const testingOnDialects = new Set(['mssql', 'sqlite', 'mysql', 'mariadb', 'postgres', 'postgres-native']); +export const testingOnDialects = new Set(["postgres"]); -// You can delete this file if you don't want your SSCCE to be tested against Sequelize 7 +class Location extends Model< + InferAttributes, + InferCreationAttributes +> { + declare id: CreationOptional; + declare name: string; + + declare customers?: Customer[]; + declare systems?: System[]; +} + +class Customer extends Model< + InferAttributes, + InferCreationAttributes +> { + declare id: CreationOptional; + declare name: string; + + declare locations?: Location[]; +} + +class System extends Model< + InferAttributes, + InferCreationAttributes +> { + declare id: CreationOptional; + declare name: string; + declare locationId: number; + + declare location?: Location; + declare fuelDeliveries?: FuelDelivery[]; +} + +class FuelDelivery extends Model< + InferAttributes, + InferCreationAttributes +> { + declare id: CreationOptional; + declare product: string; + declare systemId: number; + + declare system?: System; +} + +class LocationCustomer extends Model< + InferAttributes, + InferCreationAttributes +> { + declare locationId: number; + declare customerId: number; +} // Your SSCCE goes inside this function. export async function run() { // This function should be used instead of `new Sequelize()`. // It applies the config for your SSCCE to work on CI. const sequelize = createSequelize7Instance({ - logQueryParameters: true, - benchmark: true, + minifyAliases: true, + dialect: "postgres", define: { - // For less clutter in the SSCCE + // Keep model definitions lean so the regression focus stays on include resolution. timestamps: false, }, }); - class Foo extends Model, InferCreationAttributes> { - declare id: CreationOptional; + Location.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + }, + { + sequelize, + tableName: "locations", + } + ); - @Attribute(DataTypes.TEXT) - @NotNull - declare name: string; - } + Customer.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + }, + { + sequelize, + tableName: "customers", + } + ); - sequelize.addModels([Foo]); + System.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + locationId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + tableName: "systems", + } + ); + + FuelDelivery.init( + { + id: { + type: DataTypes.INTEGER, + autoIncrement: true, + primaryKey: true, + }, + product: { + type: DataTypes.STRING, + allowNull: false, + }, + systemId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + }, + { + sequelize, + tableName: "fuel_deliveries", + } + ); + + LocationCustomer.init( + { + locationId: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + }, + customerId: { + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true, + }, + }, + { + sequelize, + tableName: "location_customers", + } + ); + + FuelDelivery.belongsTo(System, { as: "system", foreignKey: "systemId" }); + System.hasMany(FuelDelivery, { + as: "fuelDeliveries", + foreignKey: "systemId", + }); - // You can use sinon and chai assertions directly in your SSCCE. - const spy = sinon.spy(); - sequelize.afterBulkSync(() => spy()); - await sequelize.sync({ force: true }); - expect(spy).to.have.been.called; + System.belongsTo(Location, { as: "location", foreignKey: "locationId" }); + Location.hasMany(System, { as: "systems", foreignKey: "locationId" }); - console.log(await Foo.create({ name: 'TS foo' })); - expect(await Foo.count()).to.equal(1); + Location.belongsToMany(Customer, { + as: "customers", + through: LocationCustomer, + foreignKey: "locationId", + otherKey: "customerId", + }); + Customer.belongsToMany(Location, { + as: "locations", + through: LocationCustomer, + foreignKey: "customerId", + otherKey: "locationId", + }); + + try { + await sequelize.sync({ force: true }); + + const customer = await Customer.create({ name: "Propane Co-op" }); + const location = await Location.create({ name: "Rural Depot" }); + await LocationCustomer.create({ + customerId: customer.id, + locationId: location.id, + }); + + const system = await System.create({ + name: "Delivery System Alpha", + locationId: location.id, + }); + const delivery = await FuelDelivery.create({ + product: "Propane", + systemId: system.id, + }); + + const result = await FuelDelivery.findByPk(delivery.id, { + logging: console.log, + include: [ + { + association: "system", + required: true, + include: [ + { + association: "location", + required: true, + include: [ + { + association: "customers", + required: true, + }, + ], + }, + ], + }, + ], + }); + + expect(result).to.not.be.null; + expect(result!.system).to.not.be.undefined; + expect(result!.system!.location).to.not.be.undefined; + const customers = result!.system!.location!.customers; + expect(customers).to.not.be.undefined; + expect(customers).to.have.length(1); + expect(customers![0].id).to.equal(customer.id); + } finally { + await sequelize.close(); + } }