@onehat/data 1.10.0 → 1.10.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.
|
@@ -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('
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
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
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
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
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
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.
|
|
3
|
+
"version": "1.10.2",
|
|
4
4
|
"description": "JS data modeling package with adapters for many storage mediums.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"chrono-node": "^2.4.2",
|
|
42
42
|
"fast-xml-parser": "^4.0.12",
|
|
43
43
|
"he": "^1.2.0",
|
|
44
|
-
"joi": "^17.7.0",
|
|
45
44
|
"js-base64": "^3.7.3",
|
|
46
45
|
"lodash": "^4.17.21",
|
|
47
46
|
"moment": "^2.29.4",
|
|
@@ -64,6 +63,9 @@
|
|
|
64
63
|
"cypress": "5.2.0",
|
|
65
64
|
"ink-docstrap": "^1.3.2",
|
|
66
65
|
"jsdoc": "^4.0.0",
|
|
67
|
-
"webpack": "^5.75.0"
|
|
66
|
+
"webpack": "^5.75.0",
|
|
67
|
+
"joi": "^17.7.0",
|
|
68
|
+
"yup": "^0.32.11"
|
|
69
|
+
|
|
68
70
|
}
|
|
69
71
|
}
|
package/src/Entity.js
CHANGED
|
@@ -297,7 +297,7 @@ class Entity extends EventEmitter {
|
|
|
297
297
|
*/
|
|
298
298
|
_onPropertyChange = () => {
|
|
299
299
|
this._recalculateDependentProperties();
|
|
300
|
-
this.
|
|
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.
|
|
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
|
|
1323
|
-
|
|
1324
|
-
|
|
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
|
}
|
package/src/Property/Property.js
CHANGED
|
@@ -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
|
package/src/Schema/Schema.js
CHANGED
|
@@ -73,7 +73,7 @@ export default class Schema extends EventEmitter {
|
|
|
73
73
|
sorters: [],
|
|
74
74
|
|
|
75
75
|
/**
|
|
76
|
-
* @member {object} validators - A
|
|
76
|
+
* @member {object} validators - A validator schema. Could use Joi (https://joi.dev), Yup (https://github.com/jquense/yup), or another comparable library
|
|
77
77
|
*/
|
|
78
78
|
validator: null,
|
|
79
79
|
|