alchemymvc 1.1.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app/datasource/mongo_datasource.js +75 -10
- package/lib/app/helper_datasource/00-nosql_datasource.js +73 -19
- package/lib/app/helper_model/criteria.js +73 -18
- package/lib/app/helper_model/field_config.js +24 -5
- package/lib/app/helper_model/model.js +45 -7
- package/lib/app/model/alchemy_migration_model.js +33 -0
- package/lib/bootstrap.js +9 -0
- package/lib/class/datasource.js +2 -2
- package/lib/class/field.js +7 -1
- package/lib/class/migration.js +138 -0
- package/lib/class/model.js +11 -19
- package/lib/class/schema.js +14 -12
- package/lib/init/alchemy.js +1779 -1779
- package/lib/init/load_functions.js +8 -2
- package/package.json +11 -11
- package/CHANGELOG.md +0 -462
|
@@ -228,7 +228,7 @@ Mongo.setMethod(function collection(name, callback) {
|
|
|
228
228
|
*
|
|
229
229
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
230
230
|
* @since 0.2.0
|
|
231
|
-
* @version 1.
|
|
231
|
+
* @version 1.2.0
|
|
232
232
|
*/
|
|
233
233
|
Mongo.setMethod(function _read(model, criteria, callback) {
|
|
234
234
|
|
|
@@ -250,22 +250,87 @@ Mongo.setMethod(function _read(model, criteria, callback) {
|
|
|
250
250
|
|
|
251
251
|
if (compiled.pipeline) {
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
// Sorting should happen in the pipeline
|
|
254
|
+
if (options.sort && options.sort.length) {
|
|
255
|
+
let sort_object = {};
|
|
254
256
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
+
for (let entry of options.sort) {
|
|
258
|
+
sort_object[entry[0]] = entry[1];
|
|
257
259
|
}
|
|
258
260
|
|
|
259
|
-
|
|
261
|
+
compiled.pipeline.unshift({$sort: sort_object});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Skipping also happens in the pipeline
|
|
265
|
+
if (options.skip) {
|
|
266
|
+
compiled.pipeline.push({$skip: options.skip});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
let aggregate_options = {};
|
|
260
270
|
|
|
261
|
-
|
|
262
|
-
|
|
271
|
+
// Limits can still be set as an option though
|
|
272
|
+
if (options.limit) {
|
|
273
|
+
aggregate_options.limit = options.limit;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
Function.parallel({
|
|
277
|
+
available: function getAvailable(next) {
|
|
278
|
+
|
|
279
|
+
if (criteria.options.available === false) {
|
|
280
|
+
return next(null, null);
|
|
263
281
|
}
|
|
264
282
|
|
|
265
|
-
|
|
283
|
+
let pipeline = JSON.clone(compiled.pipeline),
|
|
284
|
+
cloned_options = JSON.clone(aggregate_options);
|
|
285
|
+
|
|
286
|
+
pipeline.push({$count: 'available'});
|
|
287
|
+
|
|
288
|
+
// Expensive aggregate just to get the available count...
|
|
289
|
+
collection.aggregate(pipeline, cloned_options, function gotAggregate(err, cursor) {
|
|
290
|
+
|
|
291
|
+
if (err) {
|
|
292
|
+
return next(err);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
cursor.toArray(function gotAvailableArray(err, items) {
|
|
296
|
+
|
|
297
|
+
if (err) {
|
|
298
|
+
return next(err);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (!items || !items.length) {
|
|
302
|
+
return next(null, null);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
let available = items[0].available;
|
|
306
|
+
|
|
307
|
+
if (options.skip) {
|
|
308
|
+
available += options.skip;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return next(null, available);
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
items: function getItems(next) {
|
|
316
|
+
collection.aggregate(compiled.pipeline, aggregate_options, function gotAggregate(err, cursor) {
|
|
317
|
+
|
|
318
|
+
if (err) {
|
|
319
|
+
return next(err);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
cursor.toArray(next);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}, function done(err, data) {
|
|
326
|
+
|
|
327
|
+
if (err) {
|
|
328
|
+
return callback(err);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
data.items = that.organizeResultItems(model, data.items);
|
|
266
332
|
|
|
267
|
-
|
|
268
|
-
});
|
|
333
|
+
callback(err, data.items, data.available);
|
|
269
334
|
});
|
|
270
335
|
|
|
271
336
|
return;
|
|
@@ -611,6 +611,15 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
|
|
|
611
611
|
group = criteria.group;
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
+
let getAggregate = () => {
|
|
615
|
+
if (!aggregate) {
|
|
616
|
+
aggregate = {
|
|
617
|
+
pipeline: [],
|
|
618
|
+
lookups: {}
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
614
623
|
for (i = 0; i < group.items.length; i++) {
|
|
615
624
|
entry = group.items[i];
|
|
616
625
|
|
|
@@ -620,12 +629,7 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
|
|
|
620
629
|
}
|
|
621
630
|
|
|
622
631
|
if (entry.association) {
|
|
623
|
-
|
|
624
|
-
aggregate = {
|
|
625
|
-
pipeline: [],
|
|
626
|
-
lookups: {}
|
|
627
|
-
};
|
|
628
|
-
}
|
|
632
|
+
getAggregate();
|
|
629
633
|
|
|
630
634
|
// Get the association info
|
|
631
635
|
assoc = criteria.model.getAssociation(entry.association);
|
|
@@ -705,9 +709,45 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
|
|
|
705
709
|
not,
|
|
706
710
|
obj = {};
|
|
707
711
|
|
|
712
|
+
let field_entry = {},
|
|
713
|
+
name = entry.target_path;
|
|
714
|
+
|
|
715
|
+
// Do we need to look into an object itself?
|
|
716
|
+
// (Like the "timestamp" property of a date field when stored with units)
|
|
717
|
+
if (entry.db_property) {
|
|
718
|
+
name += '.' + entry.db_property;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (entry.association) {
|
|
722
|
+
name = entry.association + '.' + name;
|
|
723
|
+
}
|
|
724
|
+
|
|
708
725
|
for (let i = 0; i < entry.items.length; i++) {
|
|
709
726
|
item = entry.items[i];
|
|
710
727
|
|
|
728
|
+
// If the value is a RegExp, we might have to stringify the value
|
|
729
|
+
if (shouldStringify(entry, item) && RegExp.isRegExp(item.value)) {
|
|
730
|
+
|
|
731
|
+
let stringified_field = name + '_stringified';
|
|
732
|
+
|
|
733
|
+
getAggregate();
|
|
734
|
+
|
|
735
|
+
aggregate.pipeline.push({
|
|
736
|
+
$addFields: {
|
|
737
|
+
[stringified_field]: {
|
|
738
|
+
$convert: {
|
|
739
|
+
input: '$' + name,
|
|
740
|
+
to: 'string',
|
|
741
|
+
onError: '',
|
|
742
|
+
onNull: ''
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
name = stringified_field;
|
|
749
|
+
}
|
|
750
|
+
|
|
711
751
|
if (item.type == 'ne') {
|
|
712
752
|
obj.$ne = item.value;
|
|
713
753
|
} else if (item.type == 'not') {
|
|
@@ -771,19 +811,6 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
|
|
|
771
811
|
throw new Error('Unknown criteria expression: "' + item.type + '"');
|
|
772
812
|
}
|
|
773
813
|
|
|
774
|
-
let field_entry = {},
|
|
775
|
-
name = entry.target_path;
|
|
776
|
-
|
|
777
|
-
// Do we need to look into an object itself?
|
|
778
|
-
// (Like the "timestamp" property of a date field when stored with units)
|
|
779
|
-
if (entry.db_property) {
|
|
780
|
-
name += '.' + entry.db_property;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
if (entry.association) {
|
|
784
|
-
name = entry.association + '.' + name;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
814
|
if (obj && obj.$or) {
|
|
788
815
|
|
|
789
816
|
let $or = [],
|
|
@@ -870,6 +897,33 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
|
|
|
870
897
|
return {$and: result};
|
|
871
898
|
});
|
|
872
899
|
|
|
900
|
+
/**
|
|
901
|
+
* Is the given item about a string field?
|
|
902
|
+
*
|
|
903
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
904
|
+
* @since 1.2.0
|
|
905
|
+
* @version 1.2.0
|
|
906
|
+
*
|
|
907
|
+
* @param {Object} entry
|
|
908
|
+
* @param {Object} item
|
|
909
|
+
*
|
|
910
|
+
* @return {boolean}
|
|
911
|
+
*/
|
|
912
|
+
function shouldStringify(entry, item) {
|
|
913
|
+
|
|
914
|
+
if (!item || !item.value) {
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
try {
|
|
919
|
+
let field = entry.model.getField(entry.target_path);
|
|
920
|
+
|
|
921
|
+
// The field value should only be stringified if it isn't a string already
|
|
922
|
+
return !(field instanceof Classes.Alchemy.Field.String);
|
|
923
|
+
} catch (err) {}
|
|
924
|
+
|
|
925
|
+
return false;
|
|
926
|
+
}
|
|
873
927
|
|
|
874
928
|
/**
|
|
875
929
|
* Get the MongoDB options from this criteria
|
|
@@ -388,15 +388,26 @@ Criteria.setMethod(function clone() {
|
|
|
388
388
|
*
|
|
389
389
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
390
390
|
* @since 1.1.0
|
|
391
|
-
* @version 1.
|
|
391
|
+
* @version 1.2.0
|
|
392
392
|
*
|
|
393
|
-
* @return {
|
|
393
|
+
* @return {String[]}
|
|
394
394
|
*/
|
|
395
395
|
Criteria.setMethod(function getFieldsToSelect() {
|
|
396
396
|
|
|
397
|
-
|
|
397
|
+
let result;
|
|
398
398
|
|
|
399
|
-
|
|
399
|
+
if (this.options.select.fields && this.options.select.fields.length) {
|
|
400
|
+
result = this.options.select.fields.slice(0);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Fields can sometimes be required for a query (like in a join) but they
|
|
404
|
+
// won't be selected if other fields are explicitly set.
|
|
405
|
+
// So in that case: add these special fields to the projection
|
|
406
|
+
if (result && this.options.select.query_fields && this.options.select.query_fields) {
|
|
407
|
+
result.push(...this.options.select.query_fields);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return result || [];
|
|
400
411
|
});
|
|
401
412
|
|
|
402
413
|
/**
|
|
@@ -663,7 +674,7 @@ Criteria.setMethod(function page(page, page_size) {
|
|
|
663
674
|
*
|
|
664
675
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
665
676
|
* @since 1.1.0
|
|
666
|
-
* @version 1.
|
|
677
|
+
* @version 1.2.0
|
|
667
678
|
*
|
|
668
679
|
* @param {String|Array} field
|
|
669
680
|
*
|
|
@@ -681,12 +692,6 @@ Criteria.setMethod(function select(field) {
|
|
|
681
692
|
}
|
|
682
693
|
} else {
|
|
683
694
|
|
|
684
|
-
if (typeof field == 'object') {
|
|
685
|
-
if (field instanceof Classes.Alchemy.Criteria.FieldConfig || field.name) {
|
|
686
|
-
field = field.name;
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
|
|
690
695
|
if (this._select) {
|
|
691
696
|
context = this._select.parse(field);
|
|
692
697
|
} else {
|
|
@@ -1383,7 +1388,7 @@ Select.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
|
1383
1388
|
*
|
|
1384
1389
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1385
1390
|
* @since 1.1.0
|
|
1386
|
-
* @version 1.
|
|
1391
|
+
* @version 1.2.0
|
|
1387
1392
|
*
|
|
1388
1393
|
* @param {String} name
|
|
1389
1394
|
*
|
|
@@ -1419,9 +1424,39 @@ Select.setMethod(function addAssociation(name) {
|
|
|
1419
1424
|
this.associations[name].association_name = name;
|
|
1420
1425
|
}
|
|
1421
1426
|
|
|
1427
|
+
// Get the association data
|
|
1428
|
+
try {
|
|
1429
|
+
let info = this.criteria.model.getAssociation(name);
|
|
1430
|
+
|
|
1431
|
+
if (info) {
|
|
1432
|
+
// Make sure the localkey is added to the resultset
|
|
1433
|
+
this.requireFieldForQuery(info.options.localKey);
|
|
1434
|
+
}
|
|
1435
|
+
} catch (err) {
|
|
1436
|
+
console.warn('Failed to find "' + name + '" association for ' + this.criteria.model.modelName);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1422
1439
|
return this.associations[name];
|
|
1423
1440
|
});
|
|
1424
1441
|
|
|
1442
|
+
/**
|
|
1443
|
+
* Require a field for query purposes
|
|
1444
|
+
*
|
|
1445
|
+
* @author Jelle De Loecker <jelle@develry.be>
|
|
1446
|
+
* @since 1.2.0
|
|
1447
|
+
* @version 1.2.0
|
|
1448
|
+
*
|
|
1449
|
+
* @param {String} path
|
|
1450
|
+
*/
|
|
1451
|
+
Select.setMethod(function requireFieldForQuery(path) {
|
|
1452
|
+
|
|
1453
|
+
if (!this.query_fields) {
|
|
1454
|
+
this.query_fields = [];
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
this.query_fields.push(path);
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1425
1460
|
/**
|
|
1426
1461
|
* Add a field
|
|
1427
1462
|
*
|
|
@@ -1445,17 +1480,33 @@ Select.setMethod(function addField(path) {
|
|
|
1445
1480
|
*
|
|
1446
1481
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1447
1482
|
* @since 1.1.0
|
|
1448
|
-
* @version 1.
|
|
1483
|
+
* @version 1.2.0
|
|
1449
1484
|
*
|
|
1450
|
-
* @param {String} path
|
|
1485
|
+
* @param {String|Object} path
|
|
1451
1486
|
*
|
|
1452
1487
|
* @return {Criteria|Null} A criteria object if the context has changed
|
|
1453
1488
|
*/
|
|
1454
1489
|
Select.setMethod(function parse(path) {
|
|
1455
1490
|
|
|
1456
|
-
|
|
1491
|
+
let context,
|
|
1457
1492
|
select = this,
|
|
1458
|
-
parsed
|
|
1493
|
+
parsed;
|
|
1494
|
+
|
|
1495
|
+
if (typeof path == 'object' && path && path.name) {
|
|
1496
|
+
|
|
1497
|
+
if (path.path) {
|
|
1498
|
+
path = path.path;
|
|
1499
|
+
} else {
|
|
1500
|
+
let obj = path;
|
|
1501
|
+
path = obj.name;
|
|
1502
|
+
|
|
1503
|
+
if (obj.association) {
|
|
1504
|
+
path = obj.association + '.' + path;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
parsed = Criteria.parsePath(path, this.criteria);
|
|
1459
1510
|
|
|
1460
1511
|
// Associations were found,
|
|
1461
1512
|
// like "Comment._id" or "Comment.User"
|
|
@@ -1470,7 +1521,7 @@ Select.setMethod(function parse(path) {
|
|
|
1470
1521
|
continue;
|
|
1471
1522
|
}
|
|
1472
1523
|
|
|
1473
|
-
select =
|
|
1524
|
+
select = select.addAssociation(name);
|
|
1474
1525
|
}
|
|
1475
1526
|
}
|
|
1476
1527
|
|
|
@@ -1489,7 +1540,7 @@ Select.setMethod(function parse(path) {
|
|
|
1489
1540
|
*
|
|
1490
1541
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1491
1542
|
* @since 1.1.0
|
|
1492
|
-
* @version 1.
|
|
1543
|
+
* @version 1.2.0
|
|
1493
1544
|
*
|
|
1494
1545
|
* @param {Criteria} criteria
|
|
1495
1546
|
*
|
|
@@ -1507,6 +1558,10 @@ Select.setMethod(function cloneForCriteria(criteria) {
|
|
|
1507
1558
|
clone.fields = this.fields.slice(0);
|
|
1508
1559
|
}
|
|
1509
1560
|
|
|
1561
|
+
if (this.query_fields && this.query_fields.length) {
|
|
1562
|
+
clone.query_fields = this.query_fields.slice(0);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1510
1565
|
if (this.associations) {
|
|
1511
1566
|
let key;
|
|
1512
1567
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
9
9
|
* @since 1.1.3
|
|
10
|
-
* @version 1.
|
|
10
|
+
* @version 1.2.0
|
|
11
11
|
*
|
|
12
12
|
* @param {string} path
|
|
13
13
|
* @param {Object} options
|
|
@@ -20,6 +20,9 @@ const FieldConfig = Fn.inherits('Alchemy.Base', 'Alchemy.Criteria', function Fie
|
|
|
20
20
|
// The full path to the value
|
|
21
21
|
this.path = null;
|
|
22
22
|
|
|
23
|
+
// The local path to the value (subfields)
|
|
24
|
+
this.local_path = null;
|
|
25
|
+
|
|
23
26
|
// The pieces of the path
|
|
24
27
|
this.pieces = null;
|
|
25
28
|
|
|
@@ -89,7 +92,7 @@ FieldConfig.setMethod(function toDry() {
|
|
|
89
92
|
*
|
|
90
93
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
91
94
|
* @since 1.1.3
|
|
92
|
-
* @version 1.
|
|
95
|
+
* @version 1.2.0
|
|
93
96
|
*
|
|
94
97
|
* @return {Object}
|
|
95
98
|
*/
|
|
@@ -97,6 +100,7 @@ FieldConfig.setMethod(function toJSON() {
|
|
|
97
100
|
return {
|
|
98
101
|
name : this.name,
|
|
99
102
|
path : this.path,
|
|
103
|
+
local_path : this.local_path,
|
|
100
104
|
association : this.association,
|
|
101
105
|
options : this.options,
|
|
102
106
|
};
|
|
@@ -107,7 +111,7 @@ FieldConfig.setMethod(function toJSON() {
|
|
|
107
111
|
*
|
|
108
112
|
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
109
113
|
* @since 1.1.3
|
|
110
|
-
* @version 1.
|
|
114
|
+
* @version 1.2.0
|
|
111
115
|
*
|
|
112
116
|
* @param {string} path
|
|
113
117
|
*/
|
|
@@ -120,6 +124,7 @@ FieldConfig.setMethod(function parsePath(path) {
|
|
|
120
124
|
} else if (path.indexOf('.') == -1) {
|
|
121
125
|
this.name = path;
|
|
122
126
|
this.path = path;
|
|
127
|
+
this.local_path = path;
|
|
123
128
|
this.pieces = [path];
|
|
124
129
|
return;
|
|
125
130
|
} else {
|
|
@@ -132,13 +137,27 @@ FieldConfig.setMethod(function parsePath(path) {
|
|
|
132
137
|
|
|
133
138
|
this.path = path;
|
|
134
139
|
this.pieces = pieces;
|
|
140
|
+
this.local_path = '';
|
|
135
141
|
|
|
136
142
|
for (i = 0; i < pieces.length; i++) {
|
|
137
143
|
piece = pieces[i];
|
|
138
144
|
|
|
139
|
-
if (
|
|
140
|
-
|
|
145
|
+
if (piece[0].isUpperCase()) {
|
|
146
|
+
|
|
147
|
+
if (this.association) {
|
|
148
|
+
this.association += '.';
|
|
149
|
+
} else {
|
|
150
|
+
this.association = '';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.association += piece;
|
|
141
154
|
continue;
|
|
155
|
+
} else {
|
|
156
|
+
if (this.local_path) {
|
|
157
|
+
this.local_path += '.';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.local_path += piece;
|
|
142
161
|
}
|
|
143
162
|
}
|
|
144
163
|
|
|
@@ -403,7 +403,7 @@ Model.setMethod(function getFindOptions(options) {
|
|
|
403
403
|
*
|
|
404
404
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
405
405
|
* @since 1.1.0
|
|
406
|
-
* @version 1.
|
|
406
|
+
* @version 1.2.0
|
|
407
407
|
*
|
|
408
408
|
* @param {String} alias
|
|
409
409
|
*
|
|
@@ -415,7 +415,30 @@ Model.setMethod(function getAssociation(alias) {
|
|
|
415
415
|
throw new Error('Unable to find ' + this.constructor.name + ' schema associations');
|
|
416
416
|
}
|
|
417
417
|
|
|
418
|
-
let config
|
|
418
|
+
let config;
|
|
419
|
+
|
|
420
|
+
// @TODO: Test nested association getting
|
|
421
|
+
if (alias && alias.indexOf('.') > -1) {
|
|
422
|
+
let pieces = alias.split('.'),
|
|
423
|
+
context = this,
|
|
424
|
+
piece,
|
|
425
|
+
temp;
|
|
426
|
+
|
|
427
|
+
for (piece of pieces) {
|
|
428
|
+
temp = context.getAssociation(piece);
|
|
429
|
+
|
|
430
|
+
if (!temp) {
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
context = this.getModel(temp.modelName);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// The config s the last association gotten
|
|
438
|
+
config = temp;
|
|
439
|
+
} else {
|
|
440
|
+
config = this.schema.associations[alias];
|
|
441
|
+
}
|
|
419
442
|
|
|
420
443
|
if (!config) {
|
|
421
444
|
throw new Error('Unable to find ' + JSON.stringify(alias) + ' association in ' + this.constructor.name + ' model');
|
|
@@ -1401,15 +1424,30 @@ Model.setProperty(function associations() {
|
|
|
1401
1424
|
*
|
|
1402
1425
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1403
1426
|
* @since 1.0.0
|
|
1404
|
-
* @version 1.
|
|
1427
|
+
* @version 1.2.0
|
|
1405
1428
|
*
|
|
1406
|
-
* @param {
|
|
1429
|
+
* @param {string} path The path to the field
|
|
1407
1430
|
*
|
|
1408
1431
|
* @return {Object}
|
|
1409
1432
|
*/
|
|
1410
|
-
Model.setMethod(function getField(
|
|
1411
|
-
|
|
1412
|
-
|
|
1433
|
+
Model.setMethod(function getField(path) {
|
|
1434
|
+
|
|
1435
|
+
if (path.indexOf('.') > -1) {
|
|
1436
|
+
let config = new Classes.Alchemy.Criteria.FieldConfig(path);
|
|
1437
|
+
|
|
1438
|
+
// If part of the path is an association, look for that now
|
|
1439
|
+
if (config.association) {
|
|
1440
|
+
let association = this.getAssociation(config.association);
|
|
1441
|
+
let model = this.getModel(association.modelName);
|
|
1442
|
+
return model.getField(config.local_path);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// If not, just use the local_path
|
|
1446
|
+
path = config.local_path;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
return this.schema.getField(path);
|
|
1450
|
+
});
|
|
1413
1451
|
|
|
1414
1452
|
// Make this class easily available
|
|
1415
1453
|
Hawkejs.Model = Model;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Alchemy Migration Model class
|
|
3
|
+
*
|
|
4
|
+
* @constructor
|
|
5
|
+
*
|
|
6
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
|
+
* @since 1.2.0
|
|
8
|
+
* @version 1.2.0
|
|
9
|
+
*/
|
|
10
|
+
const AlchemyMigration = Function.inherits('Alchemy.Model.App', 'AlchemyMigration');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Constitute the class wide schema
|
|
14
|
+
*
|
|
15
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
16
|
+
* @since 1.2.0
|
|
17
|
+
* @version 1.2.0
|
|
18
|
+
*/
|
|
19
|
+
AlchemyMigration.constitute(function addTaskFields() {
|
|
20
|
+
|
|
21
|
+
// The name of the migration
|
|
22
|
+
this.addField('name', 'String');
|
|
23
|
+
|
|
24
|
+
// The full path of the file
|
|
25
|
+
this.addField('path', 'String');
|
|
26
|
+
|
|
27
|
+
// When the migration ended
|
|
28
|
+
this.addField('ended', 'Datetime');
|
|
29
|
+
|
|
30
|
+
// Was there an error?
|
|
31
|
+
this.addField('error', 'String');
|
|
32
|
+
|
|
33
|
+
});
|
package/lib/bootstrap.js
CHANGED
|
@@ -61,6 +61,15 @@ require('./core/base');
|
|
|
61
61
|
*/
|
|
62
62
|
require('./core/client_base');
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* The migration class
|
|
66
|
+
*
|
|
67
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
68
|
+
* @since 1.2.0
|
|
69
|
+
* @version 1.2.0
|
|
70
|
+
*/
|
|
71
|
+
require('./class/migration');
|
|
72
|
+
|
|
64
73
|
var hawkejs_options = {
|
|
65
74
|
server : false,
|
|
66
75
|
make_commonjs: true,
|
package/lib/class/datasource.js
CHANGED
|
@@ -165,7 +165,7 @@ Datasource.setMethod(function getSchema(schema) {
|
|
|
165
165
|
*
|
|
166
166
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
167
167
|
* @since 0.2.0
|
|
168
|
-
* @version 1.
|
|
168
|
+
* @version 1.2.0
|
|
169
169
|
*
|
|
170
170
|
* @param {Schema|Model} schema
|
|
171
171
|
* @param {Object} data
|
|
@@ -187,7 +187,7 @@ Datasource.setMethod(function toDatasource(schema, data, callback) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
if (!schema) {
|
|
190
|
-
log.todo('Schema not found: not normalizing data');
|
|
190
|
+
log.todo('Schema not found: not normalizing data', data);
|
|
191
191
|
pledge = Pledge.resolve(data);
|
|
192
192
|
pledge.done(callback);
|
|
193
193
|
return pledge;
|
package/lib/class/field.js
CHANGED
|
@@ -594,7 +594,7 @@ Field.setMethod(function castCondition(value, field_paths) {
|
|
|
594
594
|
*
|
|
595
595
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
596
596
|
* @since 0.5.0
|
|
597
|
-
* @version 1.0
|
|
597
|
+
* @version 1.2.0
|
|
598
598
|
*
|
|
599
599
|
* @param {Mixed} value
|
|
600
600
|
* @param {Array} field_paths The path to the field
|
|
@@ -602,6 +602,12 @@ Field.setMethod(function castCondition(value, field_paths) {
|
|
|
602
602
|
* @return {Mixed}
|
|
603
603
|
*/
|
|
604
604
|
Field.setMethod(function _castCondition(value, field_paths) {
|
|
605
|
+
|
|
606
|
+
// Always allow regex values, we'll use those in the projection stage
|
|
607
|
+
if (value && RegExp.isRegExp(value)) {
|
|
608
|
+
return value;
|
|
609
|
+
}
|
|
610
|
+
|
|
605
611
|
return this.cast(value, true);
|
|
606
612
|
});
|
|
607
613
|
|