1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | 'use strict';
|
8 | const should = require('./init.js');
|
9 | const assert = require('assert');
|
10 |
|
11 | const jdb = require('../');
|
12 | const ModelBuilder = jdb.ModelBuilder;
|
13 | const DataSource = jdb.DataSource;
|
14 | const Memory = require('../lib/connectors/memory');
|
15 |
|
16 | const ModelDefinition = require('../lib/model-definition');
|
17 |
|
18 | describe('ModelDefinition class', function() {
|
19 | let memory;
|
20 | beforeEach(function() {
|
21 | memory = new DataSource({connector: Memory});
|
22 | });
|
23 |
|
24 | it('should be able to define plain models', function(done) {
|
25 | const modelBuilder = new ModelBuilder();
|
26 |
|
27 | const User = new ModelDefinition(modelBuilder, 'User', {
|
28 | name: 'string',
|
29 | bio: ModelBuilder.Text,
|
30 | approved: Boolean,
|
31 | joinedAt: Date,
|
32 | age: 'number',
|
33 | });
|
34 |
|
35 | User.build();
|
36 | assert.equal(User.properties.name.type, String);
|
37 | assert.equal(User.properties.bio.type, ModelBuilder.Text);
|
38 | assert.equal(User.properties.approved.type, Boolean);
|
39 | assert.equal(User.properties.joinedAt.type, Date);
|
40 | assert.equal(User.properties.age.type, Number);
|
41 |
|
42 | const json = User.toJSON();
|
43 | assert.equal(json.name, 'User');
|
44 | assert.equal(json.properties.name.type, 'String');
|
45 | assert.equal(json.properties.bio.type, 'Text');
|
46 | assert.equal(json.properties.approved.type, 'Boolean');
|
47 | assert.equal(json.properties.joinedAt.type, 'Date');
|
48 | assert.equal(json.properties.age.type, 'Number');
|
49 |
|
50 | assert.deepEqual(User.toJSON(), json);
|
51 |
|
52 | done();
|
53 | });
|
54 |
|
55 | it('should be able to define additional properties', function(done) {
|
56 | const modelBuilder = new ModelBuilder();
|
57 |
|
58 | const User = new ModelDefinition(modelBuilder, 'User', {
|
59 | name: 'string',
|
60 | bio: ModelBuilder.Text,
|
61 | approved: Boolean,
|
62 | joinedAt: Date,
|
63 | age: 'number',
|
64 | });
|
65 |
|
66 | User.build();
|
67 |
|
68 | let json = User.toJSON();
|
69 |
|
70 | User.defineProperty('id', {type: 'number', id: true});
|
71 | assert.equal(User.properties.name.type, String);
|
72 | assert.equal(User.properties.bio.type, ModelBuilder.Text);
|
73 | assert.equal(User.properties.approved.type, Boolean);
|
74 | assert.equal(User.properties.joinedAt.type, Date);
|
75 | assert.equal(User.properties.age.type, Number);
|
76 |
|
77 | assert.equal(User.properties.id.type, Number);
|
78 |
|
79 | json = User.toJSON();
|
80 | assert.deepEqual(json.properties.id, {type: 'Number', id: true});
|
81 |
|
82 | done();
|
83 | });
|
84 |
|
85 | it('should be able to define nesting models', function(done) {
|
86 | const modelBuilder = new ModelBuilder();
|
87 |
|
88 | const User = new ModelDefinition(modelBuilder, 'User', {
|
89 | name: String,
|
90 | bio: ModelBuilder.Text,
|
91 | approved: Boolean,
|
92 | joinedAt: Date,
|
93 | age: Number,
|
94 | address: {
|
95 | street: String,
|
96 | city: String,
|
97 | zipCode: String,
|
98 | state: String,
|
99 | },
|
100 | });
|
101 |
|
102 | User.build();
|
103 | assert.equal(User.properties.name.type, String);
|
104 | assert.equal(User.properties.bio.type, ModelBuilder.Text);
|
105 | assert.equal(User.properties.approved.type, Boolean);
|
106 | assert.equal(User.properties.joinedAt.type, Date);
|
107 | assert.equal(User.properties.age.type, Number);
|
108 | assert.equal(typeof User.properties.address.type, 'function');
|
109 |
|
110 | const json = User.toJSON();
|
111 | assert.equal(json.name, 'User');
|
112 | assert.equal(json.properties.name.type, 'String');
|
113 | assert.equal(json.properties.bio.type, 'Text');
|
114 | assert.equal(json.properties.approved.type, 'Boolean');
|
115 | assert.equal(json.properties.joinedAt.type, 'Date');
|
116 | assert.equal(json.properties.age.type, 'Number');
|
117 |
|
118 | assert.deepEqual(json.properties.address.type, {street: {type: 'String'},
|
119 | city: {type: 'String'},
|
120 | zipCode: {type: 'String'},
|
121 | state: {type: 'String'}});
|
122 |
|
123 | done();
|
124 | });
|
125 |
|
126 | it('should be able to define referencing models', function(done) {
|
127 | const modelBuilder = new ModelBuilder();
|
128 |
|
129 | const Address = modelBuilder.define('Address', {
|
130 | street: String,
|
131 | city: String,
|
132 | zipCode: String,
|
133 | state: String,
|
134 | });
|
135 | const User = new ModelDefinition(modelBuilder, 'User', {
|
136 | name: String,
|
137 | bio: ModelBuilder.Text,
|
138 | approved: Boolean,
|
139 | joinedAt: Date,
|
140 | age: Number,
|
141 | address: Address,
|
142 |
|
143 | });
|
144 |
|
145 | User.build();
|
146 | assert.equal(User.properties.name.type, String);
|
147 | assert.equal(User.properties.bio.type, ModelBuilder.Text);
|
148 | assert.equal(User.properties.approved.type, Boolean);
|
149 | assert.equal(User.properties.joinedAt.type, Date);
|
150 | assert.equal(User.properties.age.type, Number);
|
151 | assert.equal(User.properties.address.type, Address);
|
152 |
|
153 | const json = User.toJSON();
|
154 | assert.equal(json.name, 'User');
|
155 | assert.equal(json.properties.name.type, 'String');
|
156 | assert.equal(json.properties.bio.type, 'Text');
|
157 | assert.equal(json.properties.approved.type, 'Boolean');
|
158 | assert.equal(json.properties.joinedAt.type, 'Date');
|
159 | assert.equal(json.properties.age.type, 'Number');
|
160 |
|
161 | assert.equal(json.properties.address.type, 'Address');
|
162 |
|
163 | done();
|
164 | });
|
165 |
|
166 | it('should be able to define referencing models by name', function(done) {
|
167 | const modelBuilder = new ModelBuilder();
|
168 |
|
169 | const Address = modelBuilder.define('Address', {
|
170 | street: String,
|
171 | city: String,
|
172 | zipCode: String,
|
173 | state: String,
|
174 | });
|
175 | const User = new ModelDefinition(modelBuilder, 'User', {
|
176 | name: String,
|
177 | bio: ModelBuilder.Text,
|
178 | approved: Boolean,
|
179 | joinedAt: Date,
|
180 | age: Number,
|
181 | address: 'Address',
|
182 |
|
183 | });
|
184 |
|
185 | User.build();
|
186 | assert.equal(User.properties.name.type, String);
|
187 | assert.equal(User.properties.bio.type, ModelBuilder.Text);
|
188 | assert.equal(User.properties.approved.type, Boolean);
|
189 | assert.equal(User.properties.joinedAt.type, Date);
|
190 | assert.equal(User.properties.age.type, Number);
|
191 | assert.equal(User.properties.address.type, Address);
|
192 |
|
193 | const json = User.toJSON();
|
194 | assert.equal(json.name, 'User');
|
195 | assert.equal(json.properties.name.type, 'String');
|
196 | assert.equal(json.properties.bio.type, 'Text');
|
197 | assert.equal(json.properties.approved.type, 'Boolean');
|
198 | assert.equal(json.properties.joinedAt.type, 'Date');
|
199 | assert.equal(json.properties.age.type, 'Number');
|
200 |
|
201 | assert.equal(json.properties.address.type, 'Address');
|
202 |
|
203 | done();
|
204 | });
|
205 |
|
206 | it('should report correct id names', function(done) {
|
207 | const modelBuilder = new ModelBuilder();
|
208 |
|
209 | const User = new ModelDefinition(modelBuilder, 'User', {
|
210 | userId: {type: String, id: true},
|
211 | name: 'string',
|
212 | bio: ModelBuilder.Text,
|
213 | approved: Boolean,
|
214 | joinedAt: Date,
|
215 | age: 'number',
|
216 | });
|
217 |
|
218 | assert.equal(User.idName(), 'userId');
|
219 | assert.deepEqual(User.idNames(), ['userId']);
|
220 | done();
|
221 | });
|
222 |
|
223 | it('should sort id properties by its index', function() {
|
224 | const modelBuilder = new ModelBuilder();
|
225 |
|
226 | const User = new ModelDefinition(modelBuilder, 'User', {
|
227 | userId: {type: String, id: 2},
|
228 | userType: {type: String, id: 1},
|
229 | name: 'string',
|
230 | bio: ModelBuilder.Text,
|
231 | approved: Boolean,
|
232 | joinedAt: Date,
|
233 | age: 'number',
|
234 | });
|
235 |
|
236 | const ids = User.ids();
|
237 | assert.ok(Array.isArray(ids));
|
238 | assert.equal(ids.length, 2);
|
239 | assert.equal(ids[0].id, 1);
|
240 | assert.equal(ids[0].name, 'userType');
|
241 | assert.equal(ids[1].id, 2);
|
242 | assert.equal(ids[1].name, 'userId');
|
243 | });
|
244 |
|
245 | it('should report correct table/column names', function(done) {
|
246 | const modelBuilder = new ModelBuilder();
|
247 |
|
248 | const User = new ModelDefinition(modelBuilder, 'User', {
|
249 | userId: {type: String, id: true, oracle: {column: 'ID'}},
|
250 | name: 'string',
|
251 | }, {oracle: {table: 'USER'}});
|
252 |
|
253 | assert.equal(User.tableName('oracle'), 'USER');
|
254 | assert.equal(User.tableName('mysql'), 'User');
|
255 | assert.equal(User.columnName('oracle', 'userId'), 'ID');
|
256 | assert.equal(User.columnName('mysql', 'userId'), 'userId');
|
257 | done();
|
258 | });
|
259 |
|
260 | describe('maxDepthOfQuery', function() {
|
261 | it('should report errors for deep query than maxDepthOfQuery', function(done) {
|
262 | const MyModel = memory.createModel('my-model', {}, {
|
263 | maxDepthOfQuery: 5,
|
264 | });
|
265 |
|
266 | const filter = givenComplexFilter();
|
267 |
|
268 | MyModel.find(filter, function(err) {
|
269 | should.exist(err);
|
270 | err.message.should.match('The query object exceeds maximum depth 5');
|
271 | done();
|
272 | });
|
273 | });
|
274 |
|
275 | it('should honor maxDepthOfQuery setting', function(done) {
|
276 | const MyModel = memory.createModel('my-model', {}, {
|
277 | maxDepthOfQuery: 20,
|
278 | });
|
279 |
|
280 | const filter = givenComplexFilter();
|
281 |
|
282 | MyModel.find(filter, function(err) {
|
283 | should.not.exist(err);
|
284 | done();
|
285 | });
|
286 | });
|
287 |
|
288 | it('should honor maxDepthOfQuery in options', function(done) {
|
289 | const MyModel = memory.createModel('my-model', {}, {
|
290 | maxDepthOfQuery: 5,
|
291 | });
|
292 |
|
293 | const filter = givenComplexFilter();
|
294 |
|
295 | MyModel.find(filter, {maxDepthOfQuery: 20}, function(err) {
|
296 | should.not.exist(err);
|
297 | done();
|
298 | });
|
299 | });
|
300 |
|
301 | function givenComplexFilter() {
|
302 | const filter = {where: {and: [{and: [{and: [{and: [{and: [{and:
|
303 | [{and: [{and: [{and: [{x: 1}]}]}]}]}]}]}]}]}]}};
|
304 | return filter;
|
305 | }
|
306 | });
|
307 |
|
308 | it('should serialize protected properties into JSON', function() {
|
309 | const ProtectedModel = memory.createModel('protected', {}, {
|
310 | protected: ['protectedProperty'],
|
311 | });
|
312 | const pm = new ProtectedModel({
|
313 | id: 1, foo: 'bar', protectedProperty: 'protected',
|
314 | });
|
315 | const serialized = pm.toJSON();
|
316 | assert.deepEqual(serialized, {
|
317 | id: 1, foo: 'bar', protectedProperty: 'protected',
|
318 | });
|
319 | });
|
320 |
|
321 | it('should not serialize protected properties of nested models into JSON', function(done) {
|
322 | const Parent = memory.createModel('parent');
|
323 | const Child = memory.createModel('child', {}, {protected: ['protectedProperty']});
|
324 | Parent.hasMany(Child);
|
325 | Parent.create({
|
326 | name: 'parent',
|
327 | }, function(err, parent) {
|
328 | if (err) return done(err);
|
329 | parent.children.create({
|
330 | name: 'child',
|
331 | protectedProperty: 'protectedValue',
|
332 | }, function(err, child) {
|
333 | if (err) return done(err);
|
334 | Parent.find({include: 'children'}, function(err, parents) {
|
335 | if (err) return done(err);
|
336 | const serialized = parents[0].toJSON();
|
337 | const child = serialized.children[0];
|
338 | assert.equal(child.name, 'child');
|
339 | assert.notEqual(child.protectedProperty, 'protectedValue');
|
340 | done();
|
341 | });
|
342 | });
|
343 | });
|
344 | });
|
345 |
|
346 | it('should not serialize hidden properties into JSON', function() {
|
347 | const HiddenModel = memory.createModel('hidden', {}, {
|
348 | hidden: ['secret'],
|
349 | });
|
350 | const hm = new HiddenModel({
|
351 | id: 1,
|
352 | foo: 'bar',
|
353 | secret: 'secret',
|
354 | });
|
355 | const serialized = hm.toJSON();
|
356 | assert.deepEqual(serialized, {
|
357 | id: 1,
|
358 | foo: 'bar',
|
359 | });
|
360 | });
|
361 |
|
362 | it('should not serialize hidden properties of nested models into JSON', function(done) {
|
363 | const Parent = memory.createModel('parent');
|
364 | const Child = memory.createModel('child', {}, {hidden: ['secret']});
|
365 | Parent.hasMany(Child);
|
366 | Parent.create({
|
367 | name: 'parent',
|
368 | }, function(err, parent) {
|
369 | if (err) return done(err);
|
370 | parent.children.create({
|
371 | name: 'child',
|
372 | secret: 'secret',
|
373 | }, function(err, child) {
|
374 | if (err) return done(err);
|
375 | Parent.find({include: 'children'}, function(err, parents) {
|
376 | if (err) return done(err);
|
377 | const serialized = parents[0].toJSON();
|
378 | const child = serialized.children[0];
|
379 | assert.equal(child.name, 'child');
|
380 | assert.notEqual(child.secret, 'secret');
|
381 | done();
|
382 | });
|
383 | });
|
384 | });
|
385 | });
|
386 |
|
387 | describe('hidden properties', function() {
|
388 | let Child;
|
389 |
|
390 | describe('with hidden array', function() {
|
391 | beforeEach(function() { givenChildren(); });
|
392 |
|
393 | it('should be removed if used in where', function() {
|
394 | return Child.find({
|
395 | where: {secret: 'guess'},
|
396 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
397 | });
|
398 |
|
399 | it('should be removed if used in where.and', function() {
|
400 | return Child.find({
|
401 | where: {and: [{secret: 'guess'}]},
|
402 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
403 | });
|
404 |
|
405 | it('should be allowed for update', function() {
|
406 | return Child.update({name: 'childA'}, {secret: 'new-secret'}, optionsFromRemoteReq).then(
|
407 | function(result) {
|
408 | result.count.should.equal(1);
|
409 | },
|
410 | );
|
411 | });
|
412 |
|
413 | it('should be allowed if prohibitHiddenPropertiesInQuery is `false`', function() {
|
414 | Child.definition.settings.prohibitHiddenPropertiesInQuery = false;
|
415 | return Child.find({
|
416 | where: {secret: 'guess'},
|
417 | }).then(function(children) {
|
418 | children.length.should.equal(1);
|
419 | children[0].secret.should.equal('guess');
|
420 | });
|
421 | });
|
422 |
|
423 | it('should be allowed by default if not remote call', function() {
|
424 | return Child.find({
|
425 | where: {secret: 'guess'},
|
426 | }).then(function(children) {
|
427 | children.length.should.equal(1);
|
428 | children[0].secret.should.equal('guess');
|
429 | });
|
430 | });
|
431 |
|
432 | it('should be allowed if prohibitHiddenPropertiesInQuery is `false` in options', function() {
|
433 | return Child.find({
|
434 | where: {secret: 'guess'},
|
435 | }, {
|
436 | prohibitHiddenPropertiesInQuery: false,
|
437 | }).then(function(children) {
|
438 | children.length.should.equal(1);
|
439 | children[0].secret.should.equal('guess');
|
440 | });
|
441 | });
|
442 | });
|
443 |
|
444 | describe('with hidden object', function() {
|
445 | beforeEach(function() { givenChildren({hiddenProperties: {secret: true}}); });
|
446 |
|
447 | it('should be removed if used in where', function() {
|
448 | return Child.find({
|
449 | where: {secret: 'guess'},
|
450 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
451 | });
|
452 |
|
453 | it('should be removed if used in where.and', function() {
|
454 | return Child.find({
|
455 | where: {and: [{secret: 'guess'}]},
|
456 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
457 | });
|
458 | });
|
459 |
|
460 | |
461 |
|
462 |
|
463 |
|
464 | function givenChildren(hiddenProps) {
|
465 | hiddenProps = hiddenProps || {hidden: ['secret']};
|
466 | Child = memory.createModel('child', {
|
467 | name: String,
|
468 | secret: String,
|
469 | }, hiddenProps);
|
470 | return Child.create([{
|
471 | name: 'childA',
|
472 | secret: 'secret',
|
473 | }, {
|
474 | name: 'childB',
|
475 | secret: 'guess',
|
476 | }]);
|
477 | }
|
478 |
|
479 | function assertHiddenPropertyIsIgnored(children) {
|
480 |
|
481 |
|
482 | children.length.should.equal(2);
|
483 | }
|
484 | });
|
485 |
|
486 | |
487 |
|
488 |
|
489 | const optionsFromRemoteReq = {
|
490 | prohibitHiddenPropertiesInQuery: true,
|
491 | maxDepthOfQuery: 12,
|
492 | maxDepthOfQuery: 32,
|
493 | };
|
494 |
|
495 | describe('hidden nested properties', function() {
|
496 | let Child;
|
497 | beforeEach(givenChildren);
|
498 |
|
499 | it('should be removed if used in where as a composite key - x.secret', function() {
|
500 | return Child.find({
|
501 | where: {'x.secret': 'guess'},
|
502 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
503 | });
|
504 |
|
505 | it('should be removed if used in where as a composite key - secret.y', function() {
|
506 | return Child.find({
|
507 | where: {'secret.y': 'guess'},
|
508 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
509 | });
|
510 |
|
511 | it('should be removed if used in where as a composite key - a.secret.b', function() {
|
512 | return Child.find({
|
513 | where: {'a.secret.b': 'guess'},
|
514 | }, optionsFromRemoteReq).then(assertHiddenPropertyIsIgnored);
|
515 | });
|
516 |
|
517 | function givenChildren() {
|
518 | const hiddenProps = {hidden: ['secret']};
|
519 | Child = memory.createModel('child', {
|
520 | name: String,
|
521 | x: {
|
522 | secret: String,
|
523 | },
|
524 | secret: {
|
525 | y: String,
|
526 | },
|
527 | a: {
|
528 | secret: {
|
529 | b: String,
|
530 | },
|
531 | },
|
532 | }, hiddenProps);
|
533 | return Child.create([{
|
534 | name: 'childA',
|
535 | x: {secret: 'secret'},
|
536 | secret: {y: 'secret'},
|
537 | a: {secret: {b: 'secret'}},
|
538 | }, {
|
539 | name: 'childB',
|
540 | x: {secret: 'guess'},
|
541 | secret: {y: 'guess'},
|
542 | a: {secret: {b: 'guess'}},
|
543 | }]);
|
544 | }
|
545 |
|
546 | function assertHiddenPropertyIsIgnored(children) {
|
547 |
|
548 |
|
549 | children.length.should.equal(2);
|
550 | }
|
551 | });
|
552 |
|
553 | function assertParentIncludeChildren(parents) {
|
554 | parents[0].toJSON().children.length.should.equal(1);
|
555 | }
|
556 |
|
557 | describe('protected properties', function() {
|
558 | let Parent;
|
559 | let Child;
|
560 | beforeEach(givenParentAndChild);
|
561 |
|
562 | it('should be removed if used in include scope', function() {
|
563 | Parent.find({
|
564 | include: {
|
565 | relation: 'children',
|
566 | scope: {
|
567 | where: {
|
568 | secret: 'x',
|
569 | },
|
570 | },
|
571 | },
|
572 | }, optionsFromRemoteReq).then(assertParentIncludeChildren);
|
573 | });
|
574 |
|
575 | it('should be rejected if used in include scope.where.and', function() {
|
576 | return Parent.find({
|
577 | include: {
|
578 | relation: 'children',
|
579 | scope: {
|
580 | where: {
|
581 | and: [{secret: 'x'}],
|
582 | },
|
583 | },
|
584 | },
|
585 | }, optionsFromRemoteReq).then(assertParentIncludeChildren);
|
586 | });
|
587 |
|
588 | it('should be removed if a hidden property is used in include scope', function() {
|
589 | return Parent.find({
|
590 | include: {
|
591 | relation: 'children',
|
592 | scope: {
|
593 | where: {
|
594 | secret: 'x',
|
595 | },
|
596 | },
|
597 | },
|
598 | }, optionsFromRemoteReq).then(assertParentIncludeChildren);
|
599 | });
|
600 |
|
601 | function givenParentAndChild() {
|
602 | Parent = memory.createModel('parent');
|
603 | Child = memory.createModel('child', {}, {protected: ['secret']});
|
604 | Parent.hasMany(Child);
|
605 | return Parent.create({
|
606 | name: 'parent',
|
607 | }).then(parent => {
|
608 | return parent.children.create({
|
609 | name: 'child',
|
610 | secret: 'secret',
|
611 | });
|
612 | });
|
613 | }
|
614 | });
|
615 |
|
616 | describe('hidden properties in include', function() {
|
617 | let Parent;
|
618 | let Child;
|
619 | beforeEach(givenParentAndChildWithHiddenProperty);
|
620 |
|
621 | it('should be rejected if used in scope', function() {
|
622 | return Parent.find({
|
623 | include: {
|
624 | relation: 'children',
|
625 | scope: {
|
626 | where: {
|
627 | secret: 'x',
|
628 | },
|
629 | },
|
630 | },
|
631 | }, optionsFromRemoteReq).then(assertParentIncludeChildren);
|
632 | });
|
633 |
|
634 | function givenParentAndChildWithHiddenProperty() {
|
635 | Parent = memory.createModel('parent');
|
636 | Child = memory.createModel('child', {}, {hidden: ['secret']});
|
637 | Parent.hasMany(Child);
|
638 | return Parent.create({
|
639 | name: 'parent',
|
640 | }).then(parent => {
|
641 | return parent.children.create({
|
642 | name: 'child',
|
643 | secret: 'secret',
|
644 | });
|
645 | });
|
646 | }
|
647 | });
|
648 |
|
649 | it('should throw error for property names containing dot', function() {
|
650 | (function() { memory.createModel('Dotted', {'dot.name': String}); })
|
651 | .should
|
652 | .throw(/dot\(s\).*Dotted.*dot\.name/);
|
653 | });
|
654 |
|
655 | it('should report deprecation warning for property named constructor', function() {
|
656 | let message = 'deprecation not reported';
|
657 | process.once('deprecation', function(err) { message = err.message; });
|
658 |
|
659 | memory.createModel('Ctor', {'constructor': String});
|
660 |
|
661 | message.should.match(/Property name should not be "constructor" in Model: Ctor/);
|
662 | });
|
663 |
|
664 | it('should throw error for dynamic property names containing dot',
|
665 | function(done) {
|
666 | const Model = memory.createModel('DynamicDotted');
|
667 | Model.create({'dot.name': 'dot.value'}, function(err) {
|
668 | err.should.be.instanceOf(Error);
|
669 | err.message.should.match(/dot\(s\).*DynamicDotted.*dot\.name/);
|
670 | done();
|
671 | });
|
672 | });
|
673 |
|
674 | it('should throw error for dynamic property named constructor', function(done) {
|
675 | const Model = memory.createModel('DynamicCtor');
|
676 | Model.create({'constructor': 'myCtor'}, function(err) {
|
677 | assert.equal(err.message, 'Property name "constructor" is not allowed in DynamicCtor data');
|
678 | done();
|
679 | });
|
680 | });
|
681 |
|
682 | it('should support "array" type shortcut', function() {
|
683 | const Model = memory.createModel('TwoArrays', {
|
684 | regular: Array,
|
685 | sugar: 'array',
|
686 | });
|
687 |
|
688 | const props = Model.definition.properties;
|
689 | props.regular.type.should.equal(props.sugar.type);
|
690 | });
|
691 |
|
692 | context('hasPK', function() {
|
693 | context('with primary key defined', function() {
|
694 | let Todo;
|
695 | before(function prepModel() {
|
696 | Todo = new ModelDefinition(new ModelBuilder(), 'Todo', {
|
697 | content: 'string',
|
698 | });
|
699 | Todo.defineProperty('id', {
|
700 | type: 'number',
|
701 | id: true,
|
702 | });
|
703 | Todo.build();
|
704 | });
|
705 |
|
706 | it('should return true', function() {
|
707 | Todo.hasPK().should.be.ok;
|
708 | });
|
709 | });
|
710 |
|
711 | context('without primary key defined', function() {
|
712 | let Todo;
|
713 | before(function prepModel() {
|
714 | Todo = new ModelDefinition(new ModelBuilder(), 'Todo', {
|
715 | content: 'string',
|
716 | });
|
717 | Todo.build();
|
718 | });
|
719 |
|
720 | it('should return false', function() {
|
721 | Todo.hasPK().should.not.be.ok;
|
722 | });
|
723 | });
|
724 | });
|
725 | });
|