@onehat/data 1.4.14 → 1.6.0

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.
@@ -44,7 +44,7 @@ describe('Entity', function() {
44
44
  expect(this.entity.id).to.be.eq(1);
45
45
  });
46
46
 
47
- it('createId, isTempId', function() {
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.createId();
67
+ entity.createTempId();
67
68
  expect(entity.id).to.be.not.null;
68
- expect(Entity.isTempId(entity.id)).to.be.true;
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
 
@@ -198,6 +179,17 @@ describe('Entity', function() {
198
179
  expect(_.isEqual(this.entity.submitValues, expected)).to.be.true;
199
180
  });
200
181
 
182
+ it('getSubmitValuesMapped & submitValuesMapped', function() {
183
+ const result = this.entity.getSubmitValuesMapped(),
184
+ expected = {
185
+ foo: 1,
186
+ bar: 'one',
187
+ 'baz.test.val': true,
188
+ };
189
+ expect(_.isEqual(result, expected)).to.be.true;
190
+ expect(_.isEqual(this.entity.submitValuesMapped, expected)).to.be.true;
191
+ });
192
+
201
193
  it('getDisplayValues & displayValues', function() {
202
194
  const result = this.entity.getDisplayValues(),
203
195
  expected = {
@@ -258,20 +250,74 @@ describe('Entity', function() {
258
250
  });
259
251
 
260
252
  it('getReverseMappedRawValue', function() {
261
- const definition = {
262
- name: 'foo',
263
- mapping: 'a.b.c',
264
- type: 'int',
265
- },
266
- Property = PropertyTypes[definition.type];
267
- const property = new Property(definition, 'fakeEntity');
253
+ const definition1 = {
254
+ name: 'foo',
255
+ mapping: 'a.b.c',
256
+ type: 'int',
257
+ },
258
+ Property1 = PropertyTypes[definition1.type];
259
+ const property1 = new Property1(definition1, 'fakeEntity');
260
+
261
+ property1.setValue('47');
262
+
263
+ const reverseMapped1 = Entity.getReverseMappedRawValue(property1),
264
+ expected1 = { a: { b: { c: '47' }, }, };
265
+
266
+ expect(_.isEqual(reverseMapped1, expected1)).to.be.true;
267
+
268
+
269
+ // Now, with no mapping
270
+ const definition2 = {
271
+ name: 'foo',
272
+ type: 'int',
273
+ },
274
+ Property2 = PropertyTypes[definition2.type];
275
+ const property2 = new Property2(definition2, 'fakeEntity');
268
276
 
269
- property.setValue('47');
277
+ property2.setValue('47');
270
278
 
271
- const reverseMapped = Entity.getReverseMappedRawValue(property),
272
- expected = { a: { b: { c: '47' }, }, };
279
+ const reverseMapped2 = Entity.getReverseMappedRawValue(property2),
280
+ expected2 = { foo: '47' };
273
281
 
274
- expect(_.isEqual(reverseMapped, expected)).to.be.true;
282
+ expect(_.isEqual(reverseMapped2, expected2)).to.be.true;
283
+ });
284
+
285
+ it('getReverseMappedRawValues (check deep matches)', function() {
286
+ const schema = new Schema({
287
+ name: 'baz',
288
+ model: {
289
+ idProperty: 'foo',
290
+ displayProperty: 'bar',
291
+ properties: [
292
+ { name: 'foo', type: 'int' },
293
+ { name: 'bar' },
294
+ { name: 'baz', mapping: 'baz.test.val', type: 'bool', defaultValue: null, },
295
+ { name: 'baz2', mapping: 'baz.test2', type: 'bool', defaultValue: null, },
296
+ ],
297
+ },
298
+ }),
299
+ data = {
300
+ foo: 1,
301
+ bar: 'one',
302
+ baz: {
303
+ test: {
304
+ val: true,
305
+ },
306
+ test2: false,
307
+ },
308
+ },
309
+ entity = new Entity(schema, data);
310
+ entity.initialize();
311
+
312
+ const result = entity.getReverseMappedRawValues();
313
+ expect(_.isEqual(result, data)).to.be.true;
314
+ });
315
+
316
+ it('build a new entity from an existing one using getDataForNewEntity', function() {
317
+ const entity = new Entity(this.schema, this.entity.getDataForNewEntity());
318
+ entity.initialize();
319
+
320
+ expect(_.isEqual(entity.submitValues, this.entity.submitValues)).to.be.true;
275
321
  });
276
322
 
277
323
  it('getChanged', function() {
@@ -342,6 +388,12 @@ describe('Entity', function() {
342
388
  const entity = new Entity(this.schema, {});
343
389
  entity.initialize();
344
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;
345
397
  });
346
398
 
347
399
  it('isDirty', function() {
@@ -404,6 +456,15 @@ describe('Entity', function() {
404
456
  expect(this.entity.isDirty).to.be.true;
405
457
  });
406
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
+
407
468
  it('_recalculateDependentProperties', function() {
408
469
  const schema = new Schema({
409
470
  name: 'baz',
@@ -443,6 +504,7 @@ describe('Entity', function() {
443
504
 
444
505
  entity.bar = 'Test';
445
506
  entity.markSaved();
507
+ expect(entity.isTempId).to.be.false;
446
508
 
447
509
  expect(entity.isPersisted).to.be.true;
448
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();
@@ -108,6 +108,24 @@ describe('Property', function() {
108
108
  const property = entity.getProperty('bar');
109
109
  expect(property.isDisplayProperty).to.be.true;
110
110
  });
111
+
112
+ it('getMapping', function() {
113
+ expect(this.property.getMapping()).to.be.eq('id');
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
+ });
111
129
 
112
130
  });
113
131
 
@@ -10,9 +10,21 @@ describe('StringProperty', function() {
10
10
  this.property = new Property(definition);
11
11
  });
12
12
 
13
- it('className', function() {
14
- const className = this.property.getClassName();
15
- expect(className).to.be.eq('String');
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' },
@@ -616,11 +622,18 @@ describe('Repository Base', function() {
616
622
  expect(_.isEqual(entity, deleted[0])).to.be.true;
617
623
  });
618
624
 
619
- it('isInRepository', function() {
625
+ it('isInRepository, hasId', function() {
620
626
  this.repository.setAutoSave(false);
621
- const entity = this.repository.getByIx(0),
622
- result = this.repository.isInRepository(entity);
623
-
627
+ const id = 1,
628
+ entity = this.repository.getById(id);
629
+
630
+ let result = this.repository.isInRepository(entity);
631
+ expect(result).to.be.true;
632
+
633
+ result = this.repository.isInRepository(id);
634
+ expect(result).to.be.true;
635
+
636
+ result = this.repository.hasId(id);
624
637
  expect(result).to.be.true;
625
638
  });
626
639
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.4.14",
3
+ "version": "1.6.0",
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
@@ -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
- createId = () => {
160
+ createTempId = () => {
165
161
  if (this.isDestroyed) {
166
- throw Error('this.generateTempId is no longer valid. Entity has been destroyed.');
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
- * Determines whether submitted id is a "temp" id.
178
- * @param {any} id
179
- * @return {boolean} isTempId
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
- return false;
173
+
174
+ this.setId(idProperty.newId());
175
+
176
+ idProperty.isTempId = true;
186
177
  }
187
178
 
188
179
  /**
@@ -457,6 +448,36 @@ class Entity extends EventEmitter {
457
448
  return this.getSubmitValues();
458
449
  }
459
450
 
451
+ /**
452
+ * Gets an object of properties/values for this Entity,
453
+ * and returns them with the mapped names
454
+ * Values are the "submit" values, not the "raw" or "parsed" or "display" values.
455
+ * @return {object} propertyValues
456
+ */
457
+ getSubmitValuesMapped = () => {
458
+ if (this.isDestroyed) {
459
+ throw Error('this.getSubmitValuesMapped is no longer valid. Entity has been destroyed.');
460
+ }
461
+
462
+ let propertyValues = {};
463
+ _.forOwn(this.properties, (property) => {
464
+ const name = property.hasMapping ? property.getMapping() : property.name;
465
+ propertyValues[name] = property.getSubmitValue();
466
+ });
467
+ return propertyValues;
468
+ }
469
+
470
+ /**
471
+ * Gets "submit" values for this Entity, and returns them with the mapped names
472
+ * @return {object} values
473
+ */
474
+ get submitValuesMapped() {
475
+ if (this.isDestroyed) {
476
+ throw Error('this.submitValuesMapped is no longer valid. Entity has been destroyed.');
477
+ }
478
+ return this.getSubmitValuesMapped();
479
+ }
480
+
460
481
  /**
461
482
  * Gets an object of values for this Entity,
462
483
  * Values are the "display" values, not the "raw" or "parsed" or "submit" values.
@@ -569,6 +590,11 @@ class Entity extends EventEmitter {
569
590
  * @static
570
591
  */
571
592
  static getReverseMappedRawValue(property) {
593
+ if (!property.hasMapping) {
594
+ const obj = {};
595
+ obj[property.name] = property.rawValue;
596
+ return obj;
597
+ }
572
598
  const mapStack = property.mapping.split('.'),
573
599
  rawValue = property.getRawValue();
574
600
 
@@ -591,6 +617,37 @@ class Entity extends EventEmitter {
591
617
  return value;
592
618
  }
593
619
 
620
+ /**
621
+ * Builds up an object of original values for this entity, from which another entity could be easily created
622
+ * @return {object} value - An object representing the 'path' to the raw value.
623
+ * e.g. With a mapping of 'a.b.c' and a property rawValue of '47', the
624
+ * following object will be returned:{ a: { b: { c: '47' }, }, }
625
+ */
626
+ getReverseMappedRawValues = () => {
627
+ if (this.isDestroyed) {
628
+ throw Error('this.getReverseMappedRawValues is no longer valid. Entity has been destroyed.');
629
+ }
630
+
631
+ let propertyValues = {};
632
+ _.forOwn(this.properties, (property) => {
633
+ const reverseMapped = Entity.getReverseMappedRawValue(property);
634
+ _.merge(propertyValues, reverseMapped);
635
+ });
636
+ return propertyValues;
637
+ }
638
+
639
+ /**
640
+ * Convenience function
641
+ * Build a new entity with this data
642
+ */
643
+ getDataForNewEntity = () => {
644
+ if (this.isDestroyed) {
645
+ throw Error('this.getDataForNewEntity is no longer valid. Entity has been destroyed.');
646
+ }
647
+
648
+ return this.getReverseMappedRawValues();
649
+ }
650
+
594
651
  /**
595
652
  * Gets the values that have changed since last time saved
596
653
  * @return {array|boolean} diff - Array of property names that have changed, or false
@@ -673,6 +730,14 @@ class Entity extends EventEmitter {
673
730
  return this.getId();
674
731
  }
675
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
+
676
741
  /**
677
742
  * Gets the "Display" Property object for this Entity.
678
743
  * This is the Property whose value can easily identify the whole Entity itself.
@@ -727,13 +792,13 @@ class Entity extends EventEmitter {
727
792
  const idProperty = this.getIdProperty(),
728
793
  id = idProperty.getSubmitValue();
729
794
 
730
- // No id
795
+ // No ID
731
796
  if (_.isNil(id)) {
732
797
  return true;
733
798
  }
734
799
 
735
- // Temp id
736
- if (Entity.isTempId(id)) {
800
+ // ID is temporary
801
+ if (idProperty.isTempId) {
737
802
  return true;
738
803
  }
739
804
 
@@ -785,23 +850,25 @@ class Entity extends EventEmitter {
785
850
  */
786
851
  setId = (id, force = false) => {
787
852
  let isChanged = false;
788
- const property = this.getIdProperty();
853
+ const idProperty = this.getIdProperty();
789
854
 
790
- property.pauseEvents(); // We don't need property_change to fire
791
- if (property.setValue(id)) {
855
+ idProperty.pauseEvents(); // We don't need property_change to fire
856
+ if (idProperty.setValue(id)) {
792
857
  isChanged = true;
793
858
  }
794
- property.resumeEvents();
859
+ idProperty.resumeEvents();
795
860
 
796
861
  if (isChanged || force) {
797
862
  // Set this id on the _originalData* objects
798
- if (property.hasMapping) {
799
- _.merge(this._originalData, Entity.getReverseMappedRawValue(property));
863
+ if (idProperty.hasMapping) {
864
+ _.merge(this._originalData, Entity.getReverseMappedRawValue(idProperty));
800
865
  } else {
801
- this._originalData[property.name] = property.getRawValue();
866
+ this._originalData[idProperty.name] = idProperty.getRawValue();
802
867
  }
803
- this._originalDataParsed[property.name] = property.getParsedValue();
868
+ this._originalDataParsed[idProperty.name] = idProperty.getParsedValue();
804
869
  }
870
+
871
+ idProperty.isTempId = false;
805
872
 
806
873
  return isChanged;
807
874
  }
@@ -907,6 +974,7 @@ class Entity extends EventEmitter {
907
974
  throw Error('this.markSaved is no longer valid. Entity has been destroyed.');
908
975
  }
909
976
  this.isPersisted = true;
977
+ this.getIdProperty().isTempId = false;
910
978
  this._originalData = this._getReconstructedOriginalData();
911
979
  this._originalDataParsed = this.getParsedValues();
912
980
  }
@@ -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
 
@@ -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
@@ -405,6 +411,17 @@ export default class Property extends EventEmitter {
405
411
  return this.__proto__.constructor.className;
406
412
  }
407
413
 
414
+ /**
415
+ * Gets the mapped name of this Property.
416
+ * @return {string} name
417
+ */
418
+ getMapping = () => {
419
+ if (this.isDestroyed) {
420
+ throw Error('this.getMapping is no longer valid. Property has been destroyed.');
421
+ }
422
+ return this.mapping;
423
+ }
424
+
408
425
  /**
409
426
  * Destroy this object.
410
427
  * - Removes all circular references to parent objects
@@ -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';
@@ -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;
@@ -134,7 +134,7 @@ class MemoryRepository extends Repository {
134
134
  // Add to internal store
135
135
  _.each(entities, (entity) => {
136
136
  if (entity.isPhantom) {
137
- entity.createId();
137
+ entity.createTempId();
138
138
  }
139
139
  this._keyedEntities[entity.id] = entity;
140
140
  });
@@ -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.createId(); // either a UUID or a temp id
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
  */
@@ -1147,6 +1168,15 @@ export default class Repository extends EventEmitter {
1147
1168
  return !_.isNil(this.getById(idOrEntity));
1148
1169
  }
1149
1170
 
1171
+ /**
1172
+ * Convenience function
1173
+ * Alias for isInRepository
1174
+ * NOTE: It only searches in memory. Doesn't query server
1175
+ */
1176
+ hasId = (id) => {
1177
+ return this.isInRepository(id);
1178
+ }
1179
+
1150
1180
  /**
1151
1181
  * Queues up batch operations for saving
1152
1182
  * new, edited, and deleted entities to storage medium.