Change ParkingStructureCountOptions and HistoricalParkingAverageQueryResult to use Date objects

This matches the behavior of `updatedTime` on shuttle objects. When returning API data, dates are converted into milliseconds since Epoch by the DateTime scalar implementation.
This commit is contained in:
2025-07-19 12:12:08 -04:00
parent ed037cf2d2
commit 8ee1f1522e
6 changed files with 30 additions and 26 deletions

View File

@@ -9,7 +9,7 @@ export interface IParkingStructure extends IEntityWithTimestamp, IEntityWithId {
}
export interface IParkingStructureTimestampRecord {
timestampMs: number;
timestampMs: Date;
id: string;
spotsAvailable: number;
}

View File

@@ -16,7 +16,7 @@ export interface NotificationAlertArguments {
export class AppleNotificationSender {
private apnsToken: string | undefined = undefined;
private _lastRefreshedTimeMs: number | undefined = undefined;
private _lastRefreshedTimeMs: Date | undefined = undefined;
constructor(
private shouldActuallySendNotifications = true,
@@ -34,13 +34,13 @@ export class AppleNotificationSender {
}
}
get lastRefreshedTimeMs(): number | undefined {
get lastRefreshedTimeMs(): Date | undefined {
return this._lastRefreshedTimeMs;
}
private lastReloadedTimeForAPNsIsTooRecent() {
const thirtyMinutesMs = 1800000;
return this._lastRefreshedTimeMs && Date.now() - this._lastRefreshedTimeMs < thirtyMinutesMs;
return this._lastRefreshedTimeMs && Date.now() - this._lastRefreshedTimeMs.getTime() < thirtyMinutesMs;
}
public reloadAPNsTokenIfTimePassed() {
@@ -70,7 +70,7 @@ export class AppleNotificationSender {
algorithm: "ES256",
header: tokenHeader
});
this._lastRefreshedTimeMs = nowMs;
this._lastRefreshedTimeMs = new Date(nowMs);
}
/**

View File

@@ -80,7 +80,7 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
private createTimestampRecord = (structure: IParkingStructure, timestampMs: number): IParkingStructureTimestampRecord => ({
id: structure.id,
spotsAvailable: structure.spotsAvailable,
timestampMs,
timestampMs: new Date(timestampMs),
});
private ensureHistoricalDataExists = (structureId: string): void => {
@@ -90,7 +90,7 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
};
private addRecordToHistoricalData = (structureId: string, record: IParkingStructureTimestampRecord): void => {
const sortingCallback = (a: IParkingStructureTimestampRecord, b: IParkingStructureTimestampRecord) => a.timestampMs - b.timestampMs;
const sortingCallback = (a: IParkingStructureTimestampRecord, b: IParkingStructureTimestampRecord) => a.timestampMs.getTime() - b.timestampMs.getTime();
this.historicalData.get(structureId)?.appendWithSorting(record, sortingCallback);
};
@@ -112,10 +112,11 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
const results: HistoricalParkingAverageQueryResult[] = [];
const { startUnixEpochMs, endUnixEpochMs, intervalMs } = options;
let currentIntervalStart = startUnixEpochMs;
let currentIntervalStart = startUnixEpochMs.getTime();
const endTime = endUnixEpochMs.getTime();
while (currentIntervalStart < endUnixEpochMs) {
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endUnixEpochMs);
while (currentIntervalStart < endTime) {
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endTime);
const recordsInInterval = this.getRecordsInTimeRange(records, currentIntervalStart, currentIntervalEnd);
if (recordsInInterval.length > 0) {
@@ -135,7 +136,7 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
endMs: number
): IParkingStructureTimestampRecord[] => {
return records.filter(record =>
record.timestampMs >= startMs && record.timestampMs < endMs
record.timestampMs.getTime() >= startMs && record.timestampMs.getTime() < endMs
);
};
@@ -148,8 +149,8 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
const averageSpotsAvailable = totalSpotsAvailable / records.length;
return {
fromUnixEpochMs: fromMs,
toUnixEpochMs: toMs,
fromUnixEpochMs: new Date(fromMs),
toUnixEpochMs: new Date(toMs),
averageSpotsAvailable
};
};

View File

@@ -1,14 +1,14 @@
import { IParkingStructure } from "../../entities/ParkingRepositoryEntities";
export interface ParkingStructureCountOptions {
startUnixEpochMs: number;
endUnixEpochMs: number;
startUnixEpochMs: Date;
endUnixEpochMs: Date;
intervalMs: number;
}
export interface HistoricalParkingAverageQueryResult {
fromUnixEpochMs: number;
toUnixEpochMs: number;
fromUnixEpochMs: Date;
toUnixEpochMs: Date;
averageSpotsAvailable: number;
}

View File

@@ -163,10 +163,11 @@ export class RedisParkingRepository extends BaseRedisRepository implements Parki
const { startUnixEpochMs, endUnixEpochMs, intervalMs } = options;
const results: HistoricalParkingAverageQueryResult[] = [];
let currentIntervalStart = startUnixEpochMs;
let currentIntervalStart = startUnixEpochMs.getTime();
const endTime = endUnixEpochMs.getTime();
while (currentIntervalStart < endUnixEpochMs) {
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endUnixEpochMs);
while (currentIntervalStart < endTime) {
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endTime);
try {
const aggregationResult = await this.redisClient.sendCommand([
@@ -182,8 +183,8 @@ export class RedisParkingRepository extends BaseRedisRepository implements Parki
if (aggregationResult && aggregationResult.length > 0) {
const [, averageValue] = aggregationResult[0];
results.push({
fromUnixEpochMs: currentIntervalStart,
toUnixEpochMs: currentIntervalEnd,
fromUnixEpochMs: new Date(currentIntervalStart),
toUnixEpochMs: new Date(currentIntervalEnd),
averageSpotsAvailable: parseFloat(averageValue)
});
}

View File

@@ -152,8 +152,8 @@ describe.each(repositoryImplementations)('$name', (holder) => {
describe("getHistoricalAveragesOfParkingStructureCounts", () => {
it("should return empty array for non-existent structure or no data", async () => {
const options: ParkingStructureCountOptions = {
startUnixEpochMs: 1000,
endUnixEpochMs: 2000,
startUnixEpochMs: new Date(1000),
endUnixEpochMs: new Date(2000),
intervalMs: 500
};
@@ -183,8 +183,8 @@ describe.each(repositoryImplementations)('$name', (holder) => {
const now = Date.now();
const options: ParkingStructureCountOptions = {
startUnixEpochMs: now - 10000, // Look back 10 seconds
endUnixEpochMs: now + 10000, // Look forward 10 seconds
startUnixEpochMs: new Date(now - 10000), // Look back 10 seconds
endUnixEpochMs: new Date(now + 10000), // Look forward 10 seconds
intervalMs: 20000 // Single large interval
};
@@ -195,6 +195,8 @@ describe.each(repositoryImplementations)('$name', (holder) => {
if (result.length > 0) {
expect(result[0]).toHaveProperty('fromUnixEpochMs');
expect(result[0]).toHaveProperty('toUnixEpochMs');
expect(result[0].fromUnixEpochMs).toBeInstanceOf(Date);
expect(result[0].toUnixEpochMs).toBeInstanceOf(Date);
expect(result[0]).toHaveProperty('averageSpotsAvailable');
expect(result[0].averageSpotsAvailable).toBeCloseTo(52.5);
}