@nymphjs/nymph 1.0.0-beta.61 → 1.0.0-beta.63

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.
@@ -68,6 +68,7 @@ export default abstract class NymphDriver {
68
68
  abstract connect(): Promise<boolean>;
69
69
 
70
70
  abstract isConnected(): boolean;
71
+ protected abstract internalTransaction(name: string): Promise<any>;
71
72
  abstract startTransaction(name: string): Promise<Nymph>;
72
73
  abstract commit(name: string): Promise<boolean>;
73
74
  abstract rollback(name: string): Promise<boolean>;
@@ -84,9 +85,11 @@ export default abstract class NymphDriver {
84
85
  */
85
86
  abstract disconnect(): Promise<boolean>;
86
87
 
87
- protected abstract exportEntities(
88
- writeLine: (line: string) => void,
89
- ): Promise<void>;
88
+ abstract exportDataIterator(): AsyncGenerator<
89
+ { type: 'comment' | 'uid' | 'entity'; content: string },
90
+ void,
91
+ undefined | false
92
+ >;
90
93
  abstract getEntities<T extends EntityConstructor = EntityConstructor>(
91
94
  options: Options<T> & { return: 'count' },
92
95
  ...selectors: Selector[]
@@ -104,7 +107,15 @@ export default abstract class NymphDriver {
104
107
  ...selectors: Selector[]
105
108
  ): Promise<EntityInstanceType<T>[] | string[] | number>;
106
109
  abstract getUID(name: string): Promise<number | null>;
107
- abstract import(filename: string, transaction?: boolean): Promise<boolean>;
110
+ abstract importEntity(entity: {
111
+ guid: string;
112
+ cdate: number;
113
+ mdate: number;
114
+ tags: string[];
115
+ sdata: SerializedEntityData;
116
+ etype: string;
117
+ }): Promise<void>;
118
+ abstract importUID(uid: { name: string; value: number }): Promise<void>;
108
119
  abstract newUID(name: string): Promise<number | null>;
109
120
  abstract renameUID(oldName: string, newName: string): Promise<boolean>;
110
121
  abstract saveEntity(entity: EntityInterface): Promise<boolean>;
@@ -181,9 +192,9 @@ export default abstract class NymphDriver {
181
192
  if (!fhandle) {
182
193
  throw new InvalidParametersError('Provided filename is not writeable.');
183
194
  }
184
- await this.exportEntities((line: string) => {
185
- fs.writeSync(fhandle, `${line}\n`);
186
- });
195
+ for await (let entry of this.exportDataIterator()) {
196
+ fs.writeSync(fhandle, entry.content);
197
+ }
187
198
  fs.closeSync(fhandle);
188
199
  } catch (e: any) {
189
200
  return false;
@@ -192,83 +203,113 @@ export default abstract class NymphDriver {
192
203
  }
193
204
 
194
205
  public async exportPrint() {
195
- await this.exportEntities((line: string) => {
196
- console.log(line);
197
- });
206
+ for await (let entry of this.exportDataIterator()) {
207
+ console.log(entry.content);
208
+ }
198
209
  return true;
199
210
  }
200
211
 
201
- protected async importFromFile(
202
- filename: string,
203
- saveEntityCallback: (
204
- guid: string,
205
- tags: string[],
206
- sdata: SerializedEntityData,
207
- etype: string,
208
- ) => Promise<void>,
209
- saveUIDCallback: (name: string, value: number) => Promise<void>,
210
- startTransactionCallback: (() => Promise<void>) | null = null,
211
- commitTransactionCallback: (() => Promise<void>) | null = null,
212
+ public async importDataIterator(
213
+ lines: Iterable<string>,
214
+ transaction?: boolean,
212
215
  ) {
213
- let rl: ReadLines;
214
- try {
215
- rl = new ReadLines(filename);
216
- } catch (e: any) {
217
- throw new InvalidParametersError('Provided filename is unreadable.');
216
+ const first = lines[Symbol.iterator]().next();
217
+
218
+ if (first.done || first.value !== '#nex2') {
219
+ throw new Error('Tried to import a file that is not a NEX v2 file.');
218
220
  }
219
- let guid: string | null = null;
220
- let line: Buffer | false = false;
221
- let sdata: SerializedEntityData = {};
222
- let tags: string[] = [];
223
- let etype = '__undefined';
224
- if (startTransactionCallback) {
225
- await startTransactionCallback();
221
+
222
+ if (transaction) {
223
+ await this.internalTransaction('nymph-import');
226
224
  }
227
- while ((line = rl.next())) {
228
- const text = line.toString('utf8');
229
- if (text.match(/^\s*#/)) {
230
- continue;
231
- }
232
- const entityMatch = text.match(
233
- /^\s*{([0-9A-Fa-f]+)}<([-\w_]+)>\[([^\]]*)\]\s*$/,
234
- );
235
- const propMatch = text.match(/^\s*([^=]+)\s*=\s*(.*\S)\s*$/);
236
- const uidMatch = text.match(/^\s*<([^>]+)>\[(\d+)\]\s*$/);
237
- if (uidMatch) {
238
- // Add the UID.
239
- await saveUIDCallback(uidMatch[1], Number(uidMatch[2]));
240
- } else if (entityMatch) {
241
- // Save the current entity.
242
- if (guid) {
243
- await saveEntityCallback(guid, tags, sdata, etype);
244
- guid = null;
245
- tags = [];
246
- sdata = {};
247
- etype = '__undefined';
225
+ try {
226
+ let guid: string | null = null;
227
+ let sdata: SerializedEntityData = {};
228
+ let tags: string[] = [];
229
+ let etype = '__undefined';
230
+ for (let line of lines) {
231
+ if (line.match(/^\s*#/)) {
232
+ continue;
248
233
  }
249
- // Record the new entity's info.
250
- guid = entityMatch[1];
251
- etype = entityMatch[2];
252
- tags = entityMatch[3].split(',');
253
- } else if (propMatch) {
254
- // Add the variable to the new entity.
255
- if (guid) {
256
- sdata[propMatch[1]] = propMatch[2];
234
+ const entityMatch = line.match(
235
+ /^\s*{([0-9A-Fa-f]+)}<([-\w_]+)>\[([^\]]*)\]\s*$/,
236
+ );
237
+ const propMatch = line.match(/^\s*([^=]+)\s*=\s*(.*\S)\s*$/);
238
+ const uidMatch = line.match(/^\s*<([^>]+)>\[(\d+)\]\s*$/);
239
+ if (uidMatch) {
240
+ // Add the UID.
241
+ await this.importUID({
242
+ name: uidMatch[1],
243
+ value: Number(uidMatch[2]),
244
+ });
245
+ } else if (entityMatch) {
246
+ // Save the current entity.
247
+ if (guid) {
248
+ const cdate = Number(JSON.parse(sdata.cdate));
249
+ delete sdata.cdate;
250
+ const mdate = Number(JSON.parse(sdata.mdate));
251
+ delete sdata.mdate;
252
+ await this.importEntity({ guid, cdate, mdate, tags, sdata, etype });
253
+ guid = null;
254
+ tags = [];
255
+ sdata = {};
256
+ etype = '__undefined';
257
+ }
258
+ // Record the new entity's info.
259
+ guid = entityMatch[1];
260
+ etype = entityMatch[2];
261
+ tags = entityMatch[3].split(',');
262
+ } else if (propMatch) {
263
+ // Add the variable to the new entity.
264
+ if (guid) {
265
+ sdata[propMatch[1]] = propMatch[2];
266
+ }
257
267
  }
268
+ // Clear the entity cache.
269
+ this.entityCache = {};
258
270
  }
259
- // Clear the entity cache.
260
- this.entityCache = {};
261
- }
262
- // Save the last entity.
263
- if (guid) {
264
- await saveEntityCallback(guid, tags, sdata, etype);
265
- }
266
- if (commitTransactionCallback) {
267
- await commitTransactionCallback();
271
+ // Save the last entity.
272
+ if (guid) {
273
+ const cdate = Number(JSON.parse(sdata.cdate));
274
+ delete sdata.cdate;
275
+ const mdate = Number(JSON.parse(sdata.mdate));
276
+ delete sdata.mdate;
277
+ await this.importEntity({ guid, cdate, mdate, tags, sdata, etype });
278
+ }
279
+ if (transaction) {
280
+ await this.commit('nymph-import');
281
+ }
282
+ } catch (e: any) {
283
+ await this.rollback('nymph-import');
284
+ throw e;
268
285
  }
269
286
  return true;
270
287
  }
271
288
 
289
+ public async importData(text: string, transaction?: boolean) {
290
+ return await this.importDataIterator(text.split('/n'), transaction);
291
+ }
292
+
293
+ public async import(filename: string, transaction?: boolean) {
294
+ let rl: ReadLines;
295
+ try {
296
+ rl = new ReadLines(filename);
297
+ } catch (e: any) {
298
+ throw new InvalidParametersError('Provided filename is unreadable.');
299
+ }
300
+
301
+ const lines = {
302
+ *[Symbol.iterator]() {
303
+ let line: false | Buffer;
304
+ while ((line = rl.next())) {
305
+ yield line.toString('utf8');
306
+ }
307
+ },
308
+ };
309
+
310
+ return await this.importDataIterator(lines, transaction);
311
+ }
312
+
272
313
  public checkData(
273
314
  data: EntityData,
274
315
  sdata: SerializedEntityData,
@@ -94,14 +94,23 @@ These hats are absolutely fantastic.`;
94
94
  }
95
95
 
96
96
  it('delete old test data', async () => {
97
- let all = await nymph.getEntities({ class: TestModel });
98
- expect(Array.isArray(all)).toEqual(true);
99
- for (const cur of all) {
97
+ let amodels = await nymph.getEntities({ class: TestModel });
98
+ expect(Array.isArray(amodels)).toEqual(true);
99
+ for (const cur of amodels) {
100
100
  expect(await cur.$delete()).toEqual(true);
101
101
  }
102
102
 
103
- all = await nymph.getEntities({ class: TestModel });
104
- expect(all.length).toEqual(0);
103
+ amodels = await nymph.getEntities({ class: TestModel });
104
+ expect(amodels.length).toEqual(0);
105
+
106
+ let bmodels = await nymph.getEntities({ class: TestBModel });
107
+ expect(Array.isArray(bmodels)).toEqual(true);
108
+ for (const cur of bmodels) {
109
+ expect(await cur.$delete()).toEqual(true);
110
+ }
111
+
112
+ bmodels = await nymph.getEntities({ class: TestBModel });
113
+ expect(bmodels.length).toEqual(0);
105
114
  });
106
115
 
107
116
  it('create entity', async () => {
@@ -1986,25 +1995,39 @@ export function ExportImportTest(
1986
1995
  const bmodels = await nymph.getEntities({ class: TestBModel });
1987
1996
 
1988
1997
  expect(models.length).toEqual(30);
1989
- expect(bmodels.length).toEqual(10);
1990
-
1991
- const all = [...models, ...bmodels];
1992
- for (const model of all) {
1993
- if (model.index?.match(/^\d+a$/)) {
1994
- expect(model.null).toBeNull();
1995
- expect(model.string).toEqual('test');
1996
- expect(model.array).toEqual(['full', 'of', 'values', 500]);
1997
- expect(model.number).toEqual(30);
1998
- expect(model.timestamp).toBeGreaterThanOrEqual(strtotime('-2 minutes'));
1999
-
2000
- await model.reference?.$wake();
2001
- expect(model.reference?.guid).not.toBeNull();
2002
- expect(model.reference?.string).toEqual('another');
2003
- expect(model.reference?.index?.match(/^\d+b$/)).toBeTruthy();
2004
- await Promise.all(model.refArray?.map((e) => e.$wake()) || []);
2005
- expect(model.refArray?.[0].guid).not.toBeNull();
2006
- expect(model.refArray?.[0].guid).toEqual(model.reference?.guid);
2007
- }
1998
+ expect(bmodels.length).toEqual(30);
1999
+
2000
+ for (const model of models) {
2001
+ expect(model.name).toMatch(/^Entity Test /);
2002
+ expect(model.null).toBeDefined();
2003
+ expect(model.null).toBeNull();
2004
+ expect(model.string).toEqual('test');
2005
+ expect(model.array).toEqual(['full', 'of', 'values', 500]);
2006
+ expect(model.match)
2007
+ .toEqual(`Hello, my name is Edward McCheese. It is a pleasure to meet you. As you can see, I have several hats of the most pleasant nature.
2008
+
2009
+ This one's email address is nice_hat-wednesday+newyork@im-a-hat.hat.
2010
+ This one's phone number is (555) 555-1818.
2011
+ This one's zip code is 92064.
2012
+ This one's favorite emojis are 🔥❤️😊😂⭐🤔
2013
+
2014
+ These hats are absolutely fantastic.`);
2015
+ expect(model.number).toEqual(30);
2016
+ expect(model.numberString).toEqual('30');
2017
+ expect(model.timestamp).toBeGreaterThanOrEqual(strtotime('-2 minutes'));
2018
+ expect(model.index).toMatch(/^\d+a$/);
2019
+
2020
+ await model.reference?.$wake();
2021
+ expect(model.reference?.guid).not.toBeNull();
2022
+ expect(model.reference?.string).toEqual('another');
2023
+ expect(model.reference?.index).toMatch(/^\d+b$/);
2024
+ expect(model.index?.substring(0, -1)).toEqual(
2025
+ model.reference?.index?.substring(0, -1),
2026
+ );
2027
+ expect(model.reference?.$inArray(bmodels)).toEqual(true);
2028
+ await Promise.all(model.refArray?.map((e) => e.$wake()) || []);
2029
+ expect(model.refArray?.[0].guid).not.toBeNull();
2030
+ expect(model.refArray?.[0].guid).toEqual(model.reference?.guid);
2008
2031
  }
2009
2032
  }
2010
2033
 
@@ -2017,22 +2040,29 @@ export function ExportImportTest(
2017
2040
  expect(await nymph.newUID('TestUID')).toEqual(2);
2018
2041
  expect(await nymph.newUID('TestUID2')).toEqual(1);
2019
2042
 
2020
- for (let i = 0; i < 20; i++) {
2021
- const EntityClass = i < 15 ? TestModel : TestBModel;
2022
-
2043
+ for (let i = 0; i < 30; i++) {
2023
2044
  // Creating entity...
2024
- const testEntity = await EntityClass.factory();
2045
+ const testEntity = await TestModel.factory();
2025
2046
 
2026
2047
  // Saving entity...
2027
2048
  testEntity.name = 'Entity Test ' + new Date().toLocaleString();
2028
2049
  testEntity.null = null;
2029
2050
  testEntity.string = 'test';
2030
2051
  testEntity.array = ['full', 'of', 'values', 500];
2052
+ testEntity.match = `Hello, my name is Edward McCheese. It is a pleasure to meet you. As you can see, I have several hats of the most pleasant nature.
2053
+
2054
+ This one's email address is nice_hat-wednesday+newyork@im-a-hat.hat.
2055
+ This one's phone number is (555) 555-1818.
2056
+ This one's zip code is 92064.
2057
+ This one's favorite emojis are 🔥❤️😊😂⭐🤔
2058
+
2059
+ These hats are absolutely fantastic.`;
2031
2060
  testEntity.number = 30;
2061
+ testEntity.numberString = '30';
2032
2062
  testEntity.timestamp = Date.now();
2033
2063
  testEntity.index = i + 'a';
2034
2064
 
2035
- const entityReferenceTest = await EntityClass.factory();
2065
+ const entityReferenceTest = await TestBModel.factory();
2036
2066
  entityReferenceTest.string = 'another';
2037
2067
  entityReferenceTest.index = i + 'b';
2038
2068
 
package/tsconfig.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "extends": "@tsconfig/recommended/tsconfig.json",
3
3
 
4
4
  "compilerOptions": {
5
- "lib": ["ES2021"],
6
- "target": "ES2021",
5
+ "lib": ["ES2023"],
6
+ "target": "ES2022",
7
7
  "noImplicitAny": true,
8
8
  "removeComments": false,
9
9
  "sourceMap": true,