@onehat/data 1.5.2 → 1.6.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.
- package/cypress/fixtures/Definitions/GroupsUsers.js +8 -0
- package/cypress/integration/Entity.spec.js +34 -26
- package/cypress/integration/Property/Integer.spec.js +8 -0
- package/cypress/integration/Property/Property.spec.js +14 -0
- package/cypress/integration/Property/String.spec.js +15 -3
- package/cypress/integration/Repository/Repository.spec.js +40 -4
- package/cypress/integration/Schema.spec.js +1 -0
- package/package.json +1 -1
- package/src/Entity.js +50 -30
- package/src/Property/Integer.js +29 -0
- package/src/Property/Property.js +6 -0
- package/src/Property/String.js +19 -0
- package/src/Repository/Ajax.js +1 -10
- package/src/Repository/Memory.js +1 -1
- package/src/Repository/Repository.js +46 -14
- package/src/Schema/Schema.js +6 -1
|
@@ -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,
|
|
@@ -44,7 +51,7 @@ describe('Entity', function() {
|
|
|
44
51
|
expect(this.entity.id).to.be.eq(1);
|
|
45
52
|
});
|
|
46
53
|
|
|
47
|
-
it('
|
|
54
|
+
it('createTempId, isTempId', function() {
|
|
48
55
|
const schema = new Schema({
|
|
49
56
|
name: 'baz',
|
|
50
57
|
model: {
|
|
@@ -62,35 +69,15 @@ describe('Entity', function() {
|
|
|
62
69
|
entity = new Entity(schema, data);
|
|
63
70
|
entity.initialize();
|
|
64
71
|
expect(entity.id).to.be.null;
|
|
72
|
+
expect(entity.isTempId).to.be.false;
|
|
65
73
|
|
|
66
|
-
entity.
|
|
74
|
+
entity.createTempId();
|
|
67
75
|
expect(entity.id).to.be.not.null;
|
|
68
|
-
expect(
|
|
69
|
-
|
|
76
|
+
expect(entity.isTempId).to.be.true;
|
|
70
77
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
name: 'baz',
|
|
74
|
-
model: {
|
|
75
|
-
idProperty: 'foo',
|
|
76
|
-
displayProperty: 'bar',
|
|
77
|
-
properties: [
|
|
78
|
-
{ name: 'foo', type: 'uuid' }, // MOD
|
|
79
|
-
{ name: 'bar' },
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
}),
|
|
83
|
-
entity2 = new Entity(schema2, data);
|
|
84
|
-
|
|
85
|
-
entity2.initialize();
|
|
86
|
-
expect(entity2.id).to.be.null;
|
|
87
|
-
|
|
88
|
-
entity2.createId();
|
|
89
|
-
expect(entity2.id).to.be.not.null;
|
|
90
|
-
const idProperty = entity2.getIdProperty();
|
|
91
|
-
expect(Entity.isTempId(entity2.id)).to.be.false;
|
|
78
|
+
entity.markSaved();
|
|
79
|
+
expect(entity.isTempId).to.be.false;
|
|
92
80
|
});
|
|
93
|
-
|
|
94
81
|
|
|
95
82
|
it('clone', function() {
|
|
96
83
|
const entity = this.entity;
|
|
@@ -119,6 +106,11 @@ describe('Entity', function() {
|
|
|
119
106
|
expect(entity.properties.bar.name).to.be.eq('bar');
|
|
120
107
|
expect(entity.properties.baz.name).to.be.eq('baz');
|
|
121
108
|
});
|
|
109
|
+
|
|
110
|
+
it('_createMethods', function() {
|
|
111
|
+
this.entity.testMethod();
|
|
112
|
+
expect(this.entity.bar).to.be.eq('test me');
|
|
113
|
+
});
|
|
122
114
|
|
|
123
115
|
it('loadOriginalData', function() {
|
|
124
116
|
const data = {
|
|
@@ -407,6 +399,12 @@ describe('Entity', function() {
|
|
|
407
399
|
const entity = new Entity(this.schema, {});
|
|
408
400
|
entity.initialize();
|
|
409
401
|
expect(entity.isPhantom).to.be.true;
|
|
402
|
+
|
|
403
|
+
entity.createTempId();
|
|
404
|
+
expect(entity.isPhantom).to.be.true;
|
|
405
|
+
|
|
406
|
+
entity.markSaved();
|
|
407
|
+
expect(entity.isPhantom).to.be.false;
|
|
410
408
|
});
|
|
411
409
|
|
|
412
410
|
it('isDirty', function() {
|
|
@@ -469,6 +467,15 @@ describe('Entity', function() {
|
|
|
469
467
|
expect(this.entity.isDirty).to.be.true;
|
|
470
468
|
});
|
|
471
469
|
|
|
470
|
+
it('setId', function() {
|
|
471
|
+
expect(this.entity.foo).to.be.eq(1);
|
|
472
|
+
expect(this.entity.isTempId).to.be.false;
|
|
473
|
+
|
|
474
|
+
this.entity.setId(2);
|
|
475
|
+
expect(this.entity.foo).to.be.eq(2);
|
|
476
|
+
expect(this.entity.isTempId).to.be.false;
|
|
477
|
+
});
|
|
478
|
+
|
|
472
479
|
it('_recalculateDependentProperties', function() {
|
|
473
480
|
const schema = new Schema({
|
|
474
481
|
name: 'baz',
|
|
@@ -508,6 +515,7 @@ describe('Entity', function() {
|
|
|
508
515
|
|
|
509
516
|
entity.bar = 'Test';
|
|
510
517
|
entity.markSaved();
|
|
518
|
+
expect(entity.isTempId).to.be.false;
|
|
511
519
|
|
|
512
520
|
expect(entity.isPersisted).to.be.true;
|
|
513
521
|
const expected = {
|
|
@@ -19,6 +19,14 @@ describe('IntegerProperty', function() {
|
|
|
19
19
|
expect(className).to.be.eq('Integer');
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
it('newId', function() {
|
|
23
|
+
const id1 = this.property.newId();
|
|
24
|
+
expect(id1.valueOf()).to.be.eq(this.property.idStartsAt);
|
|
25
|
+
|
|
26
|
+
const id2 = this.property.newId();
|
|
27
|
+
expect(id2.valueOf()).to.be.eq(this.property.idStartsAt +1);
|
|
28
|
+
});
|
|
29
|
+
|
|
22
30
|
// it('default value', function() {
|
|
23
31
|
// const property = this.property,
|
|
24
32
|
// rawValue = property.getDefaultValue();
|
|
@@ -112,6 +112,20 @@ describe('Property', function() {
|
|
|
112
112
|
it('getMapping', function() {
|
|
113
113
|
expect(this.property.getMapping()).to.be.eq('id');
|
|
114
114
|
});
|
|
115
|
+
|
|
116
|
+
it('getMapping', function() {
|
|
117
|
+
expect(this.property.getMapping()).to.be.eq('id');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('isTempId', function() {
|
|
121
|
+
const definition = {
|
|
122
|
+
type: 'int',
|
|
123
|
+
isTempId: true,
|
|
124
|
+
},
|
|
125
|
+
Property = PropertyTypes[definition.type];
|
|
126
|
+
const property = new Property(definition);
|
|
127
|
+
expect(property.isTempId).to.be.true;
|
|
128
|
+
});
|
|
115
129
|
|
|
116
130
|
});
|
|
117
131
|
|
|
@@ -10,9 +10,21 @@ describe('StringProperty', function() {
|
|
|
10
10
|
this.property = new Property(definition);
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
describe('general', function() {
|
|
14
|
+
|
|
15
|
+
it('className', function() {
|
|
16
|
+
const className = this.property.getClassName();
|
|
17
|
+
expect(className).to.be.eq('String');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('newId', function() {
|
|
21
|
+
const id1 = this.property.newId();
|
|
22
|
+
expect(id1.valueOf()).to.be.eq('TEMP-1');
|
|
23
|
+
|
|
24
|
+
const id2 = this.property.newId();
|
|
25
|
+
expect(id2.valueOf()).to.be.eq('TEMP-2');
|
|
26
|
+
});
|
|
27
|
+
|
|
16
28
|
});
|
|
17
29
|
|
|
18
30
|
describe('parse', function() {
|
|
@@ -581,6 +581,23 @@ describe('Repository Base', function() {
|
|
|
581
581
|
expect(result.value).to.be.eq('three');
|
|
582
582
|
});
|
|
583
583
|
|
|
584
|
+
it('getById', function() {
|
|
585
|
+
const result = this.repository.getById(3);
|
|
586
|
+
expect(result.value).to.be.eq('three');
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it('getBy', function() {
|
|
590
|
+
const result = this.repository.getBy(entity => entity.id === 2 || entity.id === 3);
|
|
591
|
+
expect(result.length).to.be.eq(2);
|
|
592
|
+
expect(result[0].value).to.be.eq('two');
|
|
593
|
+
expect(result[1].value).to.be.eq('three');
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it('getFirstBy', function() {
|
|
597
|
+
const result = this.repository.getFirstBy(entity => entity.id === 3);
|
|
598
|
+
expect(result.value).to.be.eq('three');
|
|
599
|
+
});
|
|
600
|
+
|
|
584
601
|
it('getByRange', function() {
|
|
585
602
|
const result = this.repository.getByRange(1, 4);
|
|
586
603
|
expect(_.size(result)).to.be.eq(4);
|
|
@@ -622,11 +639,18 @@ describe('Repository Base', function() {
|
|
|
622
639
|
expect(_.isEqual(entity, deleted[0])).to.be.true;
|
|
623
640
|
});
|
|
624
641
|
|
|
625
|
-
it('isInRepository', function() {
|
|
642
|
+
it('isInRepository, hasId', function() {
|
|
626
643
|
this.repository.setAutoSave(false);
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
|
|
644
|
+
const id = 1,
|
|
645
|
+
entity = this.repository.getById(id);
|
|
646
|
+
|
|
647
|
+
let result = this.repository.isInRepository(entity);
|
|
648
|
+
expect(result).to.be.true;
|
|
649
|
+
|
|
650
|
+
result = this.repository.isInRepository(id);
|
|
651
|
+
expect(result).to.be.true;
|
|
652
|
+
|
|
653
|
+
result = this.repository.hasId(id);
|
|
630
654
|
expect(result).to.be.true;
|
|
631
655
|
});
|
|
632
656
|
|
|
@@ -661,6 +685,11 @@ describe('Repository Base', function() {
|
|
|
661
685
|
|
|
662
686
|
describe('deleting', function() {
|
|
663
687
|
|
|
688
|
+
it('clear', function() {
|
|
689
|
+
this.repository.clear();
|
|
690
|
+
expect(this.repository.entities.length).to.be.eq(0);
|
|
691
|
+
});
|
|
692
|
+
|
|
664
693
|
it('delete', function() {
|
|
665
694
|
let didFire = false;
|
|
666
695
|
this.repository.on('delete', () => {
|
|
@@ -674,6 +703,13 @@ describe('Repository Base', function() {
|
|
|
674
703
|
expect(didFire).to.be.true;
|
|
675
704
|
});
|
|
676
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
|
+
|
|
677
713
|
|
|
678
714
|
// I'm going to skip these, as they're just combinations of other, tested functions
|
|
679
715
|
// deleteByIx
|
|
@@ -11,6 +11,7 @@ describe('Schema', function() {
|
|
|
11
11
|
expect(this.schema instanceof Schema).to.be.true;
|
|
12
12
|
expect(this.schema.name).to.be.eq('GroupsUsers');
|
|
13
13
|
expect(this.schema.repository.type).to.be.eq('onebuild');
|
|
14
|
+
expect(this.schema.entity.methods.testMethod).to.be.a('function');
|
|
14
15
|
});
|
|
15
16
|
|
|
16
17
|
it('clone', function() {
|
package/package.json
CHANGED
package/src/Entity.js
CHANGED
|
@@ -4,8 +4,6 @@ import EventEmitter from '@onehat/events';
|
|
|
4
4
|
import PropertyTypes from './Property';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
|
|
7
|
-
const TEMP_PREFIX = 'TEMP-';
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* Class represents a single Entity (i.e. a record)
|
|
11
9
|
* which is a collection of Properties with current values.
|
|
@@ -152,37 +150,48 @@ class Entity extends EventEmitter {
|
|
|
152
150
|
|
|
153
151
|
initialize = () => {
|
|
154
152
|
this.properties = this._createProperties();
|
|
153
|
+
this._createMethods();
|
|
155
154
|
this.reset();
|
|
156
155
|
this.isInitialized = true;
|
|
157
156
|
}
|
|
158
157
|
|
|
159
158
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* If not, then it generates a temp id.
|
|
159
|
+
* Creates the methods for this Entity, based on Schema.
|
|
160
|
+
* @private
|
|
163
161
|
*/
|
|
164
|
-
|
|
162
|
+
_createMethods = () => {
|
|
165
163
|
if (this.isDestroyed) {
|
|
166
|
-
throw Error('this.
|
|
164
|
+
throw Error('this._createMethods is no longer valid. Entity has been destroyed.');
|
|
167
165
|
}
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
const methodDefinitions = this.schema.entity.methods;
|
|
167
|
+
if (_.isEmpty(methodDefinitions)) {
|
|
168
|
+
return;
|
|
170
169
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
+
});
|
|
174
173
|
}
|
|
175
174
|
|
|
176
175
|
/**
|
|
177
|
-
*
|
|
178
|
-
* @param {any} id
|
|
179
|
-
* @return {boolean} isTempId
|
|
176
|
+
* Generates a new unique id and assigns it to this entity.
|
|
180
177
|
*/
|
|
181
|
-
|
|
182
|
-
if (
|
|
183
|
-
|
|
178
|
+
createTempId = () => {
|
|
179
|
+
if (this.isDestroyed) {
|
|
180
|
+
throw Error('this.createTempId is no longer valid. Entity has been destroyed.');
|
|
184
181
|
}
|
|
185
|
-
|
|
182
|
+
if (!_.isNil(this.id)) {
|
|
183
|
+
throw new Error('Entity id already exists.');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const idProperty = this.getIdProperty();
|
|
187
|
+
|
|
188
|
+
if (!idProperty.newId) {
|
|
189
|
+
throw new Error('idProperty.newId() does not exist');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.setId(idProperty.newId());
|
|
193
|
+
|
|
194
|
+
idProperty.isTempId = true;
|
|
186
195
|
}
|
|
187
196
|
|
|
188
197
|
/**
|
|
@@ -739,6 +748,14 @@ class Entity extends EventEmitter {
|
|
|
739
748
|
return this.getId();
|
|
740
749
|
}
|
|
741
750
|
|
|
751
|
+
/**
|
|
752
|
+
* Is this Entity's idProperty using a temporary ID?
|
|
753
|
+
* @return {boolean} isTempId
|
|
754
|
+
*/
|
|
755
|
+
get isTempId() {
|
|
756
|
+
return this.getIdProperty().isTempId;
|
|
757
|
+
}
|
|
758
|
+
|
|
742
759
|
/**
|
|
743
760
|
* Gets the "Display" Property object for this Entity.
|
|
744
761
|
* This is the Property whose value can easily identify the whole Entity itself.
|
|
@@ -793,13 +810,13 @@ class Entity extends EventEmitter {
|
|
|
793
810
|
const idProperty = this.getIdProperty(),
|
|
794
811
|
id = idProperty.getSubmitValue();
|
|
795
812
|
|
|
796
|
-
// No
|
|
813
|
+
// No ID
|
|
797
814
|
if (_.isNil(id)) {
|
|
798
815
|
return true;
|
|
799
816
|
}
|
|
800
817
|
|
|
801
|
-
//
|
|
802
|
-
if (
|
|
818
|
+
// ID is temporary
|
|
819
|
+
if (idProperty.isTempId) {
|
|
803
820
|
return true;
|
|
804
821
|
}
|
|
805
822
|
|
|
@@ -851,23 +868,25 @@ class Entity extends EventEmitter {
|
|
|
851
868
|
*/
|
|
852
869
|
setId = (id, force = false) => {
|
|
853
870
|
let isChanged = false;
|
|
854
|
-
const
|
|
871
|
+
const idProperty = this.getIdProperty();
|
|
855
872
|
|
|
856
|
-
|
|
857
|
-
if (
|
|
873
|
+
idProperty.pauseEvents(); // We don't need property_change to fire
|
|
874
|
+
if (idProperty.setValue(id)) {
|
|
858
875
|
isChanged = true;
|
|
859
876
|
}
|
|
860
|
-
|
|
877
|
+
idProperty.resumeEvents();
|
|
861
878
|
|
|
862
879
|
if (isChanged || force) {
|
|
863
880
|
// Set this id on the _originalData* objects
|
|
864
|
-
if (
|
|
865
|
-
_.merge(this._originalData, Entity.getReverseMappedRawValue(
|
|
881
|
+
if (idProperty.hasMapping) {
|
|
882
|
+
_.merge(this._originalData, Entity.getReverseMappedRawValue(idProperty));
|
|
866
883
|
} else {
|
|
867
|
-
this._originalData[
|
|
884
|
+
this._originalData[idProperty.name] = idProperty.getRawValue();
|
|
868
885
|
}
|
|
869
|
-
this._originalDataParsed[
|
|
886
|
+
this._originalDataParsed[idProperty.name] = idProperty.getParsedValue();
|
|
870
887
|
}
|
|
888
|
+
|
|
889
|
+
idProperty.isTempId = false;
|
|
871
890
|
|
|
872
891
|
return isChanged;
|
|
873
892
|
}
|
|
@@ -973,6 +992,7 @@ class Entity extends EventEmitter {
|
|
|
973
992
|
throw Error('this.markSaved is no longer valid. Entity has been destroyed.');
|
|
974
993
|
}
|
|
975
994
|
this.isPersisted = true;
|
|
995
|
+
this.getIdProperty().isTempId = false;
|
|
976
996
|
this._originalData = this._getReconstructedOriginalData();
|
|
977
997
|
this._originalDataParsed = this.getParsedValues();
|
|
978
998
|
}
|
package/src/Property/Integer.js
CHANGED
|
@@ -4,6 +4,8 @@ import Property from './Property';
|
|
|
4
4
|
import Parsers from '../Util/Parsers';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
|
|
7
|
+
let lastId = 0;
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Class represents a Property that stores an integer value.
|
|
9
11
|
* @extends Property
|
|
@@ -15,6 +17,7 @@ export default class IntegerProperty extends Property {
|
|
|
15
17
|
|
|
16
18
|
const defaults = {
|
|
17
19
|
// defaultValue: 0,
|
|
20
|
+
idStartsAt: 100 * 1000 * 1000 * 1000, // 100 billion
|
|
18
21
|
};
|
|
19
22
|
|
|
20
23
|
_.merge(this, defaults, config);
|
|
@@ -29,6 +32,32 @@ export default class IntegerProperty extends Property {
|
|
|
29
32
|
}
|
|
30
33
|
return Parsers.ParseInt(value);
|
|
31
34
|
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Generates a new id
|
|
38
|
+
* Mainly for temporary, in-memory usage
|
|
39
|
+
*/
|
|
40
|
+
newId = () => {
|
|
41
|
+
let id,
|
|
42
|
+
hasId = false;
|
|
43
|
+
|
|
44
|
+
const entity = this.getEntity(),
|
|
45
|
+
repository = entity && entity.repository;
|
|
46
|
+
|
|
47
|
+
if (lastId < this.idStartsAt) {
|
|
48
|
+
lastId = this.idStartsAt;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
id = lastId++;
|
|
52
|
+
hasId = repository ? repository.hasId(id) : false;
|
|
53
|
+
|
|
54
|
+
while(hasId) {
|
|
55
|
+
id = lastId++;
|
|
56
|
+
hasId = repository.hasId(id);
|
|
57
|
+
}
|
|
58
|
+
return id;
|
|
59
|
+
}
|
|
60
|
+
|
|
32
61
|
|
|
33
62
|
};
|
|
34
63
|
|
package/src/Property/Property.js
CHANGED
|
@@ -83,6 +83,12 @@ export default class Property extends EventEmitter {
|
|
|
83
83
|
* @member {boolean} isSortable - Whether this property type is sortable
|
|
84
84
|
*/
|
|
85
85
|
isSortable: true,
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @member {boolean} isTempId - Whether this property's ID is temporary
|
|
89
|
+
*/
|
|
90
|
+
isTempId: false,
|
|
91
|
+
|
|
86
92
|
|
|
87
93
|
|
|
88
94
|
// OneBuild META attributes, just bring these over wholesale for now
|
package/src/Property/String.js
CHANGED
|
@@ -4,6 +4,8 @@ import Property from './Property';
|
|
|
4
4
|
import Parsers from '../Util/Parsers';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
|
|
7
|
+
const TEMP_PREFIX = 'TEMP-';
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* Class represents a Property that stores string data.
|
|
9
11
|
* @extends Property
|
|
@@ -29,6 +31,23 @@ export default class StringProperty extends Property {
|
|
|
29
31
|
}
|
|
30
32
|
return Parsers.ParseString(value);
|
|
31
33
|
}
|
|
34
|
+
|
|
35
|
+
newId = () => {
|
|
36
|
+
let id,
|
|
37
|
+
hasId = false;
|
|
38
|
+
|
|
39
|
+
const entity = this.getEntity(),
|
|
40
|
+
repository = entity && entity.repository;
|
|
41
|
+
|
|
42
|
+
id = _.uniqueId(TEMP_PREFIX);
|
|
43
|
+
hasId = repository ? repository.hasId(id) : false;
|
|
44
|
+
|
|
45
|
+
while(hasId) {
|
|
46
|
+
id = _.uniqueId(TEMP_PREFIX);
|
|
47
|
+
hasId = repository.hasId(id);
|
|
48
|
+
}
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
32
51
|
};
|
|
33
52
|
|
|
34
53
|
StringProperty.className = 'String';
|
package/src/Repository/Ajax.js
CHANGED
|
@@ -395,7 +395,7 @@ class AjaxRepository extends Repository {
|
|
|
395
395
|
});
|
|
396
396
|
|
|
397
397
|
// Set the total records that pass filter
|
|
398
|
-
this.total = total;
|
|
398
|
+
this.total = total;
|
|
399
399
|
this._setPaginationVars();
|
|
400
400
|
|
|
401
401
|
this.isLoading = false;
|
|
@@ -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';
|
package/src/Repository/Memory.js
CHANGED
|
@@ -865,8 +865,8 @@ export default class Repository extends EventEmitter {
|
|
|
865
865
|
this.entities.push(entity);
|
|
866
866
|
|
|
867
867
|
// Create id if needed
|
|
868
|
-
if (entity.isPhantom) {
|
|
869
|
-
entity.
|
|
868
|
+
if (entity.isPhantom) { // i.e. idProperty has no value
|
|
869
|
+
entity.createTempId();
|
|
870
870
|
}
|
|
871
871
|
|
|
872
872
|
this.emit('add', entity);
|
|
@@ -893,7 +893,7 @@ export default class Repository extends EventEmitter {
|
|
|
893
893
|
const entity = Repository._createEntity(this.schema, data, this, isPersisted, originalIsMapped);
|
|
894
894
|
|
|
895
895
|
if (entity.isPhantom) {
|
|
896
|
-
entity.
|
|
896
|
+
entity.createTempId();
|
|
897
897
|
}
|
|
898
898
|
|
|
899
899
|
return entity;
|
|
@@ -972,6 +972,15 @@ export default class Repository extends EventEmitter {
|
|
|
972
972
|
this.entities = [];
|
|
973
973
|
}
|
|
974
974
|
|
|
975
|
+
/**
|
|
976
|
+
* Deletes all locally cached entities in repository,
|
|
977
|
+
* usually, the current "page".
|
|
978
|
+
* Does not actually affect anything on the server.
|
|
979
|
+
*/
|
|
980
|
+
clear = async () => {
|
|
981
|
+
this._destroyEntities();
|
|
982
|
+
}
|
|
983
|
+
|
|
975
984
|
/**
|
|
976
985
|
* Gets an array of "submit" values objects for the entities
|
|
977
986
|
* @return {array} map -
|
|
@@ -1064,20 +1073,19 @@ export default class Repository extends EventEmitter {
|
|
|
1064
1073
|
/**
|
|
1065
1074
|
* Get a single Entity by its id
|
|
1066
1075
|
* @param {integer} id - id of record to retrieve
|
|
1067
|
-
* @return {Entity} The Entity with matching id
|
|
1076
|
+
* @return {Entity} The Entity with matching id, or undefined
|
|
1068
1077
|
*/
|
|
1069
1078
|
getById = (id) => {
|
|
1070
1079
|
if (this.isDestroyed) {
|
|
1071
1080
|
throw Error('this.getById is no longer valid. Repository has been destroyed.');
|
|
1072
1081
|
}
|
|
1073
|
-
|
|
1074
|
-
return result.length > 0 ? result[0] : null;
|
|
1082
|
+
return this.getFirstBy(entity => entity.id === id);
|
|
1075
1083
|
}
|
|
1076
1084
|
|
|
1077
1085
|
/**
|
|
1078
1086
|
* Get an array of Entities by supplied filter function
|
|
1079
1087
|
* @param {function} filter - Filter function to apply to all entities
|
|
1080
|
-
* @return {Entity[]} Entities that passed through filter
|
|
1088
|
+
* @return {Entity[]} Entities that passed through filter, or []
|
|
1081
1089
|
*/
|
|
1082
1090
|
getBy = (filter) => {
|
|
1083
1091
|
if (this.isDestroyed) {
|
|
@@ -1093,7 +1101,7 @@ export default class Repository extends EventEmitter {
|
|
|
1093
1101
|
* filters into account. Defaults to false.
|
|
1094
1102
|
*
|
|
1095
1103
|
* @param {function} filter - Filter function to search by
|
|
1096
|
-
* @return {Entity} First Entity found
|
|
1104
|
+
* @return {Entity} First Entity found, or undefined
|
|
1097
1105
|
*/
|
|
1098
1106
|
getFirstBy = (filter) => {
|
|
1099
1107
|
if (this.isDestroyed) {
|
|
@@ -1104,7 +1112,7 @@ export default class Repository extends EventEmitter {
|
|
|
1104
1112
|
|
|
1105
1113
|
/**
|
|
1106
1114
|
* Get all phantom (unsaved) Entities
|
|
1107
|
-
* @return {Entity[]} Array of phantom Entities
|
|
1115
|
+
* @return {Entity[]} Array of phantom Entities, or []
|
|
1108
1116
|
*/
|
|
1109
1117
|
getPhantom = () => {
|
|
1110
1118
|
if (this.isDestroyed) {
|
|
@@ -1115,7 +1123,7 @@ export default class Repository extends EventEmitter {
|
|
|
1115
1123
|
|
|
1116
1124
|
/**
|
|
1117
1125
|
* Get all Entities not yet persisted to a storage medium
|
|
1118
|
-
* @return {Entity[]} Array of dirty Entities
|
|
1126
|
+
* @return {Entity[]} Array of dirty Entities, or []
|
|
1119
1127
|
*/
|
|
1120
1128
|
getNonPersisted = () => {
|
|
1121
1129
|
if (this.isDestroyed) {
|
|
@@ -1128,7 +1136,7 @@ export default class Repository extends EventEmitter {
|
|
|
1128
1136
|
|
|
1129
1137
|
/**
|
|
1130
1138
|
* Get all dirty (having unsaved changes) Entities
|
|
1131
|
-
* @return {Entity[]} Array of dirty Entities
|
|
1139
|
+
* @return {Entity[]} Array of dirty Entities, or []
|
|
1132
1140
|
*/
|
|
1133
1141
|
getDirty = () => {
|
|
1134
1142
|
if (this.isDestroyed) {
|
|
@@ -1141,7 +1149,7 @@ export default class Repository extends EventEmitter {
|
|
|
1141
1149
|
|
|
1142
1150
|
/**
|
|
1143
1151
|
* Get all deleted Entities
|
|
1144
|
-
* @return {Entity[]} Array of deleted Entities
|
|
1152
|
+
* @return {Entity[]} Array of deleted Entities, or []
|
|
1145
1153
|
*/
|
|
1146
1154
|
getDeleted = () => {
|
|
1147
1155
|
if (this.isDestroyed) {
|
|
@@ -1168,6 +1176,15 @@ export default class Repository extends EventEmitter {
|
|
|
1168
1176
|
return !_.isNil(this.getById(idOrEntity));
|
|
1169
1177
|
}
|
|
1170
1178
|
|
|
1179
|
+
/**
|
|
1180
|
+
* Convenience function
|
|
1181
|
+
* Alias for isInRepository
|
|
1182
|
+
* NOTE: It only searches in memory. Doesn't query server
|
|
1183
|
+
*/
|
|
1184
|
+
hasId = (id) => {
|
|
1185
|
+
return this.isInRepository(id);
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1171
1188
|
/**
|
|
1172
1189
|
* Queues up batch operations for saving
|
|
1173
1190
|
* new, edited, and deleted entities to storage medium.
|
|
@@ -1357,7 +1374,7 @@ export default class Repository extends EventEmitter {
|
|
|
1357
1374
|
|
|
1358
1375
|
/**
|
|
1359
1376
|
* Marks entities for deletion from storage medium.
|
|
1360
|
-
* Actual deletion takes place in save()
|
|
1377
|
+
* Actual deletion takes place in save(), unless isPhantom
|
|
1361
1378
|
* @param {object|array} entities - one or more entities to delete
|
|
1362
1379
|
* @fires delete
|
|
1363
1380
|
*/
|
|
@@ -1373,7 +1390,12 @@ export default class Repository extends EventEmitter {
|
|
|
1373
1390
|
return;
|
|
1374
1391
|
}
|
|
1375
1392
|
_.each(entities, (entity) => {
|
|
1376
|
-
entity.
|
|
1393
|
+
if (entity.isPhantom) {
|
|
1394
|
+
// Just auto-remove it. Don't bother saving to storage medium.
|
|
1395
|
+
this.removeEntity(entity);
|
|
1396
|
+
} else {
|
|
1397
|
+
entity.markDeleted(); // Entity is still there, it's just marked for deletion
|
|
1398
|
+
}
|
|
1377
1399
|
});
|
|
1378
1400
|
|
|
1379
1401
|
this.emit('delete', entities);
|
|
@@ -1383,6 +1405,16 @@ export default class Repository extends EventEmitter {
|
|
|
1383
1405
|
}
|
|
1384
1406
|
}
|
|
1385
1407
|
|
|
1408
|
+
/**
|
|
1409
|
+
* Removes an Entity from the current page
|
|
1410
|
+
* Mainly used for phantom Entities
|
|
1411
|
+
* Helper for delete()
|
|
1412
|
+
*/
|
|
1413
|
+
removeEntity = async (entity) => {
|
|
1414
|
+
this.entities = _.filter(this.entities, e => e !== entity);
|
|
1415
|
+
entity.destroy();
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1386
1418
|
/**
|
|
1387
1419
|
* Deletes a single Entity by its index (zero-indexed) on the current page
|
|
1388
1420
|
* @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
|