alchemymvc 1.2.0 → 1.2.3

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.
@@ -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.5
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);
@@ -8,151 +8,98 @@
8
8
  * @since 0.0.1
9
9
  * @version 1.0.0
10
10
  */
11
- var Paginate = Function.inherits('Alchemy.Client.Component', function Paginate(controller, options) {
12
- Paginate.super.call(this, controller, options);
13
- });
11
+ const Paginate = Function.inherits('Alchemy.Client.Component', 'Paginate');
14
12
 
15
13
  /**
16
14
  * Perform a query
17
15
  *
18
- * @author Jelle De Loecker <jelle@develry.be>
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
19
17
  * @since 0.0.1
20
- * @version 1.0.6
18
+ * @version 1.2.2
21
19
  *
22
20
  * @param {Model} model
23
- * @param {Object} options
24
- * @param {Function} callback
21
+ * @param {Criteria} criteria
25
22
  *
26
23
  * @return {Pledge}
27
24
  */
28
- Paginate.setMethod(function find(model, options, callback) {
29
-
30
- var that = this,
31
- conduit = this.controller.conduit,
32
- conditions,
33
- last_id,
34
- filter,
35
- pledge,
36
- order,
37
- name,
38
- sort;
25
+ Paginate.setMethod(function find(model, criteria) {
26
+
27
+ const conduit = this.controller.conduit;
39
28
 
40
29
  // Get the model if a name has been given
41
30
  if (typeof model == 'string') {
42
31
  model = this.getModel(model);
43
32
  }
44
33
 
45
- // Make sure callback is set correctly
46
- if (typeof options == 'function') {
47
- callback = options;
48
- }
49
-
50
- // Make sure options is an object
51
- if (!options || typeof options != 'object') {
52
- options = {};
53
- }
54
-
55
- // Set the name for this pagination
56
- if (!options.name) {
57
- options.name = model.name;
58
- } else {
59
- options.name = options.name.modelName();
60
- }
34
+ let page_size = criteria.options.page_size || 10,
35
+ skipless = criteria.options.skipless,
36
+ last_id,
37
+ name = criteria.options.name,
38
+ page = criteria.options.page;
61
39
 
62
- if (!options.pageSize) {
63
- options.pageSize = 10;
40
+ if (!name) {
41
+ name = model.name;
42
+ criteria.setOption('name', name);
64
43
  }
65
44
 
66
- if (options.skipless) {
67
- last_id = options.last_id || conduit.param('page');
45
+ if (skipless) {
46
+ let sort;
47
+ last_id = criteria.options.last_id || conduit.param('page');
68
48
 
69
49
  // When it's a skipless pagination,
70
50
  // a sort is always implied
71
- if (options.skipless === true) {
51
+ if (skipless === true) {
72
52
  sort = {_id: 1};
73
53
  } else {
74
54
  sort = {};
75
- sort[options.skipless] = 1;
55
+ sort[skipless] = 1;
76
56
  }
77
57
 
78
- options.sort = sort;
79
-
58
+ criteria.sort(sort);
80
59
  } else {
81
60
 
82
61
  // If no page has been given
83
- if (typeof options.page != 'number') {
84
- options.page = conduit.param('page');
62
+ if (typeof page != 'number') {
63
+ page = conduit.param('page');
85
64
  }
86
65
 
87
- if (options.page < 0 || !options.page) {
88
- options.page = 1;
66
+ if (page < 0 || !page) {
67
+ page = 1;
89
68
  }
90
69
 
91
- options.offset = (options.page-1) * options.pageSize;
92
-
93
- sort = conduit.param('sort');
70
+ let sort = conduit.param('sort');
94
71
 
95
72
  if (sort) {
96
73
  // Always override the sort
97
- options.sort = {};
74
+ let new_sort = {};
98
75
 
99
76
  order = conduit.param('order');
100
77
 
101
78
  if (typeof order == 'string' && order.toLowerCase() == 'desc') {
102
- options.sort[sort] = -1;
79
+ new_sort[sort] = -1;
103
80
  } else {
104
- options.sort[sort] = 1;
81
+ new_sort[sort] = 1;
105
82
  }
106
- }
107
- }
108
-
109
- options.limit = options.pageSize;
110
83
 
111
- if (conduit.param('filter_field') && conduit.param('filter_value')) {
112
- conditions = {};
113
- conditions[conduit.param('filter_field')] = RegExp.interpret('/.*' + conduit.param('filter_value') + '.*/i');
114
- options.conditions = conditions;
115
- }
116
-
117
- filter = conduit.param('filter');
118
-
119
- if (filter) {
120
- if (!conditions) {
121
- conditions = {};
84
+ criteria.sort(new_sort);
122
85
  }
123
86
 
124
- options.conditions = conditions;
125
-
126
- for (name in filter) {
127
- if (filter[name] !== '') {
128
- conditions[name] = RegExp.interpret('/.*' + filter[name] + '.*/i');
129
- }
87
+ if (page) {
88
+ criteria.page(page, page_size);
130
89
  }
131
90
  }
132
91
 
133
92
  if (last_id) {
134
- if (!options.conditions) {
135
- options.conditions = {};
136
- }
137
-
138
- if (!options.conditions.$and) {
139
- options.conditions.$and = [];
140
- }
141
-
142
- let entry = {};
143
-
144
- if (options.skipless === true) {
145
- entry._id = {$gt: alchemy.castObjectId(last_id)};
93
+ if (skipless === true) {
94
+ criteria.where('_id').gt(last_id);
146
95
  } else {
147
- entry[options.skipless] = {$gt: last_id};
96
+ criteria.where(skipless).gt(last_id);
148
97
  }
149
-
150
- options.conditions.$and.push(entry);
151
98
  }
152
99
 
153
- options.available = true;
100
+ criteria.setOption('available', true);
154
101
 
155
- pledge = model.find('all', options, function findAllPaginate(err, result) {
102
+ let pledge = model.find('all', criteria, function findAllPaginate(err, result) {
156
103
 
157
104
  if (err) {
158
105
  return;
@@ -166,21 +113,19 @@ Paginate.setMethod(function find(model, options, callback) {
166
113
  }
167
114
 
168
115
  let entry = {
169
- page : options.page,
170
- size : options.pageSize,
116
+ page : page,
117
+ size : page_size,
171
118
  items : result.available,
172
- pages : Math.ceil(result.available/options.pageSize),
173
- skipless : options.skipless
119
+ pages : Math.ceil(result.available/page_size),
120
+ skipless : skipless
174
121
  };
175
122
 
176
- if (options.skipless && result.length) {
123
+ if (skipless && result.length) {
177
124
  entry.last_id = result.last()._id;
178
125
  }
179
126
 
180
- PageInfo[options.name] = entry;
127
+ PageInfo[name] = entry;
181
128
  });
182
129
 
183
- pledge.handleCallback(callback);
184
-
185
130
  return pledge;
186
131
  });
@@ -34,7 +34,7 @@ var Conduit = Function.inherits('Alchemy.Client.Base', 'Alchemy.Client.Conduit',
34
34
  *
35
35
  * @author Jelle De Loecker <jelle@develry.be>
36
36
  * @since 1.1.0
37
- * @version 1.1.0
37
+ * @version 1.2.2
38
38
  *
39
39
  * @param {RURL} url
40
40
  * @param {Object} options
@@ -121,17 +121,19 @@ Conduit.setStatic(function handleUrlLocal(url, options) {
121
121
  conduit = new Conduit(url, options);
122
122
  }
123
123
 
124
- for (let key in options) {
125
- let info = Blast.Classes.Develry.Request.getMethodInfo(key);
124
+ if (conduit) {
125
+ for (let key in options) {
126
+ let info = Blast.Classes.Develry.Request.getMethodInfo(key);
126
127
 
127
- if (info && info.method != 'GET') {
128
- conduit.method = info.method.toLowerCase();
129
- break;
128
+ if (info && info.method != 'GET') {
129
+ conduit.method = info.method.toLowerCase();
130
+ break;
131
+ }
130
132
  }
131
- }
132
133
 
133
- if (!conduit.method) {
134
- conduit.method = 'get';
134
+ if (!conduit.method) {
135
+ conduit.method = 'get';
136
+ }
135
137
  }
136
138
 
137
139
  Function.series(tasks, function done(err) {
@@ -590,7 +590,7 @@ NoSQL.setStatic(function areComparable(a, b) {
590
590
  *
591
591
  * @author Jelle De Loecker <jelle@develry.be>
592
592
  * @since 1.1.0
593
- * @version 1.1.2
593
+ * @version 1.2.2
594
594
  *
595
595
  * @param {Criteria} criteria
596
596
  * @param {Group} group
@@ -798,6 +798,10 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
798
798
  {$exists: exists}
799
799
  ];
800
800
 
801
+ if (!entry.field) {
802
+ throw new Error('Could not find field for path "' + entry.target_path + '" in model ' + entry.model.name);
803
+ }
804
+
801
805
  if (entry.field.is_array) {
802
806
  $or.push({[comparator]: []});
803
807
  } else if (entry.field instanceof Classes.Alchemy.Field.String) {
@@ -7,9 +7,7 @@
7
7
  * @since 0.2.0
8
8
  * @version 1.1.0
9
9
  */
10
- var StringField = Function.inherits('Alchemy.Field', function String(schema, name, options) {
11
- String.super.call(this, schema, name, options);
12
- });
10
+ var StringField = Function.inherits('Alchemy.Field', 'String');
13
11
 
14
12
  /**
15
13
  * Set the datatype name
@@ -7,23 +7,4 @@
7
7
  * @since 0.2.0
8
8
  * @version 1.1.0
9
9
  */
10
- var BelongsTo = Function.inherits('Alchemy.Field.ObjectId', function BelongsTo(schema, name, options) {
11
- BelongsTo.super.call(this, schema, name, options);
12
-
13
- // @todo: set index stuff
14
- });
15
-
16
- /**
17
- * Load remote data for some fields
18
- *
19
- * @author Jelle De Loecker <jelle@elevenways.be>
20
- * @since 0.2.0
21
- * @version 0.2.0
22
- *
23
- * @param {Object} config
24
- */
25
- BelongsTo.setMethod(async function loadData(config) {
26
-
27
-
28
-
29
- });
10
+ const BelongsTo = Function.inherits('Alchemy.Field.ObjectId', 'BelongsTo');