@onehat/data 1.5.1 → 1.6.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.
- package/cypress/integration/Entity.spec.js +22 -25
- 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 +46 -4
- package/package.json +1 -1
- package/src/Entity.js +32 -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 +66 -13
|
@@ -44,7 +44,7 @@ describe('Entity', function() {
|
|
|
44
44
|
expect(this.entity.id).to.be.eq(1);
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
it('
|
|
47
|
+
it('createTempId, isTempId', function() {
|
|
48
48
|
const schema = new Schema({
|
|
49
49
|
name: 'baz',
|
|
50
50
|
model: {
|
|
@@ -62,33 +62,14 @@ describe('Entity', function() {
|
|
|
62
62
|
entity = new Entity(schema, data);
|
|
63
63
|
entity.initialize();
|
|
64
64
|
expect(entity.id).to.be.null;
|
|
65
|
+
expect(entity.isTempId).to.be.false;
|
|
65
66
|
|
|
66
|
-
entity.
|
|
67
|
+
entity.createTempId();
|
|
67
68
|
expect(entity.id).to.be.not.null;
|
|
68
|
-
expect(
|
|
69
|
+
expect(entity.isTempId).to.be.true;
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const schema2 = new Schema({
|
|
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;
|
|
71
|
+
entity.markSaved();
|
|
72
|
+
expect(entity.isTempId).to.be.false;
|
|
92
73
|
});
|
|
93
74
|
|
|
94
75
|
|
|
@@ -407,6 +388,12 @@ describe('Entity', function() {
|
|
|
407
388
|
const entity = new Entity(this.schema, {});
|
|
408
389
|
entity.initialize();
|
|
409
390
|
expect(entity.isPhantom).to.be.true;
|
|
391
|
+
|
|
392
|
+
entity.createTempId();
|
|
393
|
+
expect(entity.isPhantom).to.be.true;
|
|
394
|
+
|
|
395
|
+
entity.markSaved();
|
|
396
|
+
expect(entity.isPhantom).to.be.false;
|
|
410
397
|
});
|
|
411
398
|
|
|
412
399
|
it('isDirty', function() {
|
|
@@ -469,6 +456,15 @@ describe('Entity', function() {
|
|
|
469
456
|
expect(this.entity.isDirty).to.be.true;
|
|
470
457
|
});
|
|
471
458
|
|
|
459
|
+
it('setId', function() {
|
|
460
|
+
expect(this.entity.foo).to.be.eq(1);
|
|
461
|
+
expect(this.entity.isTempId).to.be.false;
|
|
462
|
+
|
|
463
|
+
this.entity.setId(2);
|
|
464
|
+
expect(this.entity.foo).to.be.eq(2);
|
|
465
|
+
expect(this.entity.isTempId).to.be.false;
|
|
466
|
+
});
|
|
467
|
+
|
|
472
468
|
it('_recalculateDependentProperties', function() {
|
|
473
469
|
const schema = new Schema({
|
|
474
470
|
name: 'baz',
|
|
@@ -508,6 +504,7 @@ describe('Entity', function() {
|
|
|
508
504
|
|
|
509
505
|
entity.bar = 'Test';
|
|
510
506
|
entity.markSaved();
|
|
507
|
+
expect(entity.isTempId).to.be.false;
|
|
511
508
|
|
|
512
509
|
expect(entity.isPersisted).to.be.true;
|
|
513
510
|
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() {
|
|
@@ -511,6 +511,12 @@ describe('Repository Base', function() {
|
|
|
511
511
|
expect(didFireAdd).to.be.true;
|
|
512
512
|
});
|
|
513
513
|
|
|
514
|
+
it('createStandaloneEntity', async function() {
|
|
515
|
+
const entity = await this.repository.createStandaloneEntity({ key: 6, value: 'six' });
|
|
516
|
+
expect(entity.id).to.be.eq(6);
|
|
517
|
+
expect(_.size(this.repository.entities)).to.be.eq(5);
|
|
518
|
+
});
|
|
519
|
+
|
|
514
520
|
it('addMultiple', async function() {
|
|
515
521
|
await this.repository.addMultiple([
|
|
516
522
|
{ key: 6, value: 'six' },
|
|
@@ -575,6 +581,23 @@ describe('Repository Base', function() {
|
|
|
575
581
|
expect(result.value).to.be.eq('three');
|
|
576
582
|
});
|
|
577
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
|
+
|
|
578
601
|
it('getByRange', function() {
|
|
579
602
|
const result = this.repository.getByRange(1, 4);
|
|
580
603
|
expect(_.size(result)).to.be.eq(4);
|
|
@@ -616,11 +639,18 @@ describe('Repository Base', function() {
|
|
|
616
639
|
expect(_.isEqual(entity, deleted[0])).to.be.true;
|
|
617
640
|
});
|
|
618
641
|
|
|
619
|
-
it('isInRepository', function() {
|
|
642
|
+
it('isInRepository, hasId', function() {
|
|
620
643
|
this.repository.setAutoSave(false);
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
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);
|
|
624
654
|
expect(result).to.be.true;
|
|
625
655
|
});
|
|
626
656
|
|
|
@@ -655,6 +685,11 @@ describe('Repository Base', function() {
|
|
|
655
685
|
|
|
656
686
|
describe('deleting', function() {
|
|
657
687
|
|
|
688
|
+
it('clear', function() {
|
|
689
|
+
this.repository.clear();
|
|
690
|
+
expect(this.repository.entities.length).to.be.eq(0);
|
|
691
|
+
});
|
|
692
|
+
|
|
658
693
|
it('delete', function() {
|
|
659
694
|
let didFire = false;
|
|
660
695
|
this.repository.on('delete', () => {
|
|
@@ -668,6 +703,13 @@ describe('Repository Base', function() {
|
|
|
668
703
|
expect(didFire).to.be.true;
|
|
669
704
|
});
|
|
670
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
|
+
|
|
671
713
|
|
|
672
714
|
// I'm going to skip these, as they're just combinations of other, tested functions
|
|
673
715
|
// deleteByIx
|
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.
|
|
@@ -158,31 +156,24 @@ class Entity extends EventEmitter {
|
|
|
158
156
|
|
|
159
157
|
/**
|
|
160
158
|
* Generates a new unique id and assigns it to this entity.
|
|
161
|
-
* If the idProperty is of type 'uuid', then it generates a new UUID.
|
|
162
|
-
* If not, then it generates a temp id.
|
|
163
159
|
*/
|
|
164
|
-
|
|
160
|
+
createTempId = () => {
|
|
165
161
|
if (this.isDestroyed) {
|
|
166
|
-
throw Error('this.
|
|
162
|
+
throw Error('this.createTempId is no longer valid. Entity has been destroyed.');
|
|
167
163
|
}
|
|
168
164
|
if (!_.isNil(this.id)) {
|
|
169
165
|
throw new Error('Entity id already exists.');
|
|
170
166
|
}
|
|
171
|
-
const idProperty = this.getIdProperty(),
|
|
172
|
-
id = (idProperty.type === 'uuid') ? idProperty.newId() : _.uniqueId(TEMP_PREFIX);
|
|
173
|
-
this.setId(id);
|
|
174
|
-
}
|
|
175
167
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
*/
|
|
181
|
-
static isTempId(id) {
|
|
182
|
-
if (_.isString(id) && id.match(new RegExp('^' + TEMP_PREFIX))) {
|
|
183
|
-
return true;
|
|
168
|
+
const idProperty = this.getIdProperty();
|
|
169
|
+
|
|
170
|
+
if (!idProperty.newId) {
|
|
171
|
+
throw new Error('idProperty.newId() does not exist');
|
|
184
172
|
}
|
|
185
|
-
|
|
173
|
+
|
|
174
|
+
this.setId(idProperty.newId());
|
|
175
|
+
|
|
176
|
+
idProperty.isTempId = true;
|
|
186
177
|
}
|
|
187
178
|
|
|
188
179
|
/**
|
|
@@ -739,6 +730,14 @@ class Entity extends EventEmitter {
|
|
|
739
730
|
return this.getId();
|
|
740
731
|
}
|
|
741
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Is this Entity's idProperty using a temporary ID?
|
|
735
|
+
* @return {boolean} isTempId
|
|
736
|
+
*/
|
|
737
|
+
get isTempId() {
|
|
738
|
+
return this.getIdProperty().isTempId;
|
|
739
|
+
}
|
|
740
|
+
|
|
742
741
|
/**
|
|
743
742
|
* Gets the "Display" Property object for this Entity.
|
|
744
743
|
* This is the Property whose value can easily identify the whole Entity itself.
|
|
@@ -793,13 +792,13 @@ class Entity extends EventEmitter {
|
|
|
793
792
|
const idProperty = this.getIdProperty(),
|
|
794
793
|
id = idProperty.getSubmitValue();
|
|
795
794
|
|
|
796
|
-
// No
|
|
795
|
+
// No ID
|
|
797
796
|
if (_.isNil(id)) {
|
|
798
797
|
return true;
|
|
799
798
|
}
|
|
800
799
|
|
|
801
|
-
//
|
|
802
|
-
if (
|
|
800
|
+
// ID is temporary
|
|
801
|
+
if (idProperty.isTempId) {
|
|
803
802
|
return true;
|
|
804
803
|
}
|
|
805
804
|
|
|
@@ -851,23 +850,25 @@ class Entity extends EventEmitter {
|
|
|
851
850
|
*/
|
|
852
851
|
setId = (id, force = false) => {
|
|
853
852
|
let isChanged = false;
|
|
854
|
-
const
|
|
853
|
+
const idProperty = this.getIdProperty();
|
|
855
854
|
|
|
856
|
-
|
|
857
|
-
if (
|
|
855
|
+
idProperty.pauseEvents(); // We don't need property_change to fire
|
|
856
|
+
if (idProperty.setValue(id)) {
|
|
858
857
|
isChanged = true;
|
|
859
858
|
}
|
|
860
|
-
|
|
859
|
+
idProperty.resumeEvents();
|
|
861
860
|
|
|
862
861
|
if (isChanged || force) {
|
|
863
862
|
// Set this id on the _originalData* objects
|
|
864
|
-
if (
|
|
865
|
-
_.merge(this._originalData, Entity.getReverseMappedRawValue(
|
|
863
|
+
if (idProperty.hasMapping) {
|
|
864
|
+
_.merge(this._originalData, Entity.getReverseMappedRawValue(idProperty));
|
|
866
865
|
} else {
|
|
867
|
-
this._originalData[
|
|
866
|
+
this._originalData[idProperty.name] = idProperty.getRawValue();
|
|
868
867
|
}
|
|
869
|
-
this._originalDataParsed[
|
|
868
|
+
this._originalDataParsed[idProperty.name] = idProperty.getParsedValue();
|
|
870
869
|
}
|
|
870
|
+
|
|
871
|
+
idProperty.isTempId = false;
|
|
871
872
|
|
|
872
873
|
return isChanged;
|
|
873
874
|
}
|
|
@@ -973,6 +974,7 @@ class Entity extends EventEmitter {
|
|
|
973
974
|
throw Error('this.markSaved is no longer valid. Entity has been destroyed.');
|
|
974
975
|
}
|
|
975
976
|
this.isPersisted = true;
|
|
977
|
+
this.getIdProperty().isTempId = false;
|
|
976
978
|
this._originalData = this._getReconstructedOriginalData();
|
|
977
979
|
this._originalDataParsed = this.getParsedValues();
|
|
978
980
|
}
|
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);
|
|
@@ -878,6 +878,27 @@ export default class Repository extends EventEmitter {
|
|
|
878
878
|
return entity;
|
|
879
879
|
}
|
|
880
880
|
|
|
881
|
+
/**
|
|
882
|
+
* Creates a new static Entity that does NOT persist in storage medium.
|
|
883
|
+
* @param {object} data - Either raw data object or Entity. If raw data, keys are Property names, Values are Property values.
|
|
884
|
+
* @param {boolean} isPersisted - Whether the new entity should be marked as already being persisted in storage medium.
|
|
885
|
+
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
886
|
+
* @return {object} entity - new Entity object
|
|
887
|
+
*/
|
|
888
|
+
createStandaloneEntity = async (data, isPersisted = false, originalIsMapped = false) => {
|
|
889
|
+
if (this.isDestroyed) {
|
|
890
|
+
throw Error('this.createStandaloneEntity is no longer valid. Repository has been destroyed.');
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const entity = Repository._createEntity(this.schema, data, this, isPersisted, originalIsMapped);
|
|
894
|
+
|
|
895
|
+
if (entity.isPhantom) {
|
|
896
|
+
entity.createTempId();
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
return entity;
|
|
900
|
+
}
|
|
901
|
+
|
|
881
902
|
/**
|
|
882
903
|
* Convenience function to add entity with mapped data.
|
|
883
904
|
*/
|
|
@@ -951,6 +972,15 @@ export default class Repository extends EventEmitter {
|
|
|
951
972
|
this.entities = [];
|
|
952
973
|
}
|
|
953
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
|
+
|
|
954
984
|
/**
|
|
955
985
|
* Gets an array of "submit" values objects for the entities
|
|
956
986
|
* @return {array} map -
|
|
@@ -1043,20 +1073,19 @@ export default class Repository extends EventEmitter {
|
|
|
1043
1073
|
/**
|
|
1044
1074
|
* Get a single Entity by its id
|
|
1045
1075
|
* @param {integer} id - id of record to retrieve
|
|
1046
|
-
* @return {Entity} The Entity with matching id
|
|
1076
|
+
* @return {Entity} The Entity with matching id, or undefined
|
|
1047
1077
|
*/
|
|
1048
1078
|
getById = (id) => {
|
|
1049
1079
|
if (this.isDestroyed) {
|
|
1050
1080
|
throw Error('this.getById is no longer valid. Repository has been destroyed.');
|
|
1051
1081
|
}
|
|
1052
|
-
|
|
1053
|
-
return result.length > 0 ? result[0] : null;
|
|
1082
|
+
return this.getFirstBy(entity => entity.id === id);
|
|
1054
1083
|
}
|
|
1055
1084
|
|
|
1056
1085
|
/**
|
|
1057
1086
|
* Get an array of Entities by supplied filter function
|
|
1058
1087
|
* @param {function} filter - Filter function to apply to all entities
|
|
1059
|
-
* @return {Entity[]} Entities that passed through filter
|
|
1088
|
+
* @return {Entity[]} Entities that passed through filter, or []
|
|
1060
1089
|
*/
|
|
1061
1090
|
getBy = (filter) => {
|
|
1062
1091
|
if (this.isDestroyed) {
|
|
@@ -1072,7 +1101,7 @@ export default class Repository extends EventEmitter {
|
|
|
1072
1101
|
* filters into account. Defaults to false.
|
|
1073
1102
|
*
|
|
1074
1103
|
* @param {function} filter - Filter function to search by
|
|
1075
|
-
* @return {Entity} First Entity found
|
|
1104
|
+
* @return {Entity} First Entity found, or undefined
|
|
1076
1105
|
*/
|
|
1077
1106
|
getFirstBy = (filter) => {
|
|
1078
1107
|
if (this.isDestroyed) {
|
|
@@ -1083,7 +1112,7 @@ export default class Repository extends EventEmitter {
|
|
|
1083
1112
|
|
|
1084
1113
|
/**
|
|
1085
1114
|
* Get all phantom (unsaved) Entities
|
|
1086
|
-
* @return {Entity[]} Array of phantom Entities
|
|
1115
|
+
* @return {Entity[]} Array of phantom Entities, or []
|
|
1087
1116
|
*/
|
|
1088
1117
|
getPhantom = () => {
|
|
1089
1118
|
if (this.isDestroyed) {
|
|
@@ -1094,7 +1123,7 @@ export default class Repository extends EventEmitter {
|
|
|
1094
1123
|
|
|
1095
1124
|
/**
|
|
1096
1125
|
* Get all Entities not yet persisted to a storage medium
|
|
1097
|
-
* @return {Entity[]} Array of dirty Entities
|
|
1126
|
+
* @return {Entity[]} Array of dirty Entities, or []
|
|
1098
1127
|
*/
|
|
1099
1128
|
getNonPersisted = () => {
|
|
1100
1129
|
if (this.isDestroyed) {
|
|
@@ -1107,7 +1136,7 @@ export default class Repository extends EventEmitter {
|
|
|
1107
1136
|
|
|
1108
1137
|
/**
|
|
1109
1138
|
* Get all dirty (having unsaved changes) Entities
|
|
1110
|
-
* @return {Entity[]} Array of dirty Entities
|
|
1139
|
+
* @return {Entity[]} Array of dirty Entities, or []
|
|
1111
1140
|
*/
|
|
1112
1141
|
getDirty = () => {
|
|
1113
1142
|
if (this.isDestroyed) {
|
|
@@ -1120,7 +1149,7 @@ export default class Repository extends EventEmitter {
|
|
|
1120
1149
|
|
|
1121
1150
|
/**
|
|
1122
1151
|
* Get all deleted Entities
|
|
1123
|
-
* @return {Entity[]} Array of deleted Entities
|
|
1152
|
+
* @return {Entity[]} Array of deleted Entities, or []
|
|
1124
1153
|
*/
|
|
1125
1154
|
getDeleted = () => {
|
|
1126
1155
|
if (this.isDestroyed) {
|
|
@@ -1147,6 +1176,15 @@ export default class Repository extends EventEmitter {
|
|
|
1147
1176
|
return !_.isNil(this.getById(idOrEntity));
|
|
1148
1177
|
}
|
|
1149
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
|
+
|
|
1150
1188
|
/**
|
|
1151
1189
|
* Queues up batch operations for saving
|
|
1152
1190
|
* new, edited, and deleted entities to storage medium.
|
|
@@ -1336,7 +1374,7 @@ export default class Repository extends EventEmitter {
|
|
|
1336
1374
|
|
|
1337
1375
|
/**
|
|
1338
1376
|
* Marks entities for deletion from storage medium.
|
|
1339
|
-
* Actual deletion takes place in save()
|
|
1377
|
+
* Actual deletion takes place in save(), unless isPhantom
|
|
1340
1378
|
* @param {object|array} entities - one or more entities to delete
|
|
1341
1379
|
* @fires delete
|
|
1342
1380
|
*/
|
|
@@ -1352,7 +1390,12 @@ export default class Repository extends EventEmitter {
|
|
|
1352
1390
|
return;
|
|
1353
1391
|
}
|
|
1354
1392
|
_.each(entities, (entity) => {
|
|
1355
|
-
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
|
+
}
|
|
1356
1399
|
});
|
|
1357
1400
|
|
|
1358
1401
|
this.emit('delete', entities);
|
|
@@ -1362,6 +1405,16 @@ export default class Repository extends EventEmitter {
|
|
|
1362
1405
|
}
|
|
1363
1406
|
}
|
|
1364
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
|
+
|
|
1365
1418
|
/**
|
|
1366
1419
|
* Deletes a single Entity by its index (zero-indexed) on the current page
|
|
1367
1420
|
* @param {integer} ix - Index
|