alchemymvc 1.1.10 → 1.2.2
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/backed_map.js +257 -0
- package/lib/app/helper/enum_values.js +125 -0
- package/lib/app/helper/router_helper.js +7 -1
- package/lib/app/helper_component/paginate_component.js +43 -98
- package/lib/app/helper_controller/conduit.js +11 -9
- package/lib/app/helper_datasource/00-nosql_datasource.js +78 -20
- package/lib/app/helper_field/05-string_field.js +1 -3
- package/lib/app/helper_field/belongsto_field.js +1 -20
- package/lib/app/helper_field/enum_field.js +9 -36
- package/lib/app/helper_field/schema_field.js +11 -21
- package/lib/app/helper_model/criteria.js +73 -18
- package/lib/app/helper_model/data_provider.js +92 -0
- package/lib/app/helper_model/field_config.js +115 -5
- package/lib/app/helper_model/field_set.js +27 -1
- package/lib/app/helper_model/model.js +45 -7
- package/lib/app/helper_model/remote_data_provider.js +35 -0
- package/lib/app/model/alchemy_migration_model.js +33 -0
- package/lib/bootstrap.js +25 -0
- package/lib/class/datasource.js +2 -2
- package/lib/class/element.js +6 -1
- 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 +23 -14
- package/lib/core/base.js +12 -3
- package/lib/core/client_alchemy.js +14 -0
- package/lib/init/alchemy.js +1807 -1779
- package/lib/init/functions.js +5 -2
- package/lib/init/load_functions.js +16 -5
- package/package.json +12 -12
- 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;
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
const OBJECT = Symbol('Object'),
|
|
2
|
+
BACKING = Symbol('Backing'),
|
|
3
|
+
MAP = Symbol('Map');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The Backed map class
|
|
7
|
+
*
|
|
8
|
+
* @constructor
|
|
9
|
+
*
|
|
10
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
11
|
+
* @since 1.2.1
|
|
12
|
+
* @version 1.2.1
|
|
13
|
+
*/
|
|
14
|
+
const Backed = Function.inherits('Alchemy.Base', 'Alchemy.Map', function Backed(backing) {
|
|
15
|
+
this.local = new Map();
|
|
16
|
+
this.type = null;
|
|
17
|
+
this.backing = backing;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Undry the given value
|
|
22
|
+
*
|
|
23
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
24
|
+
* @since 1.2.1
|
|
25
|
+
* @version 1.2.1
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} value
|
|
28
|
+
*
|
|
29
|
+
* @return {EnumValues}
|
|
30
|
+
*/
|
|
31
|
+
Backed.setStatic(function unDry(value, custom_method, whenDone) {
|
|
32
|
+
let result = new this(value.backing);
|
|
33
|
+
return result;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the size
|
|
38
|
+
*
|
|
39
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
40
|
+
* @since 1.2.1
|
|
41
|
+
* @version 1.2.1
|
|
42
|
+
*/
|
|
43
|
+
Backed.setProperty(function size() {
|
|
44
|
+
return this.keys().length;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Set the backing value
|
|
49
|
+
*
|
|
50
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
51
|
+
* @since 1.2.1
|
|
52
|
+
* @version 1.2.1
|
|
53
|
+
*/
|
|
54
|
+
Backed.enforceProperty(function backing(new_value, old_value) {
|
|
55
|
+
|
|
56
|
+
this.backing = null;
|
|
57
|
+
this.type = null;
|
|
58
|
+
|
|
59
|
+
if (!new_value) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (new_value instanceof Backed) {
|
|
64
|
+
this.type = BACKING;
|
|
65
|
+
} else if (new_value instanceof Map) {
|
|
66
|
+
this.type = MAP;
|
|
67
|
+
} else if (typeof new_value == 'object') {
|
|
68
|
+
this.type = OBJECT;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return new_value;
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create a (shallow) clone of this backed map.
|
|
76
|
+
* Since we don't ever touch the backing itself, we don't have to clone that.
|
|
77
|
+
*
|
|
78
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
79
|
+
* @since 1.2.1
|
|
80
|
+
* @version 1.2.1
|
|
81
|
+
*
|
|
82
|
+
* @return {Backed}
|
|
83
|
+
*/
|
|
84
|
+
Backed.setMethod(function clone() {
|
|
85
|
+
let result = new Backed(this.backing);
|
|
86
|
+
result.local = new Map(this.local);
|
|
87
|
+
return result;
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create a (shallow) clone of this backed map.
|
|
92
|
+
* Since we don't ever touch the backing itself, we don't have to clone that.
|
|
93
|
+
*
|
|
94
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
95
|
+
* @since 1.2.1
|
|
96
|
+
* @version 1.2.1
|
|
97
|
+
*
|
|
98
|
+
* @return {Backed}
|
|
99
|
+
*/
|
|
100
|
+
Backed.setMethod(function dryClone(wm, custom_method) {
|
|
101
|
+
return this.clone();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Simplify the object for Hawkejs
|
|
106
|
+
*
|
|
107
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
108
|
+
* @since 1.2.1
|
|
109
|
+
* @version 1.2.1
|
|
110
|
+
*
|
|
111
|
+
* @param {WeakMap} wm
|
|
112
|
+
*
|
|
113
|
+
* @return {Backed}
|
|
114
|
+
*/
|
|
115
|
+
Backed.setMethod(function toHawkejs(wm) {
|
|
116
|
+
|
|
117
|
+
let values = new Map(),
|
|
118
|
+
value,
|
|
119
|
+
keys = this.keys(),
|
|
120
|
+
key;
|
|
121
|
+
|
|
122
|
+
for (key of keys) {
|
|
123
|
+
value = this.get(key);
|
|
124
|
+
values.set(key, JSON.clone(value, 'toHawkejs', wm));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return new this.constructor(values);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get all the keys
|
|
132
|
+
*
|
|
133
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
134
|
+
* @since 1.2.1
|
|
135
|
+
* @version 1.2.1
|
|
136
|
+
*
|
|
137
|
+
* @return {String[]}
|
|
138
|
+
*/
|
|
139
|
+
Backed.setMethod(function keys() {
|
|
140
|
+
|
|
141
|
+
let result;
|
|
142
|
+
|
|
143
|
+
if (this.type == BACKING) {
|
|
144
|
+
result = this.backing.keys();
|
|
145
|
+
} else if (this.type == MAP) {
|
|
146
|
+
result = [...this.backing.keys()];
|
|
147
|
+
} else if (this.type == OBJECT) {
|
|
148
|
+
result = Object.keys(this.backing);
|
|
149
|
+
} else {
|
|
150
|
+
result = [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (this.local.size) {
|
|
154
|
+
for (let key of this.local.keys()) {
|
|
155
|
+
if (result.indexOf(key) == -1) {
|
|
156
|
+
result.push(key);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get a value by it's name
|
|
166
|
+
*
|
|
167
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
168
|
+
* @since 1.2.1
|
|
169
|
+
* @version 1.2.1
|
|
170
|
+
*
|
|
171
|
+
* @param {String} name
|
|
172
|
+
*
|
|
173
|
+
* @return {Mixed}
|
|
174
|
+
*/
|
|
175
|
+
Backed.setMethod(function get(name) {
|
|
176
|
+
|
|
177
|
+
if (this.local.has(name)) {
|
|
178
|
+
return this.local.get(name);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (!this.type) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let value;
|
|
186
|
+
|
|
187
|
+
if (this.type == BACKING || this.type == MAP) {
|
|
188
|
+
value = this.backing.get(name);
|
|
189
|
+
} else if (this.type == OBJECT) {
|
|
190
|
+
value = this.backing[name];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return value;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Set a value
|
|
198
|
+
*
|
|
199
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
200
|
+
* @since 1.2.1
|
|
201
|
+
* @version 1.2.1
|
|
202
|
+
*
|
|
203
|
+
* @param {String} name
|
|
204
|
+
* @param {*} value
|
|
205
|
+
*
|
|
206
|
+
* @return {*}
|
|
207
|
+
*/
|
|
208
|
+
Backed.setMethod(function set(name, value) {
|
|
209
|
+
this.local.set(name, value);
|
|
210
|
+
return value;
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Dry the object
|
|
215
|
+
*
|
|
216
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
217
|
+
* @since 1.2.1
|
|
218
|
+
* @version 1.2.1
|
|
219
|
+
*
|
|
220
|
+
* @return {Object}
|
|
221
|
+
*/
|
|
222
|
+
Backed.setMethod(function toDry() {
|
|
223
|
+
|
|
224
|
+
let result = {
|
|
225
|
+
backing : {}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
let value,
|
|
229
|
+
key;
|
|
230
|
+
|
|
231
|
+
for (key of this.keys()) {
|
|
232
|
+
value = this.get(key);
|
|
233
|
+
result.backing[key] = value;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return {value: result};
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Iterate over the object
|
|
241
|
+
*
|
|
242
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
243
|
+
* @since 1.2.1
|
|
244
|
+
* @version 1.2.1
|
|
245
|
+
*
|
|
246
|
+
* @return {Object}
|
|
247
|
+
*/
|
|
248
|
+
Backed.setMethod(Symbol.iterator, function* iterate() {
|
|
249
|
+
|
|
250
|
+
let value,
|
|
251
|
+
key;
|
|
252
|
+
|
|
253
|
+
for (key of this.keys()) {
|
|
254
|
+
value = this.get(key);
|
|
255
|
+
yield value;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The EnumValues class
|
|
3
|
+
*
|
|
4
|
+
* @constructor
|
|
5
|
+
*
|
|
6
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
|
+
* @since 1.2.1
|
|
8
|
+
* @version 1.2.1
|
|
9
|
+
*/
|
|
10
|
+
const EnumMap = Function.inherits('Alchemy.Map.Backed', 'Enum');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get a value by it's name
|
|
14
|
+
*
|
|
15
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
16
|
+
* @since 1.2.1
|
|
17
|
+
* @version 1.2.1
|
|
18
|
+
*
|
|
19
|
+
* @param {String} name
|
|
20
|
+
*
|
|
21
|
+
* @return {Mixed}
|
|
22
|
+
*/
|
|
23
|
+
EnumMap.setMethod(function get(name) {
|
|
24
|
+
|
|
25
|
+
if (this.local.has(name)) {
|
|
26
|
+
return this.local.get(name);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let value = get.super.call(this, name);
|
|
30
|
+
|
|
31
|
+
if (value) {
|
|
32
|
+
value = this.set(name, value);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return value;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Set a value
|
|
40
|
+
*
|
|
41
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
42
|
+
* @since 1.2.1
|
|
43
|
+
* @version 1.2.1
|
|
44
|
+
*
|
|
45
|
+
* @param {String} name
|
|
46
|
+
* @param {*} value
|
|
47
|
+
*
|
|
48
|
+
* @return {*}
|
|
49
|
+
*/
|
|
50
|
+
EnumMap.setMethod(function set(name, value) {
|
|
51
|
+
|
|
52
|
+
if (value == null) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (value.is_enumified) {
|
|
57
|
+
this.local.set(name, value);
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let result;
|
|
62
|
+
|
|
63
|
+
if (typeof value == 'string') {
|
|
64
|
+
result = {
|
|
65
|
+
name : value,
|
|
66
|
+
title : value,
|
|
67
|
+
};
|
|
68
|
+
} else if (typeof value == 'function') {
|
|
69
|
+
result = {
|
|
70
|
+
name : value.name,
|
|
71
|
+
title : value.title,
|
|
72
|
+
};
|
|
73
|
+
} else {
|
|
74
|
+
result = {
|
|
75
|
+
name : value.name,
|
|
76
|
+
title : value.title || value.name,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
result.value = value;
|
|
81
|
+
result.is_enumified = true;
|
|
82
|
+
|
|
83
|
+
this.local.set(name, result);
|
|
84
|
+
|
|
85
|
+
return result;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Simplify the object for Hawkejs
|
|
91
|
+
*
|
|
92
|
+
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
93
|
+
* @since 1.2.1
|
|
94
|
+
* @version 1.2.1
|
|
95
|
+
*
|
|
96
|
+
* @param {WeakMap} wm
|
|
97
|
+
*
|
|
98
|
+
* @return {Enum}
|
|
99
|
+
*/
|
|
100
|
+
EnumMap.setMethod(function toHawkejs(wm) {
|
|
101
|
+
|
|
102
|
+
let result = toHawkejs.super.call(this, wm),
|
|
103
|
+
original_value,
|
|
104
|
+
cloned_value,
|
|
105
|
+
keys = this.keys(),
|
|
106
|
+
key;
|
|
107
|
+
|
|
108
|
+
for (key of keys) {
|
|
109
|
+
original_value = this.get(key);
|
|
110
|
+
cloned_value = result.get(key);
|
|
111
|
+
|
|
112
|
+
if (original_value.value) {
|
|
113
|
+
|
|
114
|
+
if (typeof original_value.value == 'function') {
|
|
115
|
+
cloned_value.type = 'function';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (original_value.value.schema) {
|
|
119
|
+
cloned_value.schema = JSON.clone(original_value.value.schema, 'toHawkejs', wm);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return result;
|
|
125
|
+
});
|
|
@@ -266,7 +266,7 @@ Router.setMethod(function routeConfig(name, socket_route) {
|
|
|
266
266
|
*
|
|
267
267
|
* @author Jelle De Loecker <jelle@develry.be>
|
|
268
268
|
* @since 0.2.0
|
|
269
|
-
* @version 1.1
|
|
269
|
+
* @version 1.2.1
|
|
270
270
|
*
|
|
271
271
|
* @param {String} name
|
|
272
272
|
* @param {Object} parameters
|
|
@@ -331,6 +331,12 @@ Router.setMethod(function routeUrl(name, _parameters, options) {
|
|
|
331
331
|
// Remove [brackets]
|
|
332
332
|
url = url.replace(/\[.*?\]/g, '');
|
|
333
333
|
url = url.assign(parameters, true, RURL.encodeUriQuery);
|
|
334
|
+
|
|
335
|
+
// Remove capturing regexes
|
|
336
|
+
if (url.indexOf('(') > -1) {
|
|
337
|
+
// @TODO: should exclude escaped colons like "\\("
|
|
338
|
+
url = url.replace(/\(.*?\)/g, '');
|
|
339
|
+
}
|
|
334
340
|
}
|
|
335
341
|
|
|
336
342
|
url = this.parseURL(url);
|