alchemymvc 1.2.1 → 1.2.4

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.
@@ -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');
@@ -1,18 +1,20 @@
1
- var bcrypt = alchemy.use('bcrypt'),
2
- regex = /^\$2[ayb]\$/;
3
-
4
1
  /**
5
2
  * The Password Field class
6
3
  *
7
4
  * @constructor
8
5
  *
9
- * @author Jelle De Loecker <jelle@develry.be>
6
+ * @author Jelle De Loecker <jelle@elevenways.be>
10
7
  * @since 0.2.0
11
- * @version 1.1.0
8
+ * @version 1.2.3
12
9
  */
13
- var Password = Function.inherits('Alchemy.Field', function Password(schema, name, options) {
14
- Password.super.call(this, schema, name, options);
15
- });
10
+ const Password = Function.inherits('Alchemy.Field', 'Password');
11
+
12
+ if (Blast.isBrowser) {
13
+ return true;
14
+ }
15
+
16
+ const bcrypt = alchemy.use('bcrypt'),
17
+ regex = /^\$2[ayb]\$/;
16
18
 
17
19
  /**
18
20
  * Make sure the password is hashed before storing it
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * @author Jelle De Loecker <jelle@develry.be>
7
7
  * @since 0.2.0
8
- * @version 1.1.3
8
+ * @version 1.2.4
9
9
  */
10
10
  var SchemaField = Function.inherits('Alchemy.Field', function Schema(schema, name, options) {
11
11
  Schema.super.call(this, schema, name, options);
@@ -21,18 +21,20 @@ var SchemaField = Function.inherits('Alchemy.Field', function Schema(schema, nam
21
21
  this.field_schema.setName(name);
22
22
  }
23
23
 
24
- if (!this.field_schema.parent || schema.root_schema == this.field_schema.parent) {
25
- this.field_schema.setParent(schema);
26
- } else {
27
- // It's possible the given schema already had the correct parent
28
- // But if that's not the case, throw an error
29
- if (this.field_schema.parent != schema) {
30
- throw new Error('Unable to re-use a schema for field "' + name + '", use `schema.clone()`!');
24
+ if (schema) {
25
+ if (!this.field_schema.parent || schema.root_schema == this.field_schema.parent) {
26
+ this.field_schema.setParent(schema);
27
+ } else {
28
+ // It's possible the given schema already had the correct parent
29
+ // But if that's not the case, throw an error
30
+ if (this.field_schema.parent != schema) {
31
+ throw new Error('Unable to re-use a schema for field "' + name + '", use `schema.clone()`!');
32
+ }
31
33
  }
32
- }
33
34
 
34
- if (!this.field_schema.model_name) {
35
- this.field_schema.setModel(schema.model_name);
35
+ if (!this.field_schema.model_name) {
36
+ this.field_schema.setModel(schema.model_name);
37
+ }
36
38
  }
37
39
  });
38
40
 
@@ -242,7 +244,7 @@ SchemaField.setMethod(function _toDatasource(value, data, datasource, callback)
242
244
  *
243
245
  * @author Jelle De Loecker <jelle@develry.be>
244
246
  * @since 0.2.0
245
- * @version 1.1.0
247
+ * @version 1.2.4
246
248
  *
247
249
  * @param {Mixed} value
248
250
  * @param {Function} callback
@@ -262,6 +264,12 @@ SchemaField.setMethod(function _toApp(query, options, value, callback) {
262
264
  recursive = 1;
263
265
  }
264
266
 
267
+ if (recursive && Blast.isBrowser) {
268
+ // @TODO: this will mostly fail on the browser, so disable it for now.
269
+ // Maybe make it configurable later
270
+ recursive = 0;
271
+ }
272
+
265
273
  // Get associated records if the subschema has associations defined
266
274
  if (recursive && this.field_schema && !Object.isEmpty(this.field_schema.associations)) {
267
275
 
@@ -59,7 +59,7 @@ Criteria.setStatic(function isCriteria(instance) {
59
59
  *
60
60
  * @author Jelle De Loecker <jelle@develry.be>
61
61
  * @since 1.1.0
62
- * @version 1.1.5
62
+ * @version 1.2.3
63
63
  *
64
64
  * @param {Object} data
65
65
  *
@@ -81,10 +81,14 @@ Criteria.setStatic(function unDry(data) {
81
81
  // Revive the group instance
82
82
  criteria.group = Group.revive(data.group, criteria);
83
83
 
84
+ if(!data.options) {
85
+ data.options = {};
86
+ }
87
+
84
88
  // Revive the select
85
89
  data.options.select = Select.revive(data.options.select, criteria);
86
90
 
87
- criteria.options = data.options;
91
+ criteria.options = data.options || {};
88
92
 
89
93
  return criteria;
90
94
  });
@@ -248,7 +252,7 @@ Criteria.setProperty(function recursive_level() {
248
252
  *
249
253
  * @author Jelle De Loecker <jelle@develry.be>
250
254
  * @since 1.1.0
251
- * @version 1.1.0
255
+ * @version 1.2.3
252
256
  */
253
257
  Criteria.setMethod(Blast.checksumSymbol, function toChecksum() {
254
258
 
@@ -259,7 +263,7 @@ Criteria.setMethod(Blast.checksumSymbol, function toChecksum() {
259
263
 
260
264
  for (key in this.options) {
261
265
 
262
- if (key == 'init_model' || key == 'init_record') {
266
+ if (key == 'init_model' || key == 'init_record' || key == 'assoc_cache') {
263
267
  continue;
264
268
  }
265
269
 
@@ -319,21 +323,30 @@ Criteria.setMethod(Symbol.asyncIterator, function asyncIterator() {
319
323
  *
320
324
  * @author Jelle De Loecker <jelle@develry.be>
321
325
  * @since 1.1.0
322
- * @version 1.1.5
326
+ * @version 1.2.3
323
327
  *
324
328
  * @return {Object}
325
329
  */
326
330
  Criteria.setMethod(function toJSON() {
327
331
 
328
- var result = {},
329
- options = Object.assign({}, this.options);
332
+ let result = {},
333
+ options;
330
334
 
331
335
  if (this.model && this.model.name) {
332
336
  result.model = this.model.name;
333
337
  }
334
338
 
335
- if (options.init_record) {
336
- options.init_record = null;
339
+ if (this.options) {
340
+ let key;
341
+ options = {};
342
+
343
+ for (key in this.options) {
344
+ if (key == 'assoc_cache' || key == 'init_record') {
345
+ continue;
346
+ }
347
+
348
+ options[key] = this.options[key];
349
+ }
337
350
  }
338
351
 
339
352
  result.group = this.group;
@@ -388,7 +401,7 @@ Criteria.setMethod(function clone() {
388
401
  *
389
402
  * @author Jelle De Loecker <jelle@develry.be>
390
403
  * @since 1.1.0
391
- * @version 1.2.0
404
+ * @version 1.2.3
392
405
  *
393
406
  * @return {String[]}
394
407
  */
@@ -396,14 +409,14 @@ Criteria.setMethod(function getFieldsToSelect() {
396
409
 
397
410
  let result;
398
411
 
399
- if (this.options.select.fields && this.options.select.fields.length) {
412
+ if (this.options?.select?.fields?.length) {
400
413
  result = this.options.select.fields.slice(0);
401
414
  }
402
415
 
403
416
  // Fields can sometimes be required for a query (like in a join) but they
404
417
  // won't be selected if other fields are explicitly set.
405
418
  // So in that case: add these special fields to the projection
406
- if (result && this.options.select.query_fields && this.options.select.query_fields) {
419
+ if (result && this.options?.select?.query_fields) {
407
420
  result.push(...this.options.select.query_fields);
408
421
  }
409
422
 
@@ -479,7 +492,7 @@ Criteria.setMethod(function getAssociationConfiguration(alias) {
479
492
  *
480
493
  * @author Jelle De Loecker <jelle@develry.be>
481
494
  * @since 1.1.0
482
- * @version 1.1.0
495
+ * @version 1.2.3
483
496
  *
484
497
  * @param {String} name
485
498
  * @param {Object} item
@@ -524,6 +537,16 @@ Criteria.setMethod(function getCriteriaForAssociation(name, item) {
524
537
  assoc_crit.setOption('assoc_key', assoc_key);
525
538
  assoc_crit.setOption('assoc_value', value);
526
539
 
540
+ // Make the assoc_cache if it doesn't exist yet
541
+ if (options.create_references !== false && !options.assoc_cache) {
542
+ options.assoc_cache = {};
543
+ }
544
+
545
+ // Add the assoc_cache
546
+ if (options.assoc_cache) {
547
+ assoc_crit.setOption('assoc_cache', options.assoc_cache);
548
+ }
549
+
527
550
  // Take over the locale option
528
551
  if (options.locale) {
529
552
  assoc_crit.setOption('locale', options.locale);
@@ -1310,13 +1333,17 @@ var Select = Function.inherits('Alchemy.Base', 'Alchemy.Criteria', function Sele
1310
1333
  *
1311
1334
  * @author Jelle De Loecker <jelle@develry.be>
1312
1335
  * @since 1.1.0
1313
- * @version 1.1.0
1336
+ * @version 1.2.3
1314
1337
  *
1315
1338
  * @return {Select}
1316
1339
  */
1317
1340
  Select.setStatic(function revive(data, criteria) {
1318
1341
 
1319
- var result = new Select(criteria),
1342
+ if (!data) {
1343
+ return;
1344
+ }
1345
+
1346
+ let result = new Select(criteria),
1320
1347
  key;
1321
1348
 
1322
1349
  result.fields = data.fields;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The DataProvider class
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 1.2.2
6
+ * @version 1.2.2
7
+ */
8
+ const DataProvider = Function.inherits('Alchemy.Base', 'Alchemy.DataProvider', function DataProvider(config) {
9
+ this.config = config || {};
10
+ });
11
+
12
+
13
+ /**
14
+ * Undry
15
+ *
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
17
+ * @since 1.2.2
18
+ * @version 1.2.2
19
+ *
20
+ * @param {Object} obj
21
+ * @param {Boolean|String} cloned
22
+ *
23
+ * @return {DataProvider}
24
+ */
25
+ DataProvider.setStatic(function unDry(obj) {
26
+ let result = new this(obj.config);
27
+ return result;
28
+ });
29
+
30
+ /**
31
+ * Configure a new config
32
+ *
33
+ * @author Jelle De Loecker <jelle@elevenways.be>
34
+ * @since 1.2.2
35
+ * @version 1.2.2
36
+ */
37
+ DataProvider.setStatic(function addConfig(name, default_value) {
38
+ this.setProperty(name, function getValue() {
39
+
40
+ if (this.config[name] != null) {
41
+ return this.config[name];
42
+ }
43
+
44
+ return default_value;
45
+ }, function setValue(value) {
46
+ return this.config[name] = value;
47
+ });
48
+ });
49
+
50
+ /**
51
+ * The wanted page size
52
+ *
53
+ * @author Jelle De Loecker <jelle@elevenways.be>
54
+ * @since 1.2.2
55
+ * @version 1.2.2
56
+ */
57
+ DataProvider.addConfig('page_size');
58
+
59
+ /**
60
+ * Get all the data
61
+ *
62
+ * @author Jelle De Loecker <jelle@elevenways.be>
63
+ * @since 1.2.2
64
+ * @version 1.2.2
65
+ */
66
+ DataProvider.setAbstractMethod('getAll');
67
+
68
+ /**
69
+ * Get the data for the given page (pages are 1-index based)
70
+ *
71
+ * @author Jelle De Loecker <jelle@elevenways.be>
72
+ * @since 1.2.2
73
+ * @version 1.2.2
74
+ */
75
+ DataProvider.setAbstractMethod('getPage');
76
+
77
+ /**
78
+ * Return an object for json-drying this document
79
+ *
80
+ * @author Jelle De Loecker <jelle@elevenways.be>
81
+ * @since 1.2.2
82
+ * @version 1.2.2
83
+ *
84
+ * @return {Object}
85
+ */
86
+ DataProvider.setMethod(function toDry() {
87
+ return {
88
+ value : {
89
+ config : this.config,
90
+ }
91
+ };
92
+ });