@nymphjs/nymph 1.0.0-beta.124 → 1.0.0-beta.126

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.
@@ -6,6 +6,7 @@ import { Tokenizer } from '@sciactive/tokenizer';
6
6
 
7
7
  import type Nymph from '../Nymph.js';
8
8
  import type { Selector, Options, FormattedSelector } from '../Nymph.types.js';
9
+ import Entity from '../Entity.js';
9
10
  import type { EntityInstanceType, EntityObjectType } from '../Entity.js';
10
11
  import type {
11
12
  EntityConstructor,
@@ -19,7 +20,13 @@ import {
19
20
  InvalidParametersError,
20
21
  UnableToConnectError,
21
22
  } from '../errors/index.js';
22
- import { xor } from '../utils.js';
23
+ import {
24
+ classNamesToEntityConstructors,
25
+ entitiesToReferences,
26
+ entityConstructorsToClassNames,
27
+ referencesToEntities,
28
+ xor,
29
+ } from '../utils.js';
23
30
 
24
31
  // from: https://stackoverflow.com/a/6969486/664915
25
32
  function escapeRegExp(string: string): string {
@@ -735,8 +742,19 @@ export default abstract class NymphDriver {
735
742
  ) {
736
743
  return true;
737
744
  }
745
+ if (
746
+ value instanceof Entity &&
747
+ value.guid != null &&
748
+ guids.indexOf(value.guid) !== -1
749
+ ) {
750
+ return true;
751
+ }
738
752
  // Search through arrays and objects looking for the reference.
739
- if (value != null && (Array.isArray(value) || typeof value === 'object')) {
753
+ if (
754
+ value != null &&
755
+ (Array.isArray(value) ||
756
+ (typeof value === 'object' && !(value instanceof Entity)))
757
+ ) {
740
758
  for (const key in value) {
741
759
  if (this.entityReferenceSearch(value[key], guids)) {
742
760
  return true;
@@ -1328,7 +1346,20 @@ export default abstract class NymphDriver {
1328
1346
  entity.cdate = cdate;
1329
1347
  entity.mdate = mdate;
1330
1348
  entity.tags = tags;
1331
- entity.$putData(data, sdata, 'server');
1349
+ entity.$putData(
1350
+ classNamesToEntityConstructors(
1351
+ this.nymph,
1352
+ referencesToEntities(
1353
+ data,
1354
+ this.nymph,
1355
+ !!options.skipAc,
1356
+ false,
1357
+ ),
1358
+ false,
1359
+ ),
1360
+ sdata,
1361
+ 'server',
1362
+ );
1332
1363
  return {
1333
1364
  result: Promise.resolve(null),
1334
1365
  process: () => [entity],
@@ -1446,11 +1477,29 @@ export default abstract class NymphDriver {
1446
1477
  cdate,
1447
1478
  mdate,
1448
1479
  tags,
1449
- ...data,
1480
+ ...classNamesToEntityConstructors(
1481
+ this.nymph,
1482
+ referencesToEntities(
1483
+ data,
1484
+ this.nymph,
1485
+ !!options.skipAc,
1486
+ false,
1487
+ ),
1488
+ false,
1489
+ ),
1450
1490
  ...Object.fromEntries(
1451
1491
  Object.entries(sdata).map(([name, value]) => [
1452
1492
  name,
1453
- JSON.parse(value),
1493
+ classNamesToEntityConstructors(
1494
+ this.nymph,
1495
+ referencesToEntities(
1496
+ JSON.parse(value),
1497
+ this.nymph,
1498
+ !!options.skipAc,
1499
+ false,
1500
+ ),
1501
+ false,
1502
+ ),
1454
1503
  ]),
1455
1504
  ),
1456
1505
  } as EntityObjectType<T>);
@@ -1469,7 +1518,20 @@ export default abstract class NymphDriver {
1469
1518
  if (this.putDataCounter == 100) {
1470
1519
  throw new Error('Infinite loop detected in Entity loading.');
1471
1520
  }
1472
- entity.$putData(data, sdata, 'server');
1521
+ entity.$putData(
1522
+ classNamesToEntityConstructors(
1523
+ this.nymph,
1524
+ referencesToEntities(
1525
+ data,
1526
+ this.nymph,
1527
+ !!options.skipAc,
1528
+ false,
1529
+ ),
1530
+ false,
1531
+ ),
1532
+ sdata,
1533
+ 'server',
1534
+ );
1473
1535
  this.putDataCounter--;
1474
1536
  entities.push(entity);
1475
1537
  }
@@ -1537,7 +1599,11 @@ export default abstract class NymphDriver {
1537
1599
  }
1538
1600
  }
1539
1601
  const tags = difference(entity.tags, ['']);
1540
- const data = entity.$getData();
1602
+ const data = entityConstructorsToClassNames(
1603
+ // Explicitly save references to entities that aren't saved yet to help
1604
+ // save circular references by saving with a guaranteed GUID.
1605
+ entitiesToReferences(entity.$getData(), false),
1606
+ );
1541
1607
  const sdata = entity.$getSData();
1542
1608
  const uniques = await entity.$getUniques();
1543
1609
  const EntityClass = entity.constructor as EntityConstructor;
@@ -15,6 +15,10 @@ import {
15
15
  TestModelData,
16
16
  TestEmptyModel as TestEmptyModelClass,
17
17
  } from '../testArtifacts.js';
18
+ import {
19
+ entitiesToReferences,
20
+ entityConstructorsToClassNames,
21
+ } from '../utils.js';
18
22
 
19
23
  const __dirname = dirname(fileURLToPath(import.meta.url));
20
24
 
@@ -2706,7 +2710,9 @@ export function ExportImportTest(
2706
2710
  expect(model).not.toBeNull();
2707
2711
 
2708
2712
  if (model != null) {
2709
- const data = model.$getData(true);
2713
+ const data = entityConstructorsToClassNames(
2714
+ entitiesToReferences(model.$getData(true), true),
2715
+ );
2710
2716
  // These should not actually be saved in the DB.
2711
2717
  data.number = 424242424242;
2712
2718
  // But this should become searchable.
package/src/testMocks.ts CHANGED
@@ -10,6 +10,12 @@ import type {
10
10
  import { Options, Selector } from './Nymph.types.js';
11
11
  import { ClassNotAvailableError, EntityConflictError } from './errors/index.js';
12
12
  import Entity from './Entity.js';
13
+ import {
14
+ classNamesToEntityConstructors,
15
+ entitiesToReferences,
16
+ entityConstructorsToClassNames,
17
+ referencesToEntities,
18
+ } from './utils.js';
13
19
 
14
20
  const entities: { [k: string]: EntityJson } = {};
15
21
 
@@ -62,7 +68,20 @@ export class MockNymphDriver {
62
68
  entity.cdate = entityJson.cdate;
63
69
  entity.mdate = entityJson.mdate;
64
70
  entity.tags = entityJson.tags;
65
- entity.$putData(entityJson.data, {}, 'server');
71
+ entity.$putData(
72
+ classNamesToEntityConstructors(
73
+ this.nymph as unknown as Nymph,
74
+ referencesToEntities(
75
+ entityJson.data,
76
+ this.nymph as unknown as Nymph,
77
+ !!options.skipAc,
78
+ false,
79
+ ),
80
+ false,
81
+ ),
82
+ {},
83
+ 'server',
84
+ );
66
85
 
67
86
  return entity as EntityInstanceType<T>;
68
87
  }
@@ -154,8 +173,6 @@ export class MockNymph {
154
173
  }
155
174
 
156
175
  public async saveEntity(entity: EntityInterface): Promise<boolean> {
157
- const className = (entity.constructor as any).class as string;
158
-
159
176
  if (entity.guid == null) {
160
177
  entity.guid = guid();
161
178
  entity.cdate = Date.now();
@@ -171,12 +188,18 @@ export class MockNymph {
171
188
  entity.mdate = Date.now();
172
189
 
173
190
  const entityJson: EntityJson = {
174
- class: className,
191
+ class: entity.constructor as EntityConstructor,
175
192
  guid: entity.guid,
176
193
  cdate: entity.cdate,
177
194
  mdate: entity.mdate,
178
195
  tags: [...entity.tags],
179
- data: JSON.parse(JSON.stringify(entity.$getData(true))),
196
+ data: JSON.parse(
197
+ JSON.stringify(
198
+ entityConstructorsToClassNames(
199
+ entitiesToReferences(entity.$getData(true), true),
200
+ ),
201
+ ),
202
+ ),
180
203
  };
181
204
 
182
205
  entities[entity.guid] = entityJson;
package/src/utils.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import Entity from './Entity.js';
2
2
  import { EntityReference } from './Entity.types.js';
3
3
  import Nymph from './Nymph.js';
4
- import { Options, Selector } from './Nymph.types.js';
5
4
 
6
5
  export function xor(a: any, b: any): boolean {
7
6
  return !!(a && !b) || (!a && b);
@@ -15,6 +14,29 @@ export function uniqueStrings(array: string[]) {
15
14
  return Object.keys(obj);
16
15
  }
17
16
 
17
+ export function entityConstructorsToClassNames(item: any): any {
18
+ if (item == null || Buffer.isBuffer(item) || ArrayBuffer.isView(item)) {
19
+ return item;
20
+ } else if (typeof item === 'function' && item.prototype instanceof Entity) {
21
+ // Convert entity classes to class references.
22
+ return ['nymph_class_reference', item.class];
23
+ } else if (item instanceof Entity) {
24
+ // Don't touch entities.
25
+ return item;
26
+ } else if (Array.isArray(item)) {
27
+ // Recurse into lower arrays.
28
+ return item.map((entry) => entityConstructorsToClassNames(entry));
29
+ } else if (item instanceof Object) {
30
+ let newObj = Object.create(item);
31
+ for (let [key, value] of Object.entries(item)) {
32
+ newObj[key] = entityConstructorsToClassNames(value);
33
+ }
34
+ return newObj;
35
+ }
36
+ // Not an entity or array, just return it.
37
+ return item;
38
+ }
39
+
18
40
  export function classNamesToEntityConstructors<T extends any>(
19
41
  nymph: Nymph,
20
42
  item: T,
@@ -34,12 +56,12 @@ export function classNamesToEntityConstructors<T extends any>(
34
56
  throw new Error('Not accessible.');
35
57
  }
36
58
  return EntityClass as T;
37
- } else if (
38
- item instanceof Entity &&
39
- typeof item.$toReference === 'function'
40
- ) {
59
+ } else if (item instanceof Entity) {
41
60
  // Don't touch entities.
42
61
  return item;
62
+ } else if (typeof item === 'function' && item.prototype instanceof Entity) {
63
+ // Don't touch Entity classes.
64
+ return item;
43
65
  } else if (Array.isArray(item)) {
44
66
  // Recurse into lower arrays.
45
67
  return item.map((entry) =>
@@ -60,50 +82,13 @@ export function classNamesToEntityConstructors<T extends any>(
60
82
  return item;
61
83
  }
62
84
 
63
- export function entityConstructorsToClassNames(item: any): any {
64
- if (item == null || Buffer.isBuffer(item) || ArrayBuffer.isView(item)) {
65
- return item;
66
- } else if (
67
- typeof item === 'function' &&
68
- item.prototype instanceof Entity &&
69
- typeof item.class === 'string'
70
- ) {
71
- // Convert entity classes to class references.
72
- return ['nymph_class_reference', item.class];
73
- } else if (
74
- item instanceof Entity &&
75
- typeof item.$toReference === 'function'
76
- ) {
77
- // Don't touch entities.
78
- return item;
79
- } else if (Array.isArray(item)) {
80
- // Recurse into lower arrays.
81
- return item.map((entry) => entityConstructorsToClassNames(entry));
82
- } else if (item instanceof Object) {
83
- let newObj = Object.create(item);
84
- for (let [key, value] of Object.entries(item)) {
85
- newObj[key] = entityConstructorsToClassNames(value);
86
- }
87
- return newObj;
88
- }
89
- // Not an entity or array, just return it.
90
- return item;
91
- }
92
-
93
85
  export function entitiesToReferences(item: any, existingOnly?: boolean): any {
94
86
  if (item == null || Buffer.isBuffer(item) || ArrayBuffer.isView(item)) {
95
87
  return item;
96
- } else if (
97
- item instanceof Entity &&
98
- typeof item.$toReference === 'function'
99
- ) {
88
+ } else if (item instanceof Entity) {
100
89
  // Convert entities to references.
101
90
  return item.$toReference(existingOnly);
102
- } else if (
103
- typeof item === 'function' &&
104
- item.prototype instanceof Entity &&
105
- typeof item.class === 'string'
106
- ) {
91
+ } else if (typeof item === 'function' && item.prototype instanceof Entity) {
107
92
  // Don't touch Entity classes.
108
93
  return item;
109
94
  } else if (Array.isArray(item)) {
@@ -145,12 +130,27 @@ export function referencesToEntities(
145
130
  }
146
131
  } else {
147
132
  // Recurse into lower arrays.
148
- return item.map((entry) => referencesToEntities(entry, nymph, useSkipAc));
133
+ return item.map((entry) =>
134
+ referencesToEntities(entry, nymph, useSkipAc, enforceRestEnabledFlag),
135
+ );
149
136
  }
150
- } else if (Entity && item instanceof Object && !(item instanceof Entity)) {
137
+ } else if (item instanceof Entity) {
138
+ // Don't touch entities.
139
+ return item;
140
+ } else if (typeof item === 'function' && item.prototype instanceof Entity) {
141
+ // Don't touch Entity classes.
142
+ return item;
143
+ } else if (item instanceof Object) {
144
+ let newObj = Object.create(item);
151
145
  for (let [key, value] of Object.entries(item)) {
152
- item[key] = referencesToEntities(value, nymph);
146
+ newObj[key] = referencesToEntities(
147
+ value,
148
+ nymph,
149
+ useSkipAc,
150
+ enforceRestEnabledFlag,
151
+ );
153
152
  }
153
+ return newObj;
154
154
  }
155
155
  // Not an array, just return it.
156
156
  return item;