Add BaseRedisRepository as parent class of RedisNotificationRepository.ts and RedisParkingRepository.ts

This commit is contained in:
2025-07-02 20:00:44 -04:00
parent 19336ce6ec
commit 53632fe470
3 changed files with 56 additions and 85 deletions

View File

@@ -0,0 +1,33 @@
import { createClient } from 'redis';
export abstract class BaseRedisRepository {
protected redisClient;
constructor(
redisClient = createClient({
url: process.env.REDIS_URL,
socket: {
tls: (process.env.REDIS_URL?.match(/rediss:/) != null),
rejectUnauthorized: false,
}
}),
) {
this.redisClient = redisClient;
}
get isReady() {
return this.redisClient.isReady;
}
public async connect() {
await this.redisClient.connect();
}
public async disconnect() {
await this.redisClient.disconnect();
}
public async clearAllData() {
await this.redisClient.flushAll();
}
}

View File

@@ -6,52 +6,18 @@ import {
NotificationRepository,
ScheduledNotification
} from "./NotificationRepository";
import { createClient } from "redis";
import { BaseRedisRepository } from "./BaseRedisRepository";
export class RedisNotificationRepository implements NotificationRepository {
export class RedisNotificationRepository extends BaseRedisRepository implements NotificationRepository {
private listeners: Listener[] = [];
private readonly NOTIFICATION_KEY_PREFIX = 'notification:';
constructor(
private redisClient = createClient({
url: process.env.REDIS_URL,
socket: {
tls: (process.env.REDIS_URL?.match(/rediss:/) != null),
rejectUnauthorized: false,
}
}),
) {
this.getAllNotificationsForShuttleAndStopId = this.getAllNotificationsForShuttleAndStopId.bind(this);
this.getSecondsThresholdForNotificationIfExists = this.getSecondsThresholdForNotificationIfExists.bind(this);
this.deleteNotificationIfExists = this.deleteNotificationIfExists.bind(this);
this.addOrUpdateNotification = this.addOrUpdateNotification.bind(this);
this.isNotificationScheduled = this.isNotificationScheduled.bind(this);
this.subscribeToNotificationChanges = this.subscribeToNotificationChanges.bind(this);
this.unsubscribeFromNotificationChanges = this.unsubscribeFromNotificationChanges.bind(this);
}
get isReady() {
return this.redisClient.isReady;
}
public async connect() {
await this.redisClient.connect();
}
public async disconnect() {
await this.redisClient.disconnect();
}
public async clearAllData() {
await this.redisClient.flushAll();
}
private getNotificationKey(shuttleId: string, stopId: string): string {
private getNotificationKey = (shuttleId: string, stopId: string): string => {
const tuple = new TupleKey(shuttleId, stopId);
return `${this.NOTIFICATION_KEY_PREFIX}${tuple.toString()}`;
}
};
public async addOrUpdateNotification(notification: ScheduledNotification): Promise<void> {
public addOrUpdateNotification = async (notification: ScheduledNotification): Promise<void> => {
const { shuttleId, stopId, deviceId, secondsThreshold } = notification;
const key = this.getNotificationKey(shuttleId, stopId);
@@ -64,9 +30,9 @@ export class RedisNotificationRepository implements NotificationRepository {
};
listener(event);
});
}
};
public async deleteNotificationIfExists(lookupArguments: NotificationLookupArguments): Promise<void> {
public deleteNotificationIfExists = async (lookupArguments: NotificationLookupArguments): Promise<void> => {
const { shuttleId, stopId, deviceId } = lookupArguments;
const key = this.getNotificationKey(shuttleId, stopId);
@@ -93,12 +59,12 @@ export class RedisNotificationRepository implements NotificationRepository {
listener(event);
});
}
}
};
public async getAllNotificationsForShuttleAndStopId(
public getAllNotificationsForShuttleAndStopId = async (
shuttleId: string,
stopId: string
): Promise<ScheduledNotification[]> {
): Promise<ScheduledNotification[]> => {
const key = this.getNotificationKey(shuttleId, stopId);
const allNotifications = await this.redisClient.hGetAll(key);
@@ -108,40 +74,40 @@ export class RedisNotificationRepository implements NotificationRepository {
deviceId,
secondsThreshold: parseInt(secondsThreshold)
}));
}
};
public async getSecondsThresholdForNotificationIfExists(
public getSecondsThresholdForNotificationIfExists = async (
lookupArguments: NotificationLookupArguments
): Promise<number | null> {
): Promise<number | null> => {
const { shuttleId, stopId, deviceId } = lookupArguments;
const key = this.getNotificationKey(shuttleId, stopId);
const threshold = await this.redisClient.hGet(key, deviceId);
return threshold ? parseInt(threshold) : null;
}
};
public async isNotificationScheduled(
public isNotificationScheduled = async (
lookupArguments: NotificationLookupArguments
): Promise<boolean> {
): Promise<boolean> => {
const threshold = await this.getSecondsThresholdForNotificationIfExists(lookupArguments);
return threshold !== null;
}
};
public subscribeToNotificationChanges(listener: Listener): void {
public subscribeToNotificationChanges = (listener: Listener): void => {
const index = this.listeners.findIndex(
(existingListener) => existingListener === listener
);
if (index < 0) {
this.listeners.push(listener);
}
}
};
public unsubscribeFromNotificationChanges(listener: Listener): void {
public unsubscribeFromNotificationChanges = (listener: Listener): void => {
const index = this.listeners.findIndex(
(existingListener) => existingListener === listener
);
if (index >= 0) {
this.listeners.splice(index, 1);
}
}
};
}

View File

@@ -1,45 +1,17 @@
import { createClient } from 'redis';
import { ParkingGetterSetterRepository } from "./ParkingGetterSetterRepository";
import { IParkingStructure, IParkingStructureTimestampRecord } from "../entities/ParkingRepositoryEntities";
import { HistoricalParkingAverageQueryResult, ParkingStructureCountOptions } from "./ParkingGetterRepository";
import { BaseRedisRepository } from "./BaseRedisRepository";
export type ParkingStructureID = string;
// Every 10 minutes
export const PARKING_LOGGING_INTERVAL_MS = 600000;
export class RedisParkingRepository implements ParkingGetterSetterRepository {
export class RedisParkingRepository extends BaseRedisRepository implements ParkingGetterSetterRepository {
private dataLastAdded: Map<ParkingStructureID, Date> = new Map();
private loggingIntervalMs = PARKING_LOGGING_INTERVAL_MS;
constructor(
private redisClient = createClient({
url: process.env.REDIS_URL,
socket: {
tls: (process.env.REDIS_URL?.match(/rediss:/) != null),
rejectUnauthorized: false,
}
}),
) {
}
get isReady() {
return this.redisClient.isReady;
}
public async connect() {
await this.redisClient.connect();
}
public async disconnect() {
await this.redisClient.disconnect();
}
public async clearAllData() {
await this.redisClient.flushAll();
this.dataLastAdded.clear();
}
addOrUpdateParkingStructure = async (structure: IParkingStructure): Promise<void> => {
// Store current structure data
await this.redisClient.hSet(`parking:structure:${structure.id}`, {