Skip to content

Commit

Permalink
SC-2369: Firebase mirror | Part 3 (#70)
Browse files Browse the repository at this point in the history
* Fix unsubscribe from events

* Create mirror interfaces

---------

Co-authored-by: Nikita Bereziuk <nikita.bereziuk@sysgears.com>
  • Loading branch information
bnwebdev and Nikita Bereziuk authored Sep 26, 2023
1 parent e40b206 commit 194bee7
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 1 deletion.
105 changes: 105 additions & 0 deletions src/modules/firebase/firebase-mirror/firebase-mirror-core.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { skipFirst } from '../../common/common.utils';
import {
SubscriptionService,
Unsubscribe,
} from '../../subscription-manager/subscription-manager.types';
import {
FirebaseSnapshot,
FirebaseTable,
FirebaseTableReference,
} from '../firebase.types';
import { subscribeOnFirebaseEvent } from '../firebase.utils';

export abstract class FirebaseMirrorCoreService<Entity>
implements SubscriptionService
{
static dataByTableName: Map<string, Map<string, unknown>> = new Map();

protected readonly tableName: string;

constructor(protected readonly reference: FirebaseTableReference<Entity>) {
this.tableName = this.getTableName(reference);
this.initializeTableData();
}

public async subscribe(): Promise<Unsubscribe> {
await this.loadTableData();

const unsubscribes = [
subscribeOnFirebaseEvent<FirebaseTable<Entity>, 'child_changed'>(
this.reference,
'child_changed',
this.entityAddedOrUpdatedHandler,
),
subscribeOnFirebaseEvent(
this.reference.limitToLast(1),
'child_added',
skipFirst(this.entityAddedOrUpdatedHandler),
),
subscribeOnFirebaseEvent(
this.reference,
'child_removed',
this.entityRemovedHandler,
),
];

return () => unsubscribes.forEach((unsubscribe) => unsubscribe());
}

protected getTableData(): Map<string, Entity> {
const { dataByTableName } = FirebaseMirrorCoreService;
const { key: tableName } = this.reference;

return dataByTableName.get(tableName || '') as Map<string, Entity>;
}

entityAddedOrUpdatedHandler = (snapshot: FirebaseSnapshot<Entity>): void => {
const { key } = snapshot;
const candidate = snapshot.val();

if (key && candidate) {
this.getTableData().set(key, candidate);
}
};

private entityRemovedHandler = (snapshot: FirebaseSnapshot<Entity>): void => {
const { key } = snapshot;
const candidate = snapshot.val();

if (key && candidate) {
this.getTableData().delete(key);
}
};

private getTableName(reference: FirebaseTableReference<Entity>): string {
const { key: tableName } = reference;

if (!tableName) {
throw new Error('Table name is not defined');
}

return tableName;
}

private initializeTableData(): void {
const { dataByTableName } = FirebaseMirrorCoreService;

if (!dataByTableName.has(this.tableName)) {
dataByTableName.set(this.tableName, new Map());
}
}

private async loadTableData(): Promise<void> {
const snapshot = await this.reference.get();
const tableData = this.getTableData();

snapshot.forEach((childSnapshot) => {
const { key } = childSnapshot;
const data = childSnapshot.val();

if (key && data) {
tableData.set(key, data);
}
});
}
}
13 changes: 13 additions & 0 deletions src/modules/firebase/firebase-mirror/firebase-mirror.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { FirebaseMirrorCoreService } from './firebase-mirror-core.interface';

export abstract class FirebaseMirrorService<
Entity,
> extends FirebaseMirrorCoreService<Entity> {
getByKey(key: string): Entity | undefined {
return this.getTableData().get(key);
}

getAll(): Array<[string, Entity]> {
return Array.from(this.getTableData());
}
}
2 changes: 1 addition & 1 deletion src/modules/firebase/firebase.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ export const subscribeOnFirebaseEvent = <Entity, Event extends EventType>(
): (() => void) => {
ref.on(eventType, eventHandler);

return () => ref.off(eventType);
return () => ref.off(eventType, eventHandler);
};

0 comments on commit 194bee7

Please sign in to comment.