diff --git a/package.json b/package.json index 895d977b..4eb6eddf 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "md5": "^2.3.0", "outvariant": "^1.2.1", "pluralize": "^8.0.0", - "strict-event-emitter": "^0.2.0", + "strict-event-emitter": "^0.5.0", "uuid": "^8.3.1" }, "optionalDependencies": { @@ -65,4 +65,4 @@ "path": "./node_modules/cz-conventional-changelog" } } -} \ No newline at end of file +} diff --git a/src/db/Database.ts b/src/db/Database.ts index 92745e13..dd0d1178 100644 --- a/src/db/Database.ts +++ b/src/db/Database.ts @@ -1,6 +1,6 @@ import md5 from 'md5' import { invariant } from 'outvariant' -import { StrictEventEmitter } from 'strict-event-emitter' +import { Emitter } from 'strict-event-emitter' import { Entity, ENTITY_TYPE, @@ -27,40 +27,31 @@ export interface SerializedEntity extends Entity { [SERIALIZED_INTERNAL_PROPERTIES_KEY]: SerializedInternalEntityProperties } -export type DatabaseMethodToEventFn = ( - sourceId: string, - args: ArgsType, -) => void - -export interface DatabaseEventsMap { - create: DatabaseMethodToEventFn< - [ - modelName: KeyType, - entity: SerializedEntity, - customPrimaryKey?: PrimaryKeyType, - ] - > - update: DatabaseMethodToEventFn< - [ - modelName: KeyType, - prevEntity: SerializedEntity, - nextEntity: SerializedEntity, - ] - > - delete: DatabaseMethodToEventFn< - [modelName: KeyType, primaryKey: PrimaryKeyType] - > +export type DatabaseEventsMap = { + create: [ + sourceId: string, + modelName: KeyType, + entity: SerializedEntity, + customPrimaryKey?: PrimaryKeyType, + ] + update: [ + sourceId: string, + modelName: KeyType, + prevEntity: SerializedEntity, + nextEntity: SerializedEntity, + ] + delete: [sourceId: string, modelName: KeyType, primaryKey: PrimaryKeyType] } let callOrder = 0 export class Database { public id: string - public events: StrictEventEmitter + public events: Emitter private models: Models constructor(dictionary: Dictionary) { - this.events = new StrictEventEmitter() + this.events = new Emitter() this.models = Object.keys(dictionary).reduce>( (acc, modelName: keyof Dictionary) => { acc[modelName] = new Map>() @@ -120,11 +111,13 @@ export class Database { const primaryKey = customPrimaryKey || (entity[entity[PRIMARY_KEY]] as string) - this.events.emit('create', this.id, [ + this.events.emit( + 'create', + this.id, modelName, this.serializeEntity(entity), customPrimaryKey, - ]) + ) return this.getModel(modelName).set(primaryKey, entity) } @@ -143,11 +136,13 @@ export class Database { this.getModel(modelName).set(nextPrimaryKey, nextEntity) // this.create(modelName, nextEntity, nextPrimaryKey) - this.events.emit('update', this.id, [ + this.events.emit( + 'update', + this.id, modelName, this.serializeEntity(prevEntity), this.serializeEntity(nextEntity), - ]) + ) } delete( @@ -155,7 +150,7 @@ export class Database { primaryKey: PrimaryKeyType, ): void { this.getModel(modelName).delete(primaryKey) - this.events.emit('delete', this.id, [modelName, primaryKey]) + this.events.emit('delete', this.id, modelName, primaryKey) } has( diff --git a/src/extensions/sync.ts b/src/extensions/sync.ts index 90bb4576..8768896c 100644 --- a/src/extensions/sync.ts +++ b/src/extensions/sync.ts @@ -6,26 +6,29 @@ import { SERIALIZED_INTERNAL_PROPERTIES_KEY, } from '../db/Database' import { inheritInternalProperties } from '../utils/inheritInternalProperties' +import { Listener } from 'strict-event-emitter' export type DatabaseMessageEventData = | { operationType: 'create' - payload: Parameters + payload: DatabaseEventsMap['create'] } | { operationType: 'update' - payload: Parameters + payload: DatabaseEventsMap['update'] } | { operationType: 'delete' - payload: Parameters + payload: DatabaseEventsMap['delete'] } function removeListeners( event: Event, db: Database, ) { - const listeners = db.events.listeners(event) as DatabaseEventsMap[Event][] + const listeners = db.events.listeners(event) as Listener< + DatabaseEventsMap[Event] + >[] listeners.forEach((listener) => { db.events.removeListener(event, listener) @@ -90,13 +93,13 @@ export function sync(db: Database) { // to the current database instance. switch (event.data.operationType) { case 'create': { - const [modelName, entity, customPrimaryKey] = event.data.payload[1] + const [_, modelName, entity, customPrimaryKey] = event.data.payload db.create(modelName, deserializeEntity(entity), customPrimaryKey) break } case 'update': { - const [modelName, prevEntity, nextEntity] = event.data.payload[1] + const [_, modelName, prevEntity, nextEntity] = event.data.payload db.update( modelName, deserializeEntity(prevEntity), @@ -105,8 +108,10 @@ export function sync(db: Database) { break } - default: { - db[event.data.operationType](...event.data.payload[1]) + case 'delete': { + const [_, modelName, primaryKey] = event.data.payload + db.delete(modelName, primaryKey) + break } } @@ -120,7 +125,7 @@ export function sync(db: Database) { function broadcastDatabaseEvent( operationType: Event, ) { - return (...payload: Parameters) => { + return (...payload: DatabaseEventsMap[Event]) => { channel.postMessage({ operationType, payload, diff --git a/src/model/generateGraphQLHandlers.ts b/src/model/generateGraphQLHandlers.ts index c5cccc71..474aec2e 100644 --- a/src/model/generateGraphQLHandlers.ts +++ b/src/model/generateGraphQLHandlers.ts @@ -57,7 +57,11 @@ function createComparatorGraphQLInputType( name, fields: Object.keys(comparators).reduce( (fields, comparatorFn) => { - const fieldType = ['between', 'notBetween', 'in', 'notIn'].includes(comparatorFn) ? new GraphQLList(type) : type + const fieldType = ['between', 'notBetween', 'in', 'notIn'].includes( + comparatorFn, + ) + ? new GraphQLList(type) + : type fields[comparatorFn] = { type: fieldType } return fields }, diff --git a/src/model/generateRestHandlers.ts b/src/model/generateRestHandlers.ts index 08388653..39870fa9 100644 --- a/src/model/generateRestHandlers.ts +++ b/src/model/generateRestHandlers.ts @@ -32,7 +32,10 @@ type RequestParams = { export function createUrlBuilder(baseUrl?: string) { return (path: string) => { // For the previous implementation trailing slash didn't matter, we must keep it this way for backward compatibility - const normalizedBaseUrl = baseUrl && baseUrl.slice(-1) === '/' ? baseUrl.slice(0, -1) : baseUrl || ''; + const normalizedBaseUrl = + baseUrl && baseUrl.slice(-1) === '/' + ? baseUrl.slice(0, -1) + : baseUrl || '' return `${normalizedBaseUrl}/${path}` } } diff --git a/src/utils/iteratorUtils.ts b/src/utils/iteratorUtils.ts index 212d60a7..52c7c34a 100644 --- a/src/utils/iteratorUtils.ts +++ b/src/utils/iteratorUtils.ts @@ -1,4 +1,4 @@ -import { PrimaryKeyType } from "../glossary" +import { PrimaryKeyType } from '../glossary' export function forEach( fn: (key: K, value: V) => any, diff --git a/test/db/events.test.ts b/test/db/events.test.ts index 4e649e14..f8bede6a 100644 --- a/test/db/events.test.ts +++ b/test/db/events.test.ts @@ -19,7 +19,7 @@ test('emits the "create" event when a new entity is created', (done) => { user: dictionary.user, }) - db.events.on('create', (id, [modelName, entity, primaryKey]) => { + db.events.on('create', (id, modelName, entity, primaryKey) => { expect(id).toEqual(db.id) expect(modelName).toEqual('user') expect(entity).toEqual({ @@ -69,7 +69,7 @@ test('emits the "update" event when an existing entity is updated', (done) => { user: dictionary.user, }) - db.events.on('update', (id, [modelName, prevEntity, nextEntity]) => { + db.events.on('update', (id, modelName, prevEntity, nextEntity) => { expect(id).toEqual(db.id) expect(modelName).toEqual('user') expect(prevEntity).toEqual({ @@ -133,7 +133,7 @@ test('emits the "delete" event when an existing entity is deleted', (done) => { user: dictionary.user, }) - db.events.on('delete', (id, [modelName, primaryKey]) => { + db.events.on('delete', (id, modelName, primaryKey) => { expect(id).toEqual(db.id) expect(modelName).toEqual('user') expect(primaryKey).toEqual('abc-123') diff --git a/yarn.lock b/yarn.lock index 2d3ef2f3..6ae8949c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -814,7 +814,7 @@ resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== -"@types/debug@^4.1.5", "@types/debug@^4.1.7": +"@types/debug@^4.1.7": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== @@ -5475,6 +5475,11 @@ strict-event-emitter@^0.2.0: dependencies: events "^3.3.0" +strict-event-emitter@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/strict-event-emitter/-/strict-event-emitter-0.5.0.tgz#a4aa84a3d9b4a9be12e750a75e089cabb3dbc0e2" + integrity sha512-sqnMpVJLSB3daNO6FcvsEk4Mq5IJeAwDeH80DP1S8+pgxrF6yZnE1+VeapesGled7nEcIkz1Ax87HzaIy+02kA== + string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"