From 842dc54a34af058e3b05da1a7bd8fb589def5308 Mon Sep 17 00:00:00 2001 From: Andrew Sidhu Date: Mon, 29 Sep 2025 14:04:28 -0400 Subject: [PATCH 1/3] Refactor Sequelize model definitions and setup --- src/sscce-sequelize-7.ts | 256 +++++++++++++++++++++++++++++++++++---- 1 file changed, 232 insertions(+), 24 deletions(-) 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(); + } } From 77839334175271d6d2183a22a628d3ce8af0c659 Mon Sep 17 00:00:00 2001 From: Andrew Sidhu Date: Mon, 29 Sep 2025 14:05:26 -0400 Subject: [PATCH 2/3] Update createSequelize7Instance to use AbstractDialect --- dev/create-sequelize-instance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/create-sequelize-instance.ts b/dev/create-sequelize-instance.ts index 1ec6d6438..a34e13977 100644 --- a/dev/create-sequelize-instance.ts +++ b/dev/create-sequelize-instance.ts @@ -7,7 +7,7 @@ export function createSequelize6Instance(options?: Sequelize6Options): Sequelize return new Sequelize6(wrapOptions(options)); } -export function createSequelize7Instance(options?: Sequelize7Options): Sequelize7 { +export function createSequelize7Instance(options?: Sequelize7Options): Sequelize7 { // not compatible with node 10 const { Sequelize: Sequelize7Constructor } = require('@sequelize/core'); // @ts-expect-error -- wrapOptions expect sequelize 6. From 49d6c492eeedaaabd77975f44b66e710272a5233 Mon Sep 17 00:00:00 2001 From: Andrew Sidhu Date: Mon, 29 Sep 2025 14:16:47 -0400 Subject: [PATCH 3/3] revert typing --- dev/create-sequelize-instance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/create-sequelize-instance.ts b/dev/create-sequelize-instance.ts index a34e13977..1ec6d6438 100644 --- a/dev/create-sequelize-instance.ts +++ b/dev/create-sequelize-instance.ts @@ -7,7 +7,7 @@ export function createSequelize6Instance(options?: Sequelize6Options): Sequelize return new Sequelize6(wrapOptions(options)); } -export function createSequelize7Instance(options?: Sequelize7Options): Sequelize7 { +export function createSequelize7Instance(options?: Sequelize7Options): Sequelize7 { // not compatible with node 10 const { Sequelize: Sequelize7Constructor } = require('@sequelize/core'); // @ts-expect-error -- wrapOptions expect sequelize 6.