Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Commit

Permalink
Allow custom ID
Browse files Browse the repository at this point in the history
v3.1.0
  • Loading branch information
onechiporenko committed Nov 25, 2021
1 parent 5c04036 commit 391f5f0
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 32 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ Use option `lastValuesCount` if your sequence items depends on limited number of

### Extending Factories

New Factory may be created based on another Factory. `attrs`, `createRelated`, `afterCreate` and all other fields will be put in the child Factory and overridden if needed:
New Factory may be created based on another Factory:

```typescript
class Parent1Factory extends Factory {
Expand Down Expand Up @@ -597,6 +597,8 @@ class ChildFactory extends Parent2Factory {
}
```

**IMPORTANT** All parent-factories must be registered in the Lair BEFORE any record of child-factory is create.

### Ignore related factories

There are some cases when you don't need to get all related to the record data. Let's go back to the example with `squad` and `units` (one `squad` has many `units` and one `unit` belongs to only one `squad`). We consider the cases:
Expand Down
95 changes: 68 additions & 27 deletions lib/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export interface SequenceMetaAttr<T> extends MetaAttr {
getNextValue: (prevItems: T[]) => T;
prevValues: T[];
lastValuesCount: number;
started: boolean;
}

export interface RelationshipMetaAttr extends MetaAttr {
Expand Down Expand Up @@ -88,6 +89,17 @@ const setupFactoryMeta = (classConstructor: any): void => {
}
};

const defaultSet = function (propertyKey) {
return function (v: any) {
if (!this.cache.has(this.currentRecordId)) {
this.cache.set(this.currentRecordId, {});
}
const recordCache = this.cache.get(this.currentRecordId);
recordCache[propertyKey] = v;
this.cache.set(this.currentRecordId, recordCache);
};
};

const updateFactoryMeta = (
classConstructor: any,
propertyKey: string,
Expand Down Expand Up @@ -151,14 +163,7 @@ export function field<T>(fieldOptions: FieldOptions<T> = {}): any {
this.cache.set(this.currentRecordId, recordCache);
return recordCache[propertyKey];
};
descriptor.set = function (v: any) {
if (!this.cache.has(this.currentRecordId)) {
this.cache.set(this.currentRecordId, {});
}
const recordCache = this.cache.get(this.currentRecordId);
recordCache[propertyKey] = v;
this.cache.set(this.currentRecordId, recordCache);
};
descriptor.set = defaultSet(propertyKey);
}
};
}
Expand Down Expand Up @@ -250,8 +255,11 @@ export function sequenceItem<T>(
`Decorator "sequenceItem" must be used only for instance properties (now it's used for "${propertyKey}")`,
!!target.constructor
);
setupFactoryMeta(target.constructor);
updateFactoryMeta(target.constructor, propertyKey, {
assert(
`"sequenceItem" for "${propertyKey}" should not have getter or setter`,
!descriptor
);
const propertyKeyMeta = {
getNextValue,
initialValue: getOrCalcValue<T>(initialValue),
lastValuesCount:
Expand All @@ -260,7 +268,36 @@ export function sequenceItem<T>(
: Infinity,
prevValues: [],
type: MetaAttrType.SEQUENCE_ITEM,
});
started: false,
};
setupFactoryMeta(target.constructor);
updateFactoryMeta(target.constructor, propertyKey, propertyKeyMeta);
if (!descriptor) {
const options = {} as PropertyDescriptor;
options.get = function () {
if (!this.cache.has(this.currentRecordId)) {
this.cache.set(this.currentRecordId, {});
}
const recordCache = this.cache.get(this.currentRecordId);
if (recordCache[propertyKey]) {
return recordCache[propertyKey];
}
const attrMeta = this.meta[propertyKey];
const v = attrMeta.started
? attrMeta.getNextValue.call(
this,
attrMeta.prevValues.slice(-attrMeta.lastValuesCount)
)
: attrMeta.initialValue;
attrMeta.prevValues.push(v);
attrMeta.started = true;
recordCache[propertyKey] = v;
this.cache.set(this.currentRecordId, recordCache);
return recordCache[propertyKey];
};
options.set = defaultSet(propertyKey);
defineProperty(target, propertyKey, options);
}
};
}

Expand Down Expand Up @@ -291,6 +328,7 @@ export class Factory {
{
...meta[attrName],
prevValues: [],
started: false,
},
true
);
Expand All @@ -305,7 +343,15 @@ export class Factory {
protected cache = new Map();
protected currentRecordId;

@field() id;
protected _id;

@field()
get id() {
return this._id;
}
set id(v) {
this._id = v;
}

get meta(): Meta {
return Reflect.getOwnMetadata(
Expand Down Expand Up @@ -353,10 +399,14 @@ export class Factory {
}

public constructor() {
setupFactoryMeta(this['__proto__'].constructor);
this.softInitMeta();
this.mergeMetaWithParent();
}

protected softInitMeta(): void {
setupFactoryMeta(this['__proto__'].constructor);
}

protected mergeMetaWithParent(): void {
const parentClass = this['__proto__']['__proto__'];
if (parentClass) {
Expand All @@ -380,11 +430,10 @@ export class Factory {
): LairRecord {
this.currentRecordId = id;
const _id = String(id);
this.id = _id;
const record = {
id: _id,
extraData,
} as LairRecord;
if (!this.allowCustomIds) {
this.id = _id;
}
const record = {} as LairRecord;
keys(this.meta).forEach((attrName) => {
const attrMeta = this.meta[attrName];
const options: PropertyDescriptor = { enumerable: true };
Expand All @@ -395,15 +444,7 @@ export class Factory {
options.value = [];
}
if (attrMeta.type === MetaAttrType.SEQUENCE_ITEM) {
const v =
id === 1
? attrMeta.initialValue
: attrMeta.getNextValue.call(
record,
attrMeta.prevValues.slice(-attrMeta.lastValuesCount)
);
attrMeta.prevValues.push(v);
options.value = copy(v);
options.value = copy(this[attrName]);
}
if (attrMeta.type === MetaAttrType.FIELD) {
options.value = copy(this[attrName]);
Expand Down
1 change: 1 addition & 0 deletions lib/lair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export class Lair {
keys(factory.meta).forEach((attrName) => {
if (
hasOwnProperty.call(newData, attrName) &&
attrName !== 'id' &&
factory.meta[attrName].type === MetaAttrType.FIELD
) {
this.db[fName][id][attrName] = newData[attrName];
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lair-db",
"version": "3.0.1",
"version": "3.1.0",
"description": "JS database",
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
Expand Down
8 changes: 6 additions & 2 deletions tests/factory-extend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe('Lair create records', () => {
@hasMany('a', 'manyB') manyA;
}
beforeEach(() => {
lair.registerFactory(new FactoryWithoutAttrsOverridesA());
lair.registerFactory(new FactoryWithoutAttrsOverridesAChild());
lair.registerFactory(new FactoryWithoutAttrsOverridesB());
FactoryWithoutAttrsOverridesA.resetMeta();
Expand Down Expand Up @@ -114,7 +115,8 @@ describe('Lair create records', () => {
@field() field = 'b';
}
beforeEach(() => {
lair.registerFactory(new FactoryWithStaticFieldB());
lair.registerFactory(FactoryWithStaticFieldA);
lair.registerFactory(FactoryWithStaticFieldB);
lair.createRecords('b', 1);
});
it('should override field', () => {
Expand All @@ -138,10 +140,12 @@ describe('Lair create records', () => {
}
}
beforeEach(() => {
lair.registerFactory(new FactoryWithDynamicFieldB());
lair.registerFactory(FactoryWithDynamicFieldA);
lair.registerFactory(FactoryWithDynamicFieldB);
lair.createRecords('b', 1);
});
it('should override field', () => {
console.error(JSON.stringify(lair.getAll('b'), null, 2));
expect(lair.getOne('b', '1').field).to.be.equal('b');
});
});
Expand Down
41 changes: 41 additions & 0 deletions tests/factory/custom-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { expect } from 'chai';
import { Factory, field, sequenceItem } from '../../lib/factory';
import { Lair } from '../../lib/lair';

let lair;

class FactoryWithCustomId extends Factory {
static factoryName = 'a';

@field()
get id() {
return `custom_${this.index}`;
}

@sequenceItem(1, (prevValues) => prevValues.length + 1)
index;

allowCustomIds = true;
}

describe('Factory', () => {
beforeEach(() => {
lair = Lair.getLair();
});
afterEach(() => {
Lair.cleanLair();
});

describe('#id', () => {
beforeEach(() => {
lair.registerFactory(FactoryWithCustomId);
});
it('should allow id to have a getter', () => {
lair.createRecords('a', 3);
console.error(JSON.stringify(lair.getAll('a'), null, 2));
expect(lair.getOne('a', 'custom_1')).to.have.property('index', 1);
expect(lair.getOne('a', 'custom_2')).to.have.property('index', 2);
expect(lair.getOne('a', 'custom_3')).to.have.property('index', 3);
});
});
});
19 changes: 19 additions & 0 deletions tests/lair/create-records/after-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ class FactoryToTestAfterCreate3cCase extends Factory {
}
}

class FactoryToTestAfterCreate4aCase extends Factory {
static factoryName = 'a';
afterCreate(record: LairRecord): LairRecord {
record.id = '100500';
return record;
}
}

describe('Lair', () => {
beforeEach(() => {
lair = Lair.getLair();
Expand Down Expand Up @@ -265,6 +273,17 @@ describe('Lair', () => {
});
});
});

describe('should not update id', () => {
beforeEach(() => {
lair.registerFactory(FactoryToTestAfterCreate4aCase);
lair.createRecords('a', 1);
});

it('id is not updated', () => {
expect(lair.getOne('a', '1').id).to.be.equal('1');
});
});
});
});
});

0 comments on commit 391f5f0

Please sign in to comment.