Skip to content

Commit

Permalink
feat: make entities in nymph client instance specific too
Browse files Browse the repository at this point in the history
  • Loading branch information
hperrin committed Jan 8, 2023
1 parent 0f2e743 commit 1029f06
Show file tree
Hide file tree
Showing 17 changed files with 253 additions and 170 deletions.
2 changes: 1 addition & 1 deletion packages/client/src/Entity.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export interface EntityInterface extends DataObjectInterface {
$toReference(): EntityReference | EntityInterface;
}

export type EntityConstructor = (new () => EntityInterface) & {
export type EntityConstructor = (new (...args: any[]) => EntityInterface) & {
/**
* The instance of Nymph to use for queries.
*/
Expand Down
37 changes: 25 additions & 12 deletions packages/client/src/Nymph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default class Nymph {
/**
* The entity class for this instance of Nymph.
*/
public Entity: typeof Entity = Entity;
public Entity: typeof Entity;

private requestCallbacks: RequestCallback[] = [];
private responseCallbacks: ResponseCallback[] = [];
Expand All @@ -49,10 +49,7 @@ export default class Nymph {
// @ts-ignore TS doesn't know about WeakRef.
this.weakCache = !!NymphOptions.weakCache && typeof WeakRef !== 'undefined';

class NymphEntity<T extends EntityData = EntityData> extends Entity<T> {}
NymphEntity.nymph = this;
this.Entity = NymphEntity;
this.addEntityClass(NymphEntity);
this.Entity = this.addEntityClass(Entity);

requester = new HttpRequester(
'fetch' in NymphOptions ? NymphOptions.fetch : undefined
Expand All @@ -71,16 +68,32 @@ export default class Nymph {
});
}

public addEntityClass(entityClass: EntityConstructor) {
this.entityClasses[entityClass.class] = entityClass;
entityClass.nymph = this;
/**
* Add your class to this instance.
*
* This will create a class that extends your class within this instance of
* Nymph and return it. You can then use this class's constructor and methods,
* which will use this instance of Nymph.
*
* Because this creates a subclass, don't use the class
* returned from `getEntityClass` to check with `instanceof`.
*/
public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
const nymph = this;
class NymphEntity extends entityClass {
static nymph: Nymph = nymph;

constructor(...args: any[]) {
super(...args);
}
}
this.entityClasses[entityClass.class] = NymphEntity;
return NymphEntity;
}

public getEntityClass(className: string) {
if (this.entityClasses.hasOwnProperty(className)) {
const EntityClass = this.entityClasses[className];
EntityClass.nymph = this;
return EntityClass;
if (className in this.entityClasses) {
return this.entityClasses[className];
}
throw new ClassNotAvailableError(
"Tried to get class that's not available: " + className
Expand Down
16 changes: 10 additions & 6 deletions packages/nymph/src/Entity.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { MockNymph } from './testMocks';
import { TestBModel, TestModel, TestModelData } from './testArtifacts';
import {
TestBModel as TestBModelClass,
TestModel as TestModelClass,
TestModelData,
} from './testArtifacts';
import { cloneDeep } from 'lodash';

const nymph = new MockNymph();
Expand All @@ -9,11 +13,11 @@ jest.mock('./Nymph', () => ({
default: nymph,
}));

nymph.addEntityClass(TestModel);
nymph.addEntityClass(TestBModel);
const TestModel = nymph.addEntityClass(TestModelClass);
const TestBModel = nymph.addEntityClass(TestBModelClass);

let testEntity = TestModel.factorySync();
let entityReferenceTest: TestModel & TestModelData;
let entityReferenceTest: TestModelClass & TestModelData;
let entityReferenceGuid: string;

describe('Entity', () => {
Expand Down Expand Up @@ -71,7 +75,7 @@ describe('Entity', () => {

it('array searching work', async () => {
const testInArray = await TestModel.factory(testEntity.guid as string);
const array: (string | (TestModel & TestModelData))[] = [
const array: (string | (TestModelClass & TestModelData))[] = [
'thing',
testInArray,
];
Expand Down Expand Up @@ -198,7 +202,7 @@ describe('Entity', () => {
'nymph_entity_reference',
testEntity.guid as string,
'TestModel',
]) as TestModel & TestModelData;
]) as TestModelClass & TestModelData;

expect(entity.guid).toEqual(testEntity.guid);
expect(entity.cdate).toEqual(testEntity.cdate);
Expand Down
54 changes: 27 additions & 27 deletions packages/nymph/src/Nymph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,33 @@ export default class Nymph {
private beforeDeleteUIDCallbacks: NymphBeforeDeleteUIDCallback[] = [];
private afterDeleteUIDCallbacks: NymphAfterDeleteUIDCallback[] = [];

/**
* Initialize Nymph.
*
* @param config The Nymph configuration.
* @param driver The Nymph database driver.
* @param tilmeld The Tilmeld user/group manager instance, if you want to use it.
*/
public constructor(
config: Partial<Config>,
driver: NymphDriver,
tilmeld?: TilmeldInterface
) {
this.config = { ...defaults, ...config };
this.driver = driver;

this.Entity = this.addEntityClass(Entity);

if (typeof tilmeld !== 'undefined') {
this.tilmeld = tilmeld;
}

this.driver.init(this);
if (this.tilmeld) {
this.tilmeld.init(this);
}
}

/**
* Add your class to this instance.
*
Expand Down Expand Up @@ -120,33 +147,6 @@ export default class Nymph {
throw new ClassNotAvailableError('Tried to use class: ' + className);
}

/**
* Initialize Nymph.
*
* @param config The Nymph configuration.
* @param driver The Nymph database driver.
* @param tilmeld The Tilmeld user/group manager instance, if you want to use it.
*/
public constructor(
config: Partial<Config>,
driver: NymphDriver,
tilmeld?: TilmeldInterface
) {
this.config = { ...defaults, ...config };
this.driver = driver;

this.Entity = this.addEntityClass(Entity);

if (typeof tilmeld !== 'undefined') {
this.tilmeld = tilmeld;
}

this.driver.init(this);
if (this.tilmeld) {
this.tilmeld.init(this);
}
}

/**
* Get a clone of this instance with duplicate classes and event listeners.
*
Expand Down
21 changes: 14 additions & 7 deletions packages/nymph/src/testMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,31 @@ export class MockNymph {
private entityClasses: { [k: string]: EntityConstructor } = {};
public driver: MockNymphDriver;
public Tilmeld: any = undefined;
public Entity: typeof Entity;

public constructor() {
this.driver = new MockNymphDriver(this);

// class NymphEntity extends Entity {}
this.addEntityClass(Entity);
this.Entity = this.addEntityClass(Entity);
}

public addEntityClass(entityClass: EntityConstructor) {
this.entityClasses[entityClass.class] = entityClass;
entityClass.nymph = this as unknown as Nymph;
public addEntityClass<T extends EntityConstructor>(entityClass: T): T {
const nymph = this;
class NymphEntity extends entityClass {
static nymph: Nymph = nymph as unknown as Nymph;

constructor(...args: any[]) {
super(...args);
}
}
this.entityClasses[entityClass.class] = NymphEntity;
return NymphEntity;
}

public getEntityClass(className: string): EntityConstructor {
if (className in this.entityClasses) {
const EntityClass = this.entityClasses[className];
EntityClass.nymph = this as unknown as Nymph;
return EntityClass;
return this.entityClasses[className];
}
throw new ClassNotAvailableError('Tried to use class: ' + className);
}
Expand Down
26 changes: 13 additions & 13 deletions packages/pubsub/src/PubSub.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { Nymph as NymphServer } from '@nymphjs/nymph';
import { Nymph, PubSub } from '@nymphjs/client-node';
import createRestServer from '@nymphjs/server';
import {
EmployeeModel,
Employee,
EmployeeModel as EmployeeModelClass,
Employee as EmployeeClass,
EmployeeData,
} from '@nymphjs/server/dist/testArtifacts.js';

Expand All @@ -23,7 +23,7 @@ const pubSubConfig = {
};

const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
nymphServer.addEntityClass(EmployeeModel);
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);
PubSubServer.initPublisher(pubSubConfig, nymphServer);

const app = express();
Expand All @@ -39,7 +39,7 @@ const nymphOptions = {
};
const nymph = new Nymph(nymphOptions);
const pubsub = new PubSub(nymphOptions, nymph);
nymph.addEntityClass(Employee);
const Employee = nymph.addEntityClass(EmployeeClass);

describe('Nymph REST Server and Client', () => {
async function createJane() {
Expand Down Expand Up @@ -91,7 +91,7 @@ describe('Nymph REST Server and Client', () => {
}

it('notified of new match', async () => {
let jane: Promise<Employee>;
let jane: Promise<EmployeeClass>;

await new Promise((resolve) => {
let updated = false;
Expand Down Expand Up @@ -120,7 +120,7 @@ describe('Nymph REST Server and Client', () => {

it('notified of entity update', async () => {
let jane = await createJane();
let entities: (Employee & EmployeeData)[] = [];
let entities: (EmployeeClass & EmployeeData)[] = [];

await new Promise((resolve) => {
let mdate = 0;
Expand Down Expand Up @@ -155,7 +155,7 @@ describe('Nymph REST Server and Client', () => {

it('notified of entity update for qref query', async () => {
let [jane, john] = await createBossJane();
let entities: (Employee & EmployeeData)[] = [];
let entities: (EmployeeClass & EmployeeData)[] = [];

await new Promise((resolve) => {
let mdate = 0;
Expand Down Expand Up @@ -193,7 +193,7 @@ describe('Nymph REST Server and Client', () => {

it('notified of new match for qref query', async () => {
let [jane, john] = await createBossJane();
let entities: (Employee & EmployeeData)[] = [];
let entities: (EmployeeClass & EmployeeData)[] = [];

await new Promise((resolve) => {
if (jane.guid == null || john.guid == null) {
Expand Down Expand Up @@ -230,7 +230,7 @@ describe('Nymph REST Server and Client', () => {

it('notified of removed match for qref query', async () => {
let [jane, john] = await createBossJane();
let entities: (Employee & EmployeeData)[] = [];
let entities: (EmployeeClass & EmployeeData)[] = [];

await new Promise((resolve) => {
if (jane.guid == null || john.guid == null) {
Expand Down Expand Up @@ -267,7 +267,7 @@ describe('Nymph REST Server and Client', () => {

it('receives correct number of updates', async () => {
let jane = await createJane();
let entities: (Employee & EmployeeData)[] = [];
let entities: (EmployeeClass & EmployeeData)[] = [];

// Wait for change to propagate. (Only needed since we're not going across network.)
await new Promise((resolve) => setTimeout(() => resolve(true), 10));
Expand Down Expand Up @@ -306,7 +306,7 @@ describe('Nymph REST Server and Client', () => {

it('notified of entity delete', async () => {
let jane = await createJane();
let entities: (Employee & EmployeeData)[] = [];
let entities: (EmployeeClass & EmployeeData)[] = [];

// Wait for change to propagate. (Only needed since we're not going across network.)
await new Promise((resolve) => setTimeout(() => resolve(true), 10));
Expand Down Expand Up @@ -342,8 +342,8 @@ describe('Nymph REST Server and Client', () => {
});

it('entire match is updated', async () => {
let jane: (Employee & EmployeeData) | undefined;
let entities: (Employee & EmployeeData)[] = [];
let jane: (EmployeeClass & EmployeeData) | undefined;
let entities: (EmployeeClass & EmployeeData)[] = [];
await createJane();

// Wait for change to propagate. (Only needed since we're not going across network.)
Expand Down
9 changes: 6 additions & 3 deletions packages/server/src/cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import { Nymph as NymphServer } from '@nymphjs/nymph';
import { Nymph } from '@nymphjs/client-node';

import createServer from './index';
import { EmployeeModel, Employee } from './testArtifacts';
import {
EmployeeModel as EmployeeModelClass,
Employee as EmployeeClass,
} from './testArtifacts';

const sqliteConfig = {
filename: ':memory:',
};

const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
nymphServer.addEntityClass(EmployeeModel);
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);

const app = express();
app.use('/test', createServer(nymphServer));
Expand All @@ -21,7 +24,7 @@ const nymph = new Nymph({
restUrl: 'http://localhost:5081/test/',
weakCache: true,
});
nymph.addEntityClass(Employee);
const Employee = nymph.addEntityClass(EmployeeClass);

describe('Nymph REST Server and Client with Client Weak Ref Cache', () => {
async function createJane() {
Expand Down
9 changes: 6 additions & 3 deletions packages/server/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import { Nymph } from '@nymphjs/client-node';
import { Entity } from '@nymphjs/client';

import createServer from './index';
import { EmployeeModel, Employee } from './testArtifacts';
import {
EmployeeModel as EmployeeModelClass,
Employee as EmployeeClass,
} from './testArtifacts';

const sqliteConfig = {
filename: ':memory:',
};

const nymphServer = new NymphServer({}, new SQLite3Driver(sqliteConfig));
nymphServer.addEntityClass(EmployeeModel);
const EmployeeModel = nymphServer.addEntityClass(EmployeeModelClass);

const app = express();
app.use('/test', createServer(nymphServer));
Expand All @@ -21,7 +24,7 @@ const server = app.listen(5080);
const nymph = new Nymph({
restUrl: 'http://localhost:5080/test/',
});
nymph.addEntityClass(Employee);
const Employee = nymph.addEntityClass(EmployeeClass);

describe('Nymph REST Server and Client', () => {
async function createJane() {
Expand Down
Loading

0 comments on commit 1029f06

Please sign in to comment.