@onehat/data 1.6.1 → 1.6.6
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/cypress/fixtures/Definitions/GroupsUsers.js +15 -0
- package/cypress/integration/Entity.spec.js +12 -1
- package/cypress/integration/OneHatData.spec.js +15 -0
- package/cypress/integration/Repository/Repository.spec.js +12 -0
- package/cypress/integration/Schema.spec.js +5 -0
- package/package.json +1 -1
- package/src/Entity.js +66 -0
- package/src/OneHatData.js +16 -3
- package/src/Repository/Ajax.js +1 -10
- package/src/Repository/Repository.js +32 -3
- package/src/Schema/Schema.js +7 -2
|
@@ -25,6 +25,21 @@ const GroupsUsers = {
|
|
|
25
25
|
{ name: 'users__last_login', mapping: 'user.last_login', type: 'datetime' },
|
|
26
26
|
],
|
|
27
27
|
|
|
28
|
+
associations: {
|
|
29
|
+
hasOne: [
|
|
30
|
+
'Groups',
|
|
31
|
+
'Users',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
entity: {
|
|
38
|
+
methods: {
|
|
39
|
+
testMethod: function() {
|
|
40
|
+
this.users__login_count = this.users__login_count +1;
|
|
41
|
+
},
|
|
42
|
+
},
|
|
28
43
|
},
|
|
29
44
|
|
|
30
45
|
repository: 'onebuild',
|
|
@@ -17,6 +17,13 @@ describe('Entity', function() {
|
|
|
17
17
|
{ name: 'baz', mapping: 'baz.test.val', type: 'bool', defaultValue: null, },
|
|
18
18
|
],
|
|
19
19
|
},
|
|
20
|
+
entity: {
|
|
21
|
+
methods: {
|
|
22
|
+
testMethod: function() {
|
|
23
|
+
this.bar = 'test me';
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
20
27
|
});
|
|
21
28
|
this.data = {
|
|
22
29
|
foo: 1,
|
|
@@ -71,7 +78,6 @@ describe('Entity', function() {
|
|
|
71
78
|
entity.markSaved();
|
|
72
79
|
expect(entity.isTempId).to.be.false;
|
|
73
80
|
});
|
|
74
|
-
|
|
75
81
|
|
|
76
82
|
it('clone', function() {
|
|
77
83
|
const entity = this.entity;
|
|
@@ -100,6 +106,11 @@ describe('Entity', function() {
|
|
|
100
106
|
expect(entity.properties.bar.name).to.be.eq('bar');
|
|
101
107
|
expect(entity.properties.baz.name).to.be.eq('baz');
|
|
102
108
|
});
|
|
109
|
+
|
|
110
|
+
it('_createMethods', function() {
|
|
111
|
+
this.entity.testMethod();
|
|
112
|
+
expect(this.entity.bar).to.be.eq('test me');
|
|
113
|
+
});
|
|
103
114
|
|
|
104
115
|
it('loadOriginalData', function() {
|
|
105
116
|
const data = {
|
|
@@ -175,6 +175,21 @@ describe('OneHatData', function() {
|
|
|
175
175
|
})();
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
+
it('hasRepository', function() {
|
|
179
|
+
(async function() {
|
|
180
|
+
await beforeEach();
|
|
181
|
+
|
|
182
|
+
const oneHatData = new OneHatData();
|
|
183
|
+
oneHatData.createSchemas([
|
|
184
|
+
{ name: 'foo', },
|
|
185
|
+
]);
|
|
186
|
+
oneHatData.createBoundRepositories();
|
|
187
|
+
expect(oneHatData.hasRepository('foo')).to.be.true;
|
|
188
|
+
|
|
189
|
+
afterEach();
|
|
190
|
+
})();
|
|
191
|
+
});
|
|
192
|
+
|
|
178
193
|
it('hasRepositoryWithId', function() {
|
|
179
194
|
(async function() {
|
|
180
195
|
await beforeEach();
|
|
@@ -685,6 +685,11 @@ describe('Repository Base', function() {
|
|
|
685
685
|
|
|
686
686
|
describe('deleting', function() {
|
|
687
687
|
|
|
688
|
+
it('clear', function() {
|
|
689
|
+
this.repository.clear();
|
|
690
|
+
expect(this.repository.entities.length).to.be.eq(0);
|
|
691
|
+
});
|
|
692
|
+
|
|
688
693
|
it('delete', function() {
|
|
689
694
|
let didFire = false;
|
|
690
695
|
this.repository.on('delete', () => {
|
|
@@ -698,6 +703,13 @@ describe('Repository Base', function() {
|
|
|
698
703
|
expect(didFire).to.be.true;
|
|
699
704
|
});
|
|
700
705
|
|
|
706
|
+
it('delete() / removeEntity', async function() {
|
|
707
|
+
this.repository.setAutoSave(false);
|
|
708
|
+
const entity = await this.repository.add({ value: 'six' });
|
|
709
|
+
this.repository.delete(entity);
|
|
710
|
+
expect(this.repository.entities.length).to.be.eq(5);
|
|
711
|
+
});
|
|
712
|
+
|
|
701
713
|
|
|
702
714
|
// I'm going to skip these, as they're just combinations of other, tested functions
|
|
703
715
|
// deleteByIx
|
|
@@ -10,6 +10,11 @@ describe('Schema', function() {
|
|
|
10
10
|
it('schema is valid', function() {
|
|
11
11
|
expect(this.schema instanceof Schema).to.be.true;
|
|
12
12
|
expect(this.schema.name).to.be.eq('GroupsUsers');
|
|
13
|
+
expect(this.schema.model.associations.hasOne).to.be.an('array');
|
|
14
|
+
expect(this.schema.model.associations.hasMany).to.be.an('array');
|
|
15
|
+
expect(this.schema.model.associations.belongsTo).to.be.an('array');
|
|
16
|
+
expect(this.schema.model.associations.belongsToMany).to.be.an('array');
|
|
17
|
+
expect(this.schema.entity.methods.testMethod).to.be.a('function');
|
|
13
18
|
expect(this.schema.repository.type).to.be.eq('onebuild');
|
|
14
19
|
});
|
|
15
20
|
|
package/package.json
CHANGED
package/src/Entity.js
CHANGED
|
@@ -150,10 +150,28 @@ class Entity extends EventEmitter {
|
|
|
150
150
|
|
|
151
151
|
initialize = () => {
|
|
152
152
|
this.properties = this._createProperties();
|
|
153
|
+
this._createMethods();
|
|
153
154
|
this.reset();
|
|
154
155
|
this.isInitialized = true;
|
|
155
156
|
}
|
|
156
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Creates the methods for this Entity, based on Schema.
|
|
160
|
+
* @private
|
|
161
|
+
*/
|
|
162
|
+
_createMethods = () => {
|
|
163
|
+
if (this.isDestroyed) {
|
|
164
|
+
throw Error('this._createMethods is no longer valid. Entity has been destroyed.');
|
|
165
|
+
}
|
|
166
|
+
const methodDefinitions = this.schema.entity.methods;
|
|
167
|
+
if (_.isEmpty(methodDefinitions)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
_.each(methodDefinitions, (method, name) => {
|
|
171
|
+
this[name] = method; // NOTE: Methods must be defined in schema as "function() {}", not as "() => {}" so "this" will be assigned correctly
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
157
175
|
/**
|
|
158
176
|
* Generates a new unique id and assigns it to this entity.
|
|
159
177
|
*/
|
|
@@ -380,6 +398,17 @@ class Entity extends EventEmitter {
|
|
|
380
398
|
return this.schema;
|
|
381
399
|
}
|
|
382
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Gets the Repository object
|
|
403
|
+
* @return {Repository} repository
|
|
404
|
+
*/
|
|
405
|
+
getRepository = () => {
|
|
406
|
+
if (this.isDestroyed) {
|
|
407
|
+
throw Error('this.getRepository is no longer valid. Entity has been destroyed.');
|
|
408
|
+
}
|
|
409
|
+
return this.repository;
|
|
410
|
+
}
|
|
411
|
+
|
|
383
412
|
/**
|
|
384
413
|
* Alias for this.properties
|
|
385
414
|
*/
|
|
@@ -833,6 +862,43 @@ class Entity extends EventEmitter {
|
|
|
833
862
|
return this._originalData;
|
|
834
863
|
}
|
|
835
864
|
|
|
865
|
+
/**
|
|
866
|
+
* Gets the associated Repository
|
|
867
|
+
* @param {string} repositoryName - Name of the Repository to retrieve
|
|
868
|
+
* @return {boolean} hasProperty
|
|
869
|
+
*/
|
|
870
|
+
getAssociatedRepository = (repositoryName) => {
|
|
871
|
+
if (this.isDestroyed) {
|
|
872
|
+
throw Error('this.getAssociatedRepository is no longer valid. Entity has been destroyed.');
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const schema = this.getSchema();
|
|
876
|
+
if (!schema.model.associations.hasOne.includes(repositoryName) &&
|
|
877
|
+
!schema.model.associations.hasMany.includes(repositoryName) &&
|
|
878
|
+
!schema.model.associations.belongsTo.includes(repositoryName) &&
|
|
879
|
+
!schema.model.associations.belongsToMany.includes(repositoryName)
|
|
880
|
+
) {
|
|
881
|
+
throw Error(repositoryName + ' is not associated with this schema');
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
const repository = this.getRepository();
|
|
885
|
+
if (!repository) {
|
|
886
|
+
throw Error('No repository on this entity');
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
const oneHatData = repository.oneHatData;
|
|
890
|
+
if (!oneHatData) {
|
|
891
|
+
throw Error('No global oneHatData object');
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const associatedRepository = oneHatData.getRepository(repositoryName);
|
|
895
|
+
if (!associatedRepository) {
|
|
896
|
+
throw Error('Repository ' + repositoryName + ' cannot be found');
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return associatedRepository;
|
|
900
|
+
}
|
|
901
|
+
|
|
836
902
|
|
|
837
903
|
|
|
838
904
|
// _____ __ __
|
package/src/OneHatData.js
CHANGED
|
@@ -254,8 +254,8 @@ export class OneHatData extends EventEmitter {
|
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
// Apply the general config settings to each specific one
|
|
257
|
-
const localConfig = _.
|
|
258
|
-
remoteConfig = _.
|
|
257
|
+
const localConfig = _.merge({}, generalConfig, config.local),
|
|
258
|
+
remoteConfig = _.merge({}, generalConfig, config.remote);
|
|
259
259
|
|
|
260
260
|
// Actually create the local and remote repositories
|
|
261
261
|
config.local = await this.createRepository(localConfig);
|
|
@@ -263,7 +263,7 @@ export class OneHatData extends EventEmitter {
|
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
const Repository = this._repositoryTypes[config.type],
|
|
266
|
-
repository = new Repository(config);
|
|
266
|
+
repository = new Repository(config, this);
|
|
267
267
|
await repository.initialize();
|
|
268
268
|
|
|
269
269
|
return repository;
|
|
@@ -442,6 +442,19 @@ export class OneHatData extends EventEmitter {
|
|
|
442
442
|
return schema.getBoundRepository();
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Checks whether the requested bound Repository exists.
|
|
447
|
+
* @param {string} name - Name of Schema
|
|
448
|
+
* @return {boolean} hasRepository
|
|
449
|
+
*/
|
|
450
|
+
hasRepository = (name) => {
|
|
451
|
+
if (this.isDestroyed) {
|
|
452
|
+
throw new Error('this.getRepository is no longer valid. OneHatData has been destroyed.');
|
|
453
|
+
}
|
|
454
|
+
const repository = this.getRepository(name);
|
|
455
|
+
return !!repository;
|
|
456
|
+
}
|
|
457
|
+
|
|
445
458
|
/**
|
|
446
459
|
* Get Repositories by a filter function
|
|
447
460
|
* @param {function} filter - Filter function
|
package/src/Repository/Ajax.js
CHANGED
|
@@ -370,7 +370,7 @@ class AjaxRepository extends Repository {
|
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
const repository = this;
|
|
373
|
-
const data = _.
|
|
373
|
+
const data = _.merge({}, this._baseParams, this._params);
|
|
374
374
|
|
|
375
375
|
return this._send(this.methods.get, this.api.get, data)
|
|
376
376
|
.then(result => {
|
|
@@ -678,15 +678,6 @@ class AjaxRepository extends Repository {
|
|
|
678
678
|
}));
|
|
679
679
|
}
|
|
680
680
|
|
|
681
|
-
/**
|
|
682
|
-
* Deletes all locally cached entities in repository,
|
|
683
|
-
* usually, the current "page".
|
|
684
|
-
* Does not actually affect anything on the server.
|
|
685
|
-
*/
|
|
686
|
-
clear = async () => {
|
|
687
|
-
this._destroyEntities();
|
|
688
|
-
}
|
|
689
|
-
|
|
690
681
|
}
|
|
691
682
|
|
|
692
683
|
AjaxRepository.className = 'Ajax';
|
|
@@ -23,7 +23,7 @@ export default class Repository extends EventEmitter {
|
|
|
23
23
|
* - name {string} - Optional. Defaults to schema.name
|
|
24
24
|
* - schema - Schema object
|
|
25
25
|
*/
|
|
26
|
-
constructor(config = {}) {
|
|
26
|
+
constructor(config = {}, oneHatData = null) {
|
|
27
27
|
super(...arguments);
|
|
28
28
|
|
|
29
29
|
const { schema } = config;
|
|
@@ -214,6 +214,11 @@ export default class Repository extends EventEmitter {
|
|
|
214
214
|
*/
|
|
215
215
|
this.isDestroyed = false;
|
|
216
216
|
|
|
217
|
+
/**
|
|
218
|
+
* @member {boolean} oneHatData - The global @onehat/data object
|
|
219
|
+
*/
|
|
220
|
+
this.oneHatData = oneHatData;
|
|
221
|
+
|
|
217
222
|
this.registerEvents([
|
|
218
223
|
'add',
|
|
219
224
|
'beforeSave',
|
|
@@ -972,6 +977,15 @@ export default class Repository extends EventEmitter {
|
|
|
972
977
|
this.entities = [];
|
|
973
978
|
}
|
|
974
979
|
|
|
980
|
+
/**
|
|
981
|
+
* Deletes all locally cached entities in repository,
|
|
982
|
+
* usually, the current "page".
|
|
983
|
+
* Does not actually affect anything on the server.
|
|
984
|
+
*/
|
|
985
|
+
clear = async () => {
|
|
986
|
+
this._destroyEntities();
|
|
987
|
+
}
|
|
988
|
+
|
|
975
989
|
/**
|
|
976
990
|
* Gets an array of "submit" values objects for the entities
|
|
977
991
|
* @return {array} map -
|
|
@@ -1365,7 +1379,7 @@ export default class Repository extends EventEmitter {
|
|
|
1365
1379
|
|
|
1366
1380
|
/**
|
|
1367
1381
|
* Marks entities for deletion from storage medium.
|
|
1368
|
-
* Actual deletion takes place in save()
|
|
1382
|
+
* Actual deletion takes place in save(), unless isPhantom
|
|
1369
1383
|
* @param {object|array} entities - one or more entities to delete
|
|
1370
1384
|
* @fires delete
|
|
1371
1385
|
*/
|
|
@@ -1381,7 +1395,12 @@ export default class Repository extends EventEmitter {
|
|
|
1381
1395
|
return;
|
|
1382
1396
|
}
|
|
1383
1397
|
_.each(entities, (entity) => {
|
|
1384
|
-
entity.
|
|
1398
|
+
if (entity.isPhantom) {
|
|
1399
|
+
// Just auto-remove it. Don't bother saving to storage medium.
|
|
1400
|
+
this.removeEntity(entity);
|
|
1401
|
+
} else {
|
|
1402
|
+
entity.markDeleted(); // Entity is still there, it's just marked for deletion
|
|
1403
|
+
}
|
|
1385
1404
|
});
|
|
1386
1405
|
|
|
1387
1406
|
this.emit('delete', entities);
|
|
@@ -1391,6 +1410,16 @@ export default class Repository extends EventEmitter {
|
|
|
1391
1410
|
}
|
|
1392
1411
|
}
|
|
1393
1412
|
|
|
1413
|
+
/**
|
|
1414
|
+
* Removes an Entity from the current page
|
|
1415
|
+
* Mainly used for phantom Entities
|
|
1416
|
+
* Helper for delete()
|
|
1417
|
+
*/
|
|
1418
|
+
removeEntity = async (entity) => {
|
|
1419
|
+
this.entities = _.filter(this.entities, e => e !== entity);
|
|
1420
|
+
entity.destroy();
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1394
1423
|
/**
|
|
1395
1424
|
* Deletes a single Entity by its index (zero-indexed) on the current page
|
|
1396
1425
|
* @param {integer} ix - Index
|
package/src/Schema/Schema.js
CHANGED
|
@@ -5,11 +5,12 @@ import _ from 'lodash';
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Class represents the Schema definition for Model and Source
|
|
8
|
-
* This is basically just a big config object, used to instantiate
|
|
8
|
+
* This is basically just a big config object, used to instantiate an Entity, and Repository.
|
|
9
9
|
* Usage:
|
|
10
10
|
* - const schema = new Schema({
|
|
11
11
|
* name: 'Users',
|
|
12
12
|
* model: {},
|
|
13
|
+
* entity: {},
|
|
13
14
|
* repository: {},
|
|
14
15
|
* });
|
|
15
16
|
*
|
|
@@ -96,6 +97,10 @@ export default class Schema extends EventEmitter {
|
|
|
96
97
|
belongsToMany: [],
|
|
97
98
|
},
|
|
98
99
|
},
|
|
100
|
+
|
|
101
|
+
entity: {
|
|
102
|
+
methods: {}, // NOTE: Methods must be defined as "function() {}", not as "() => {}" so "this" will be assigned correctly
|
|
103
|
+
},
|
|
99
104
|
|
|
100
105
|
/**
|
|
101
106
|
* @member {object|string} repository - Config for Repository
|
|
@@ -104,7 +109,7 @@ export default class Schema extends EventEmitter {
|
|
|
104
109
|
|
|
105
110
|
};
|
|
106
111
|
|
|
107
|
-
this._originalConfig = _.
|
|
112
|
+
this._originalConfig = _.merge({}, defaults, config);
|
|
108
113
|
_.merge(this, this._originalConfig);
|
|
109
114
|
|
|
110
115
|
/**
|