Skip to content

Upgrade to Sequelize 6 #787

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
669 changes: 143 additions & 526 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
"glob": "7.1.2"
},
"devDependencies": {
"@types/bluebird": "3.5.25",
"@types/chai": "3.4.35",
"@types/chai-as-promised": "0.0.29",
"@types/chai-datetime": "0.0.30",
Expand All @@ -61,25 +60,24 @@
"nyc": "13.3.0",
"prettyjson": "1.2.1",
"reflect-metadata": "0.1.9",
"sequelize": "5.15.1",
"sequelize": "^6.0.0-beta.6",
"sinon": "1.17.7",
"sinon-chai": "2.8.0",
"source-map-support": "0.4.14",
"sqlite3": "4.0.4",
"sqlite3": "4.2.0",
"ts-node": "7.0.1",
"tslint": "5.14.0",
"typescript": "3.3.3",
"uuid-validate": "0.0.2"
},
"peerDependencies": {
"@types/bluebird": "*",
"@types/node": "*",
"@types/validator": "*",
"reflect-metadata": "*",
"sequelize": "^5.1.0"
"sequelize": "^6.0.0-beta.6"
},
"engines": {
"node": ">=0.8.15"
"node": ">=10.0.0"
},
"nyc": {
"lines": 85,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class BelongsToManyAssociation extends BaseAssociation {
const associatedClass = this.getAssociatedClass();
const throughOptions = this.getThroughOptions(sequelize);

const throughModel = typeof throughOptions === 'object' ? throughOptions.model : undefined;
const throughModel = typeof throughOptions === 'object' && typeof throughOptions.model !== "string" ? throughOptions.model : undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this change is necessary?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because throughOptions.model has type string | typeof Model. The subsequent code isn't designed to handle the string case. Since my goals were to start with the minimal set of changes to make the code compatible with Sequelize 6 beta.6, this was the smallest fix to make the compiler and test suite happy.

options.through = throughOptions;
options.foreignKey = getForeignKeyOptions(model, throughModel, this.options.foreignKey);
options.otherKey = getForeignKeyOptions(associatedClass, throughModel, this.options.otherKey);
Expand Down
6 changes: 3 additions & 3 deletions src/model/model/model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {InitOptions, Model as OriginModel, ModelAttributes, FindOptions, BuildOptions, Promise} from 'sequelize';
import {InitOptions, Model as OriginModel, ModelAttributes, FindOptions, BuildOptions} from 'sequelize';
import {capitalize} from '../../shared/string';
import {inferAlias} from '../../associations/alias-inference/alias-inference-service';
import {ModelNotInitializedError} from '../shared/model-not-initialized-error';
Expand All @@ -24,7 +24,7 @@ export abstract class Model<T = any, T2 = any> extends OriginModel<T, T2> {

static isInitialized = false;

static init(attributes: ModelAttributes, options: InitOptions): void {
static init(attributes: ModelAttributes, options: InitOptions): Model {
this.isInitialized = true;
// @ts-ignore
return super.init(attributes, options);
Expand Down Expand Up @@ -135,7 +135,7 @@ function isFunctionMember(propertyKey: string, target: any): boolean {

function isForbiddenMember(propertyKey: string): boolean {
const FORBIDDEN_KEYS = ['name', 'constructor', 'length', 'prototype', 'caller', 'arguments', 'apply',
'QueryInterface', 'QueryGenerator', 'init', 'replaceHookAliases', 'refreshAttributes', 'inspect'];
'queryInterface', 'queryGenerator', 'init', 'replaceHookAliases', 'refreshAttributes', 'inspect'];
return FORBIDDEN_KEYS.indexOf(propertyKey) !== -1;
}

Expand Down
1 change: 1 addition & 0 deletions src/model/shared/model-service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "reflect-metadata";
import {DataTypeAbstract, ModelOptions} from 'sequelize';

import {Model} from '../model/model';
Expand Down
1 change: 1 addition & 0 deletions src/sequelize/sequelize/sequelize-service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {basename, extname, join, parse} from "path";

import * as glob from "glob";
import {uniqueFilter} from "../../shared/array";
import {ModelMatch, SequelizeOptions} from "./sequelize-options";
Expand Down
3 changes: 1 addition & 2 deletions src/sequelize/sequelize/sequelize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class Sequelize extends OriginSequelize {
const options = association.getSequelizeOptions(model, this);
const associatedClass = this.model(association.getAssociatedClass());

if (!associatedClass.isInitialized) {
if (!associatedClass.sequelize) {
throw new ModelNotInitializedError(
associatedClass,
`Association between ${associatedClass.name} and ${model.name} cannot be resolved.`
Expand All @@ -81,7 +81,6 @@ export class Sequelize extends OriginSequelize {
}

private defineModels(models: ModelCtor[]): ModelCtor[] {

return models.map(model => {
const modelName = getModelName(model.prototype);
const attributes = getAttributes(model.prototype);
Expand Down
1 change: 0 additions & 1 deletion test/specs/association.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import {expect, use} from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import * as OriginSequelize from 'sequelize';
import * as Promise from 'bluebird';
import {createSequelize} from "../utils/sequelize";
import {
Sequelize, Model, Table, Column, BelongsToMany,
Expand Down
1 change: 0 additions & 1 deletion test/specs/instance-methods.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {expect} from 'chai';
import * as Promise from 'bluebird';
import {Model, Table, Column} from "../../src";
import {createSequelize} from "../utils/sequelize";

Expand Down
52 changes: 24 additions & 28 deletions test/specs/instance.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as Promise from 'bluebird';
import { expect, use } from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
import { useFakeTimers } from 'sinon';
Expand Down Expand Up @@ -654,9 +653,10 @@ describe('instance', () => {
it('should support updating a subset of attributes', () =>
User
.create({aNumber: 1, bNumber: 1})
// TODO Sequelize typings issue caused by sequelize/types/lib/model.d.ts on line 2394
// TODO The order of overloads is wrong
.tap((user) => User.update({bNumber: 2}, {where: {id: user.get('id') as any}}))
.then((user) => {
User.update({bNumber: 2}, {where: {id: user.get('id') }});
return user;
})
.then((user) => user.reload({attributes: ['bNumber']}))
.then((user) => {
expect(user.get('aNumber')).to.equal(1);
Expand Down Expand Up @@ -777,7 +777,7 @@ describe('instance', () => {
})
.then((lePlayer: Player) => {
expect(lePlayer.shoe).not.to.be.null;
return lePlayer.shoe.destroy().return(lePlayer);
return lePlayer.shoe.destroy().then(() => lePlayer);
})
.then((lePlayer) => lePlayer.reload() as any)
.then((lePlayer: Player) => {
Expand Down Expand Up @@ -809,7 +809,8 @@ describe('instance', () => {
.destroy()
.then(() => {
return leTeam.players[0].destroy();
}).return(leTeam);
})
.then(() => leTeam);
})
.then((leTeam) => leTeam.reload() as any)
.then((leTeam: Team) => {
Expand Down Expand Up @@ -1321,7 +1322,7 @@ describe('instance', () => {
.update(
{aNumber: 1},
{
where: {},
where: {},
// TODO silent options missing in UpdateOptions
['silent' as any]: true
}
Expand Down Expand Up @@ -1496,7 +1497,7 @@ describe('instance', () => {
describe('with version option', () => {

it("version column is updated by sequelize", () => {
let version = undefined;
let version: number | any;
UserWithCustomUpdatedAt
.sync()
.then(() => UserWithVersion.create({name: 'john doe'}))
Expand Down Expand Up @@ -1666,15 +1667,15 @@ describe('instance', () => {
it('saves many objects that each a have collection of eagerly loaded objects', () =>

Promise
.props({
bart: UserEager.create({username: 'bart', age: 20}),
lisa: UserEager.create({username: 'lisa', age: 20}),
detention1: ProjectEager.create({title: 'detention1', overdueDays: 0}),
detention2: ProjectEager.create({title: 'detention2', overdueDays: 0}),
exam1: ProjectEager.create({title: 'exam1', overdueDays: 0}),
exam2: ProjectEager.create({title: 'exam2', overdueDays: 0})
})
.then(({bart, lisa, detention1, detention2, exam1, exam2}) =>
.all([
UserEager.create({username: 'bart', age: 20}),
UserEager.create({username: 'lisa', age: 20}),
ProjectEager.create({title: 'detention1', overdueDays: 0}),
ProjectEager.create({title: 'detention2', overdueDays: 0}),
ProjectEager.create({title: 'exam1', overdueDays: 0}),
ProjectEager.create({title: 'exam2', overdueDays: 0})
])
.then(([bart, lisa, detention1, detention2, exam1, exam2]) =>
Promise
.all([
bart.$set('projects', [detention1, detention2]),
Expand All @@ -1686,13 +1687,10 @@ describe('instance', () => {
include: [ProjectEager]
}))
.then((simpsons) => {
let _bart;
let _lisa;

expect(simpsons.length).to.equal(2);

_bart = simpsons[0];
_lisa = simpsons[1];
const _bart = simpsons[0];
const _lisa = simpsons[1];

expect(_bart.projects).to.exist;
expect(_lisa.projects).to.exist;
Expand Down Expand Up @@ -2412,12 +2410,10 @@ describe('instance', () => {

describe('restore', () => {

it('returns an error if the model is not paranoid', () =>

User.create({username: 'Peter'}).then((user) =>
expect(() => user.restore()).to.throw(Error, 'Model is not paranoid')
)
);
it('returns an error if the model is not paranoid', async () => {
const user = await User.create({username: 'Peter'});
return expect(user.restore()).to.be.rejectedWith(Error, 'Model is not paranoid');
});

it('restores a previously deleted model', () => {

Expand Down
1 change: 0 additions & 1 deletion test/specs/model-methods.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {expect} from 'chai';
import * as Promise from 'bluebird';
import {Model, Table, Column} from "../../src";
import {createSequelize} from "../utils/sequelize";

Expand Down
5 changes: 2 additions & 3 deletions test/specs/model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {useFakeTimers, stub, spy} from 'sinon';
import * as sinonChai from 'sinon-chai';
import * as _ from 'lodash';
import * as moment from 'moment';
import * as Promise from 'bluebird';
import {Op, UniqueConstraintError} from 'sequelize';
import * as chaiAsPromised from 'chai-as-promised';
import {createSequelize} from "../utils/sequelize";
Expand Down Expand Up @@ -453,7 +452,7 @@ describe('model', () => {
return Promise.all([
User.create({username: 'tobi', email: '[email protected]'}),
User.create({username: 'tobi', email: '[email protected]'})]);
}).catch(UniqueConstraintError, (err) => {
}).catch((err) => {
expect(err.message).to.equal('User and email must be unique');
});
});
Expand Down Expand Up @@ -509,7 +508,7 @@ describe('model', () => {
return Promise.all([
User.create({userId: 1, email: '[email protected]'}),
User.create({userId: 1, email: '[email protected]'})]);
}).catch(UniqueConstraintError, (err) => {
}).catch((err) => {
expect(err.message).to.equal('User and email must be unique');
});
});
Expand Down