Skip to content

Commit ebaa056

Browse files
Merge pull request #210 from RobinBuschmann/issue-209-scope-symbols
Issue 209 scope symbols
2 parents 67d720a + e043263 commit ebaa056

File tree

3 files changed

+107
-23
lines changed

3 files changed

+107
-23
lines changed

lib/utils/object.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ export function deepAssign(target: any, ...sources: any[]): any {
1515
.getOwnPropertyNames(source)
1616
.forEach(key => assign(key, target, source))
1717
;
18+
/* istanbul ignore next */
19+
if (Object.getOwnPropertySymbols) {
20+
Object
21+
.getOwnPropertySymbols(source)
22+
.forEach(key => assign(key, target, source))
23+
;
24+
}
1825
});
19-
2026
return target;
2127

22-
function assign(key: string | number, _target: any, _source: any): void {
28+
function assign(key: string | number | symbol, _target: any, _source: any): void {
2329
const sourceValue = _source[key];
2430

2531
if (sourceValue !== void 0) {

test/specs/scopes.spec.ts

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import {expect, use} from 'chai';
22
import * as chaiAsPromised from 'chai-as-promised';
3+
import {useFakeTimers} from 'sinon';
4+
import {Op} from 'sequelize';
35
import {createSequelize} from "../utils/sequelize";
46
import {getScopeOptions} from "../../lib/services/scopes";
57
import {ShoeWithScopes, SHOE_DEFAULT_SCOPE, SHOE_SCOPES} from "../models/ShoeWithScopes";
68
import {Manufacturer} from "../models/Manufacturer";
79
import {Person} from "../models/Person";
10+
import {Model} from '../../lib/models/Model';
11+
import {Table} from '../../lib/annotations/Table';
12+
import {Scopes} from '../../lib/annotations/Scopes';
13+
import {majorVersion} from '../../lib/utils/versioning';
14+
import {Column} from '../../lib/annotations/Column';
15+
import {UpdatedAt} from '../../lib/annotations/UpdatedAt';
16+
import chaiDatetime = require('chai-datetime');
817

918
use(chaiAsPromised);
19+
use(chaiDatetime);
1020

1121
describe('scopes', () => {
1222

@@ -92,30 +102,30 @@ describe('scopes', () => {
92102
it('should consider scopes and additional included model (object)', () =>
93103
expect(
94104
(ShoeWithScopes.scope('full') as typeof ShoeWithScopes)
95-
.findOne({
96-
include: [{
97-
model: Person,
98-
}]
99-
})
100-
.then(shoe => {
101-
expect(shoe).to.have.property('manufacturer').which.is.not.null;
102-
expect(shoe).to.have.property('manufacturer').which.have.property('brand', BRAND);
103-
expect(shoe).to.have.property('owner').which.is.not.null;
104-
})
105+
.findOne({
106+
include: [{
107+
model: Person,
108+
}]
109+
})
110+
.then(shoe => {
111+
expect(shoe).to.have.property('manufacturer').which.is.not.null;
112+
expect(shoe).to.have.property('manufacturer').which.have.property('brand', BRAND);
113+
expect(shoe).to.have.property('owner').which.is.not.null;
114+
})
105115
).not.to.be.rejected
106116
);
107117

108118
it('should consider scopes and additional included model (model)', () =>
109119
expect(
110120
(ShoeWithScopes.scope('full') as typeof ShoeWithScopes)
111-
.findOne({
112-
include: [Person]
113-
})
114-
.then(shoe => {
115-
expect(shoe).to.have.property('manufacturer').which.is.not.null;
116-
expect(shoe).to.have.property('manufacturer').which.have.property('brand', BRAND);
117-
expect(shoe).to.have.property('owner').which.is.not.null;
118-
})
121+
.findOne({
122+
include: [Person]
123+
})
124+
.then(shoe => {
125+
expect(shoe).to.have.property('manufacturer').which.is.not.null;
126+
expect(shoe).to.have.property('manufacturer').which.have.property('brand', BRAND);
127+
expect(shoe).to.have.property('owner').which.is.not.null;
128+
})
119129
).not.to.be.rejected
120130
);
121131

@@ -134,7 +144,7 @@ describe('scopes', () => {
134144
it('should not consider default scope due to unscoped call, but additonal includes (model)', () =>
135145

136146
(ShoeWithScopes
137-
.unscoped() as typeof ShoeWithScopes)
147+
.unscoped() as typeof ShoeWithScopes)
138148
.findOne({
139149
include: [Person]
140150
})
@@ -219,6 +229,55 @@ describe('scopes', () => {
219229

220230
});
221231

232+
if (majorVersion > 3) {
233+
234+
describe('with symbols', () => {
235+
const _sequelize = createSequelize(false);
236+
237+
@Scopes({
238+
bob: {where: {name: {[Op.like]: '%bob%'}}},
239+
updated: {where: {updated: {[Op.gt]: new Date(2000, 1)}}},
240+
})
241+
@Table
242+
class Person extends Model<Person> {
243+
244+
@Column
245+
name: string;
246+
247+
@UpdatedAt
248+
updated: Date;
249+
}
250+
251+
_sequelize.addModels([Person]);
252+
253+
beforeEach(() => _sequelize.sync({force: true}));
254+
255+
it('should consider symbols while finding elements', () => {
256+
return Person
257+
.create({name: '1bob2'})
258+
.then(() => Person.create({name: 'bob'}))
259+
.then(() => Person.create({name: 'bobby'}))
260+
.then(() => Person.create({name: 'robert'}))
261+
.then(() => (Person.scope('bob') as typeof Person).findAll())
262+
.then(persons => expect(persons).to.have.property('length', 3))
263+
;
264+
});
265+
266+
it('should consider symbols on timestamp column while finding elements', () => {
267+
const clock = useFakeTimers(+new Date());
268+
return Person
269+
.create({name: 'test'})
270+
.then(() => (Person.scope('updated') as typeof Person).findAll())
271+
.then(() => Person.findAll())
272+
.then(persons => expect(persons).to.have.property('length', 1))
273+
.then(() => clock.restore())
274+
;
275+
});
276+
277+
});
278+
}
279+
280+
222281
});
223282

224283
});

test/specs/utils/object.spec.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ describe('utils', () => {
1313
const childSourceA = {f: childSourceF};
1414
const childSourceB = {};
1515
const source1 = {a: childSourceA, b: childSourceB, c: 1, d: 'd', over: 'ride', regex: /reg/gim, notNull: null};
16-
const source2 = {e: 'für elisa', g: () => null, arr: [{h: 1}, {}, 'e'], over: 'ridden', nullable: null, notNull: 'notNull'};
16+
const source2 = {
17+
e: 'für elisa',
18+
g: () => null,
19+
arr: [{h: 1}, {}, 'e'],
20+
over: 'ridden',
21+
nullable: null,
22+
notNull: 'notNull'
23+
};
1724
const sourceKeys = [].concat(Object.keys(source1), Object.keys(source2));
1825

1926
it('should not be undefined', () => {
@@ -110,15 +117,27 @@ describe('utils', () => {
110117

111118
it('should keep prototype chain', () => {
112119
class Test {
113-
protoFn(): any {}
120+
protoFn(): any {
121+
}
114122
}
123+
115124
const copy = deepAssign({}, {test: new Test()});
116125

117126
expect(copy.test)
118127
.to.have.property('protoFn')
119128
.that.is.a('function');
120129
});
121130

131+
if (Object.getOwnPropertySymbols) {
132+
it('should copy symbol based objects', () => {
133+
const symbol = Symbol('test');
134+
const value = 'test';
135+
const copy = deepAssign({}, {[symbol]: value});
136+
137+
expect(copy[symbol]).to.equal(value);
138+
});
139+
}
140+
122141
});
123142

124143
});

0 commit comments

Comments
 (0)