@onehat/data 1.10.1 → 1.10.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.
@@ -1,4 +1,5 @@
1
1
  import Joi from 'Joi';
2
+ import * as yup from 'yup';
2
3
  import Entity from '../../src/Entity.js';
3
4
  import Schema from '../../src/Schema/index.js';
4
5
  import PropertyTypes from '../../src/Property/index.js';
@@ -746,37 +747,148 @@ describe('Entity', function() {
746
747
 
747
748
  describe('validators', function() {
748
749
 
749
- it('whole validation process', function() {
750
- let didFire = false;
751
- this.entity.on('changeValidity', (entity) => {
752
- didFire = true;
753
- });
750
+ it('Yup integration', function() {
751
+ (async () => {
752
+
753
+ // Recreate everything from beforeEach()
754
+ const schema = new Schema({
755
+ name: 'baz',
756
+ model: {
757
+ idProperty: 'foo',
758
+ displayProperty: 'bar',
759
+ properties: [
760
+ { name: 'foo', type: 'int' },
761
+ { name: 'bar' },
762
+ { name: 'baz', mapping: 'baz.test.val', type: 'bool', defaultValue: null, },
763
+ ],
764
+ validator: yup.object({
765
+ foo: yup.number()
766
+ .integer(),
767
+ bar: yup.string()
768
+ .required(),
769
+ baz: yup.mixed(),
770
+ }),
771
+ },
772
+ entity: {
773
+ methods: {
774
+ testMethod: function() {
775
+ this.azx = 'test me';
776
+ },
777
+ },
778
+ statics: {
779
+ azx: null,
780
+ },
781
+ },
782
+ }),
783
+ data = {
784
+ foo: 1,
785
+ bar: 'one',
786
+ baz: {
787
+ test: {
788
+ val: true,
789
+ },
790
+ },
791
+ },
792
+ entity = new Entity(schema, data);
793
+ entity.initialize();
794
+ // END recreate
754
795
 
755
- // Initial condition
756
- expect(this.entity.isValid).to.be.null;
757
-
758
- // Add validators
759
- this.schema.model.validator = Joi.object({
760
- foo: Joi.number()
761
- .integer(),
762
- bar: Joi.string()
763
- .alphanum()
764
- .required(),
765
- baz: Joi.any(),
766
- });
767
- const result = this.entity.validate();
768
- expect(result).to.be.true;
796
+ let didFire = false;
797
+ entity.on('changeValidity', (entity) => {
798
+ didFire = true;
799
+ });
769
800
 
770
- // Set a property to be invalid
771
- this.entity.bar = null;
772
- expect(didFire).to.be.true;
773
- expect(this.entity.isValid).to.be.false;
774
- expect(this.entity.validationError).to.match(/"bar" must be a string/);
801
+ // Initial condition
802
+ expect(entity.isValid).to.be.null;
803
+ await entity.validate();
804
+ expect(entity.isValid).to.be.true;
805
+ expect(didFire).to.be.true;
806
+
807
+ // Set a property to be invalid
808
+ entity.bar = null;
809
+ await entity.validate();
810
+ expect(entity.isValid).to.be.false;
811
+ expect(entity.validationError).to.match(/bar must be a `string`/);
812
+
813
+ // Restore validity
814
+ entity.bar = 'test';
815
+ await entity.validate();
816
+ expect(entity.isValid).to.be.true;
817
+ expect(!entity.validationError).to.be.true;
818
+
819
+ })();
820
+ });
821
+
822
+ it('Joi integration', function() {
823
+ (async () => {
824
+
825
+ // Recreate everything from beforeEach()
826
+ const schema = new Schema({
827
+ name: 'baz',
828
+ model: {
829
+ idProperty: 'foo',
830
+ displayProperty: 'bar',
831
+ properties: [
832
+ { name: 'foo', type: 'int' },
833
+ { name: 'bar' },
834
+ { name: 'baz', mapping: 'baz.test.val', type: 'bool', defaultValue: null, },
835
+ ],
836
+ validator: Joi.object({
837
+ foo: Joi.number()
838
+ .integer(),
839
+ bar: Joi.string()
840
+ .required(),
841
+ baz: Joi.any(),
842
+ }),
843
+ },
844
+ entity: {
845
+ methods: {
846
+ testMethod: function() {
847
+ this.azx = 'test me';
848
+ },
849
+ },
850
+ statics: {
851
+ azx: null,
852
+ },
853
+ },
854
+ }),
855
+ data = {
856
+ foo: 1,
857
+ bar: 'one',
858
+ baz: {
859
+ test: {
860
+ val: true,
861
+ },
862
+ },
863
+ },
864
+ entity = new Entity(schema, data);
865
+ entity.initialize();
866
+ // END recreate
867
+
868
+ let didFire = false;
869
+ entity.on('changeValidity', (entity) => {
870
+ didFire = true;
871
+ });
775
872
 
776
- // Restore validity
777
- this.entity.bar = 'test';
778
- expect(this.entity.isValid).to.be.true;
779
- expect(this.entity.validationError).to.be.null;
873
+ // Initial condition
874
+ expect(entity.isValid).to.be.null;
875
+ await entity.validate();
876
+ expect(entity.isValid).to.be.true;
877
+ expect(didFire).to.be.true;
878
+
879
+ // Set a property to be invalid
880
+ entity.bar = null;
881
+ await entity.validate();
882
+ expect(entity.isValid).to.be.false;
883
+ expect(entity.validationError).to.match(/"bar" must be a string/);
884
+
885
+ // Restore validity
886
+ entity.bar = 'test';
887
+ await entity.validate();
888
+ expect(entity.isValid).to.be.true;
889
+ expect(!entity.validationError).to.be.true;
890
+
891
+ })();
780
892
  });
781
893
  });
782
894
 
@@ -1,4 +1,3 @@
1
- import Joi from 'Joi';
2
1
  import PropertyTypes from '../../../src/Property/index.js';
3
2
  import Entity from '../../../src/Entity.js';
4
3
  import Schema from '../../../src/Schema/index.js';
@@ -234,51 +233,4 @@ describe('Property', function() {
234
233
 
235
234
  });
236
235
 
237
- describe('validators', function() {
238
-
239
- it('whole validation process', function() {
240
- let didFire = false;
241
- this.property.on('changeValidity', (entity) => {
242
- didFire = true;
243
- });
244
-
245
- // Initial condition
246
- expect(this.property.isValid).to.be.null;
247
-
248
- // Add validators
249
- const schema = new Schema({
250
- name: 'baz',
251
- model: {
252
- idProperty: 'foo',
253
- displayProperty: 'bar',
254
- properties: [
255
- { name: 'foo', type: 'int' },
256
- { name: 'bar' },
257
- ],
258
- validator: Joi.object({
259
- foo: Joi.number()
260
- .integer(),
261
- }),
262
- },
263
- }),
264
- entity = new Entity(schema);
265
- entity.initialize();
266
- const property = entity.getProperty('foo');
267
- property.setValue(2);
268
-
269
- const result = property.validate();
270
- expect(result).to.be.true;
271
-
272
- // Set a property to be invalid
273
- property.setValue(null);
274
- expect(property.isValid).to.be.false;
275
- expect(property.validationError).to.match(/"foo" must be a number/);
276
-
277
- // Restore validity
278
- property.setValue(2);
279
- expect(property.isValid).to.be.true;
280
- expect(property.validationError).to.be.null;
281
- });
282
- });
283
-
284
236
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.10.1",
3
+ "version": "1.10.3",
4
4
  "description": "JS data modeling package with adapters for many storage mediums.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/Entity.js CHANGED
@@ -297,7 +297,7 @@ class Entity extends EventEmitter {
297
297
  */
298
298
  _onPropertyChange = () => {
299
299
  this._recalculateDependentProperties();
300
- this.validate();
300
+ this.isValid = null;
301
301
  this.emit('change', this._proxy);
302
302
  }
303
303
 
@@ -1148,7 +1148,7 @@ class Entity extends EventEmitter {
1148
1148
 
1149
1149
  if (isChanged) {
1150
1150
  this._recalculateDependentProperties();
1151
- this.validate();
1151
+ this.isValid = null;
1152
1152
  this.emit('change', this._proxy);
1153
1153
  }
1154
1154
  return isChanged;
@@ -1310,18 +1310,26 @@ class Entity extends EventEmitter {
1310
1310
  * Gets whether or not the Entity validates according to schema's validation rules
1311
1311
  * @return {boolean} isValid
1312
1312
  */
1313
- validate = () => {
1313
+ validate = async () => {
1314
1314
  if (this.isDestroyed) {
1315
1315
  throw Error('this.validate is no longer valid. Entity has been destroyed.');
1316
1316
  }
1317
1317
 
1318
+ const submitValues = this.submitValues;
1318
1319
  let isValid = null,
1320
+ validationResult,
1319
1321
  error;
1320
1322
 
1321
1323
  if (this.schema.model.validator) {
1322
- const validationResult = this.schema.model.validator.validate(this.submitValues);
1323
- error = validationResult && validationResult.error || null;
1324
- isValid = !error;
1324
+ const validator = this.schema.model.validator;
1325
+ try {
1326
+ validationResult = await validator.validate(submitValues);
1327
+ error = validationResult.error; // Joi would populate 'error' if validation error. Yup would throw Error
1328
+ isValid = !error; // 'error' would be truthy if Joi error occurs, would never *get* here if an error with Yup
1329
+ } catch(e) {
1330
+ error = e; // yup error only
1331
+ isValid = false;
1332
+ }
1325
1333
  if (this.validationError !== error) {
1326
1334
  this.validationError = error;
1327
1335
  }
@@ -160,17 +160,6 @@ export default class Property extends EventEmitter {
160
160
  * @private
161
161
  */
162
162
  this.isDestroyed = false;
163
-
164
- /**
165
- * @member {boolean} isValid - Whether this Property passes validation
166
- * @private
167
- */
168
- this.isValid = null;
169
-
170
- /**
171
- * @member {object} validationError - Any error in last validation.
172
- */
173
- this.validationError = null;
174
163
 
175
164
  }
176
165
 
@@ -369,7 +358,6 @@ export default class Property extends EventEmitter {
369
358
  if (isChanged) {
370
359
  this.rawValue = rawValue;
371
360
  this.parsedValue = newValue;
372
- this.validate();
373
361
  this.emit('change', this, oldValue, newValue);
374
362
  }
375
363
 
@@ -446,43 +434,6 @@ export default class Property extends EventEmitter {
446
434
  return this.mapping;
447
435
  }
448
436
 
449
- // _ __ ___ __ __ _
450
- // | | / /___ _/ (_)___/ /___ _/ /_(_)___ ____
451
- // | | / / __ `/ / / __ / __ `/ __/ / __ \/ __ \
452
- // | |/ / /_/ / / / /_/ / /_/ / /_/ / /_/ / / / /
453
- // |___/\__,_/_/_/\__,_/\__,_/\__/_/\____/_/ /_/
454
-
455
- /**
456
- * Gets whether or not the Property validates according to schema's validation rules
457
- * @return {boolean} isValid
458
- */
459
- validate = () => {
460
- if (this.isDestroyed) {
461
- throw Error('this.validate is no longer valid. Entity has been destroyed.');
462
- }
463
-
464
- let isValid = null,
465
- error;
466
-
467
- if (this._entity?.schema?.model?.validator) {
468
- const obj = {};
469
- obj[this.name] = this.submitValue;
470
- const validationResult = this._entity.schema.model.validator.validate(obj);
471
- error = validationResult && validationResult.error || null;
472
- isValid = !error;
473
- if (this.validationError !== error) {
474
- this.validationError = error;
475
- }
476
- }
477
-
478
- if (this.isValid !== isValid) {
479
- this.emit('changeValidity', this._proxy, isValid);
480
- this.isValid = isValid;
481
- }
482
-
483
- return isValid;
484
- }
485
-
486
437
  /**
487
438
  * Destroy this object.
488
439
  * - Removes all circular references to parent objects
@@ -253,8 +253,11 @@ class MemoryRepository extends Repository {
253
253
  static _getNatSort = (sorter) => {
254
254
  const
255
255
  name = sorter.name,
256
- direction = sorter.direction.toUpperCase(),
257
- sortFn = natsort.default({ desc: direction !== 'ASC', });
256
+ direction = sorter.direction.toUpperCase();
257
+
258
+ const ns = natsort.default || natsort; // When imported into cypress, natsort has default, when in React Native, it doesn't.
259
+
260
+ const sortFn = ns({ desc: direction !== 'ASC', });
258
261
  return (entity1, entity2) => {
259
262
  const
260
263
  a = entity1[name],