alchemymvc 1.1.7 → 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/behaviour/sluggable_behaviour.js +2 -4
- package/lib/app/conduit/http_conduit.js +173 -192
- package/lib/app/conduit/loopback_conduit.js +0 -0
- package/lib/app/conduit/socket_conduit.js +620 -620
- package/lib/app/datasource/mongo_datasource.js +75 -10
- package/lib/app/element/time_ago.js +0 -0
- package/lib/app/helper/socket_helper.js +613 -613
- package/lib/app/helper_datasource/00-nosql_datasource.js +73 -19
- package/lib/app/helper_datasource/remote_datasource.js +0 -0
- package/lib/app/helper_field/05-string_field.js +0 -0
- package/lib/app/helper_field/schema_field.js +7 -2
- package/lib/app/helper_model/criteria.js +76 -18
- package/lib/app/helper_model/field_config.js +24 -5
- package/lib/app/helper_model/model.js +65 -7
- package/lib/app/model/alchemy_migration_model.js +33 -0
- package/lib/bootstrap.js +9 -0
- package/lib/class/conduit.js +2474 -2412
- package/lib/class/datasource.js +8 -8
- package/lib/class/field.js +7 -1
- package/lib/class/inode.js +62 -0
- package/lib/class/inode_dir.js +115 -0
- package/lib/class/inode_file.js +112 -111
- package/lib/class/migration.js +138 -0
- package/lib/class/model.js +1765 -1772
- package/lib/class/reciprocal.js +8 -2
- package/lib/class/router.js +0 -0
- package/lib/class/schema.js +14 -12
- package/lib/core/base.js +37 -10
- package/lib/core/client_base.js +1 -9
- package/lib/core/middleware.js +4 -8
- package/lib/core/socket.js +159 -159
- package/lib/init/alchemy.js +1779 -1779
- package/lib/init/devwatch.js +1 -1
- package/lib/init/functions.js +2 -56
- package/lib/init/load_functions.js +8 -2
- package/lib/init/requirements.js +101 -96
- package/lib/stages.js +12 -0
- package/package.json +74 -76
- package/CHANGELOG.md +0 -445
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
@@ -277,7 +277,12 @@ SchemaField.setMethod(function _toApp(query, options, value, callback) {
|
|
|
277
277
|
|
|
278
278
|
name = this.name + 'FieldModel';
|
|
279
279
|
Dummy = alchemy.getModel('Model', false);
|
|
280
|
-
|
|
280
|
+
|
|
281
|
+
Dummy = new Dummy({
|
|
282
|
+
root_model : this.root_model,
|
|
283
|
+
name : name
|
|
284
|
+
});
|
|
285
|
+
|
|
281
286
|
item = {};
|
|
282
287
|
|
|
283
288
|
item[name] = value;
|
|
@@ -338,7 +343,7 @@ SchemaField.setMethod(function _toApp(query, options, value, callback) {
|
|
|
338
343
|
|
|
339
344
|
if (field != null) {
|
|
340
345
|
tasks[field_name] = function doToDatasource(next) {
|
|
341
|
-
field.toApp({}, {}, field_value, next);
|
|
346
|
+
field.toApp({}, {_root_data: options._root_data}, field_value, next);
|
|
342
347
|
};
|
|
343
348
|
}
|
|
344
349
|
});
|
|
@@ -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
|
/**
|
|
@@ -510,6 +521,9 @@ Criteria.setMethod(function getCriteriaForAssociation(name, item) {
|
|
|
510
521
|
assoc_crit.where(assoc_key).equals(value);
|
|
511
522
|
}
|
|
512
523
|
|
|
524
|
+
assoc_crit.setOption('assoc_key', assoc_key);
|
|
525
|
+
assoc_crit.setOption('assoc_value', value);
|
|
526
|
+
|
|
513
527
|
// Take over the locale option
|
|
514
528
|
if (options.locale) {
|
|
515
529
|
assoc_crit.setOption('locale', options.locale);
|
|
@@ -660,7 +674,7 @@ Criteria.setMethod(function page(page, page_size) {
|
|
|
660
674
|
*
|
|
661
675
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
662
676
|
* @since 1.1.0
|
|
663
|
-
* @version 1.
|
|
677
|
+
* @version 1.2.0
|
|
664
678
|
*
|
|
665
679
|
* @param {String|Array} field
|
|
666
680
|
*
|
|
@@ -678,12 +692,6 @@ Criteria.setMethod(function select(field) {
|
|
|
678
692
|
}
|
|
679
693
|
} else {
|
|
680
694
|
|
|
681
|
-
if (typeof field == 'object') {
|
|
682
|
-
if (field instanceof Classes.Alchemy.Criteria.FieldConfig || field.name) {
|
|
683
|
-
field = field.name;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
|
|
687
695
|
if (this._select) {
|
|
688
696
|
context = this._select.parse(field);
|
|
689
697
|
} else {
|
|
@@ -1380,7 +1388,7 @@ Select.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
|
1380
1388
|
*
|
|
1381
1389
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1382
1390
|
* @since 1.1.0
|
|
1383
|
-
* @version 1.
|
|
1391
|
+
* @version 1.2.0
|
|
1384
1392
|
*
|
|
1385
1393
|
* @param {String} name
|
|
1386
1394
|
*
|
|
@@ -1416,9 +1424,39 @@ Select.setMethod(function addAssociation(name) {
|
|
|
1416
1424
|
this.associations[name].association_name = name;
|
|
1417
1425
|
}
|
|
1418
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
|
+
|
|
1419
1439
|
return this.associations[name];
|
|
1420
1440
|
});
|
|
1421
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
|
+
|
|
1422
1460
|
/**
|
|
1423
1461
|
* Add a field
|
|
1424
1462
|
*
|
|
@@ -1442,17 +1480,33 @@ Select.setMethod(function addField(path) {
|
|
|
1442
1480
|
*
|
|
1443
1481
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1444
1482
|
* @since 1.1.0
|
|
1445
|
-
* @version 1.
|
|
1483
|
+
* @version 1.2.0
|
|
1446
1484
|
*
|
|
1447
|
-
* @param {String} path
|
|
1485
|
+
* @param {String|Object} path
|
|
1448
1486
|
*
|
|
1449
1487
|
* @return {Criteria|Null} A criteria object if the context has changed
|
|
1450
1488
|
*/
|
|
1451
1489
|
Select.setMethod(function parse(path) {
|
|
1452
1490
|
|
|
1453
|
-
|
|
1491
|
+
let context,
|
|
1454
1492
|
select = this,
|
|
1455
|
-
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);
|
|
1456
1510
|
|
|
1457
1511
|
// Associations were found,
|
|
1458
1512
|
// like "Comment._id" or "Comment.User"
|
|
@@ -1467,7 +1521,7 @@ Select.setMethod(function parse(path) {
|
|
|
1467
1521
|
continue;
|
|
1468
1522
|
}
|
|
1469
1523
|
|
|
1470
|
-
select =
|
|
1524
|
+
select = select.addAssociation(name);
|
|
1471
1525
|
}
|
|
1472
1526
|
}
|
|
1473
1527
|
|
|
@@ -1486,7 +1540,7 @@ Select.setMethod(function parse(path) {
|
|
|
1486
1540
|
*
|
|
1487
1541
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1488
1542
|
* @since 1.1.0
|
|
1489
|
-
* @version 1.
|
|
1543
|
+
* @version 1.2.0
|
|
1490
1544
|
*
|
|
1491
1545
|
* @param {Criteria} criteria
|
|
1492
1546
|
*
|
|
@@ -1504,6 +1558,10 @@ Select.setMethod(function cloneForCriteria(criteria) {
|
|
|
1504
1558
|
clone.fields = this.fields.slice(0);
|
|
1505
1559
|
}
|
|
1506
1560
|
|
|
1561
|
+
if (this.query_fields && this.query_fields.length) {
|
|
1562
|
+
clone.query_fields = this.query_fields.slice(0);
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1507
1565
|
if (this.associations) {
|
|
1508
1566
|
let key;
|
|
1509
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');
|
|
@@ -1058,6 +1081,26 @@ Model.setMethod(function addAssociatedDataToRecord(criteria, item, callback) {
|
|
|
1058
1081
|
return;
|
|
1059
1082
|
}
|
|
1060
1083
|
|
|
1084
|
+
// SchemaFields use a dummy Model name, so get the root_model in that case
|
|
1085
|
+
let root_model = (that.options && that.options.root_model) || that.name;
|
|
1086
|
+
|
|
1087
|
+
// Make sure references to the same model don't cause a deadlock
|
|
1088
|
+
// (Can happen when a model refers to itself)
|
|
1089
|
+
if (association.modelName == root_model && criteria.options._root_data) {
|
|
1090
|
+
let assoc_key = assoc_crit.options.assoc_key,
|
|
1091
|
+
assoc_value = assoc_crit.options.assoc_value,
|
|
1092
|
+
root = criteria.options._root_data[root_model];
|
|
1093
|
+
|
|
1094
|
+
if (root && root[assoc_key] && Object.alike(root[assoc_key], assoc_value)) {
|
|
1095
|
+
|
|
1096
|
+
aliases[alias] = nextAlias => {
|
|
1097
|
+
nextAlias(null, root[assoc_key]);
|
|
1098
|
+
};
|
|
1099
|
+
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1061
1104
|
aliases[alias] = function aliasRecordTask(nextAlias) {
|
|
1062
1105
|
|
|
1063
1106
|
var key;
|
|
@@ -1381,15 +1424,30 @@ Model.setProperty(function associations() {
|
|
|
1381
1424
|
*
|
|
1382
1425
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
1383
1426
|
* @since 1.0.0
|
|
1384
|
-
* @version 1.
|
|
1427
|
+
* @version 1.2.0
|
|
1385
1428
|
*
|
|
1386
|
-
* @param {
|
|
1429
|
+
* @param {string} path The path to the field
|
|
1387
1430
|
*
|
|
1388
1431
|
* @return {Object}
|
|
1389
1432
|
*/
|
|
1390
|
-
Model.setMethod(function getField(
|
|
1391
|
-
|
|
1392
|
-
|
|
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
|
+
});
|
|
1393
1451
|
|
|
1394
1452
|
// Make this class easily available
|
|
1395
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,
|