Skip to content

Commit

Permalink
perf(core): cache if entity has event listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Nov 5, 2023
1 parent 5515b18 commit cfa8d52
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 1 deletion.
5 changes: 5 additions & 0 deletions packages/core/src/enums.ts
Expand Up @@ -165,6 +165,11 @@ export enum EventType {
afterTransactionRollback = 'afterTransactionRollback',
}

export const EventTypeMap = Object.keys(EventType).reduce((a, b, i) => {
a[b as EventType] = i;
return a;
}, {} as Record<EventType, number>);

export type TransactionEventType = EventType.beforeTransactionStart | EventType.afterTransactionStart | EventType.beforeTransactionCommit | EventType.afterTransactionCommit | EventType.beforeTransactionRollback | EventType.afterTransactionRollback;

export interface TransactionOptions {
Expand Down
13 changes: 12 additions & 1 deletion packages/core/src/events/EventManager.ts
@@ -1,12 +1,13 @@
import type { AnyEntity, AsyncFunction, EntityMetadata } from '../typings';
import type { EventArgs, EventSubscriber, FlushEventArgs, TransactionEventArgs } from './EventSubscriber';
import { Utils } from '../utils';
import { EventType, type TransactionEventType } from '../enums';
import { EventType, EventTypeMap, type TransactionEventType } from '../enums';

export class EventManager {

private readonly listeners: { [K in EventType]?: EventSubscriber[] } = {};
private readonly entities: Map<EventSubscriber, string[]> = new Map();
private readonly cache: Map<number, boolean> = new Map();
private readonly subscribers: EventSubscriber[] = [];

constructor(subscribers: EventSubscriber[]) {
Expand All @@ -16,6 +17,7 @@ export class EventManager {
registerSubscriber(subscriber: EventSubscriber): void {
this.subscribers.push(subscriber);
this.entities.set(subscriber, this.getSubscribedEntities(subscriber));
this.cache.clear();
Utils.keys(EventType)
.filter(event => event in subscriber)
.forEach(event => {
Expand Down Expand Up @@ -55,20 +57,29 @@ export class EventManager {
}

hasListeners<T>(event: EventType, meta: EntityMetadata<T>): boolean {
const cacheKey = meta._id + EventTypeMap[event];

if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey)!;
}

const hasHooks = meta.hooks[event]?.length;

if (hasHooks) {
this.cache.set(cacheKey, true);
return true;
}

for (const listener of this.listeners[event] ?? []) {
const entities = this.entities.get(listener)!;

if (entities.length === 0 || entities.includes(meta.className)) {
this.cache.set(cacheKey, true);
return true;
}
}

this.cache.set(cacheKey, false);
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/typings.ts
Expand Up @@ -341,6 +341,8 @@ export interface EntityProperty<T = any> {

export class EntityMetadata<T = any> {

private static counter = 0;
readonly _id = 1000 * EntityMetadata.counter++; // keep the id >= 1000 to allow computing cache keys by simple addition
readonly propertyOrder = new Map<string, number>();

constructor(meta: Partial<EntityMetadata> = {}) {
Expand Down Expand Up @@ -571,6 +573,8 @@ export interface EntityMetadata<T = any> {
polymorphs?: EntityMetadata[];
root: EntityMetadata<T>;
definedProperties: Dictionary;
/** @internal can be used for computed numeric cache keys */
readonly _id: number;
}

export interface ISchemaGenerator {
Expand Down

0 comments on commit cfa8d52

Please sign in to comment.