mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-19 08:50:29 +00:00
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:
@@ -9,7 +9,7 @@ export interface IParkingStructure extends IEntityWithTimestamp, IEntityWithId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IParkingStructureTimestampRecord {
|
export interface IParkingStructureTimestampRecord {
|
||||||
timestampMs: number;
|
timestampMs: Date;
|
||||||
id: string;
|
id: string;
|
||||||
spotsAvailable: number;
|
spotsAvailable: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export interface NotificationAlertArguments {
|
|||||||
|
|
||||||
export class AppleNotificationSender {
|
export class AppleNotificationSender {
|
||||||
private apnsToken: string | undefined = undefined;
|
private apnsToken: string | undefined = undefined;
|
||||||
private _lastRefreshedTimeMs: number | undefined = undefined;
|
private _lastRefreshedTimeMs: Date | undefined = undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private shouldActuallySendNotifications = true,
|
private shouldActuallySendNotifications = true,
|
||||||
@@ -34,13 +34,13 @@ export class AppleNotificationSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get lastRefreshedTimeMs(): number | undefined {
|
get lastRefreshedTimeMs(): Date | undefined {
|
||||||
return this._lastRefreshedTimeMs;
|
return this._lastRefreshedTimeMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private lastReloadedTimeForAPNsIsTooRecent() {
|
private lastReloadedTimeForAPNsIsTooRecent() {
|
||||||
const thirtyMinutesMs = 1800000;
|
const thirtyMinutesMs = 1800000;
|
||||||
return this._lastRefreshedTimeMs && Date.now() - this._lastRefreshedTimeMs < thirtyMinutesMs;
|
return this._lastRefreshedTimeMs && Date.now() - this._lastRefreshedTimeMs.getTime() < thirtyMinutesMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public reloadAPNsTokenIfTimePassed() {
|
public reloadAPNsTokenIfTimePassed() {
|
||||||
@@ -70,7 +70,7 @@ export class AppleNotificationSender {
|
|||||||
algorithm: "ES256",
|
algorithm: "ES256",
|
||||||
header: tokenHeader
|
header: tokenHeader
|
||||||
});
|
});
|
||||||
this._lastRefreshedTimeMs = nowMs;
|
this._lastRefreshedTimeMs = new Date(nowMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
|
|||||||
private createTimestampRecord = (structure: IParkingStructure, timestampMs: number): IParkingStructureTimestampRecord => ({
|
private createTimestampRecord = (structure: IParkingStructure, timestampMs: number): IParkingStructureTimestampRecord => ({
|
||||||
id: structure.id,
|
id: structure.id,
|
||||||
spotsAvailable: structure.spotsAvailable,
|
spotsAvailable: structure.spotsAvailable,
|
||||||
timestampMs,
|
timestampMs: new Date(timestampMs),
|
||||||
});
|
});
|
||||||
|
|
||||||
private ensureHistoricalDataExists = (structureId: string): void => {
|
private ensureHistoricalDataExists = (structureId: string): void => {
|
||||||
@@ -90,7 +90,7 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
|
|||||||
};
|
};
|
||||||
|
|
||||||
private addRecordToHistoricalData = (structureId: string, record: IParkingStructureTimestampRecord): void => {
|
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);
|
this.historicalData.get(structureId)?.appendWithSorting(record, sortingCallback);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,10 +112,11 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
|
|||||||
const results: HistoricalParkingAverageQueryResult[] = [];
|
const results: HistoricalParkingAverageQueryResult[] = [];
|
||||||
const { startUnixEpochMs, endUnixEpochMs, intervalMs } = options;
|
const { startUnixEpochMs, endUnixEpochMs, intervalMs } = options;
|
||||||
|
|
||||||
let currentIntervalStart = startUnixEpochMs;
|
let currentIntervalStart = startUnixEpochMs.getTime();
|
||||||
|
const endTime = endUnixEpochMs.getTime();
|
||||||
|
|
||||||
while (currentIntervalStart < endUnixEpochMs) {
|
while (currentIntervalStart < endTime) {
|
||||||
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endUnixEpochMs);
|
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endTime);
|
||||||
const recordsInInterval = this.getRecordsInTimeRange(records, currentIntervalStart, currentIntervalEnd);
|
const recordsInInterval = this.getRecordsInTimeRange(records, currentIntervalStart, currentIntervalEnd);
|
||||||
|
|
||||||
if (recordsInInterval.length > 0) {
|
if (recordsInInterval.length > 0) {
|
||||||
@@ -135,7 +136,7 @@ export class InMemoryParkingRepository implements ParkingGetterSetterRepository
|
|||||||
endMs: number
|
endMs: number
|
||||||
): IParkingStructureTimestampRecord[] => {
|
): IParkingStructureTimestampRecord[] => {
|
||||||
return records.filter(record =>
|
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;
|
const averageSpotsAvailable = totalSpotsAvailable / records.length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fromUnixEpochMs: fromMs,
|
fromUnixEpochMs: new Date(fromMs),
|
||||||
toUnixEpochMs: toMs,
|
toUnixEpochMs: new Date(toMs),
|
||||||
averageSpotsAvailable
|
averageSpotsAvailable
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { IParkingStructure } from "../../entities/ParkingRepositoryEntities";
|
import { IParkingStructure } from "../../entities/ParkingRepositoryEntities";
|
||||||
|
|
||||||
export interface ParkingStructureCountOptions {
|
export interface ParkingStructureCountOptions {
|
||||||
startUnixEpochMs: number;
|
startUnixEpochMs: Date;
|
||||||
endUnixEpochMs: number;
|
endUnixEpochMs: Date;
|
||||||
intervalMs: number;
|
intervalMs: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HistoricalParkingAverageQueryResult {
|
export interface HistoricalParkingAverageQueryResult {
|
||||||
fromUnixEpochMs: number;
|
fromUnixEpochMs: Date;
|
||||||
toUnixEpochMs: number;
|
toUnixEpochMs: Date;
|
||||||
averageSpotsAvailable: number;
|
averageSpotsAvailable: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -163,10 +163,11 @@ export class RedisParkingRepository extends BaseRedisRepository implements Parki
|
|||||||
const { startUnixEpochMs, endUnixEpochMs, intervalMs } = options;
|
const { startUnixEpochMs, endUnixEpochMs, intervalMs } = options;
|
||||||
const results: HistoricalParkingAverageQueryResult[] = [];
|
const results: HistoricalParkingAverageQueryResult[] = [];
|
||||||
|
|
||||||
let currentIntervalStart = startUnixEpochMs;
|
let currentIntervalStart = startUnixEpochMs.getTime();
|
||||||
|
const endTime = endUnixEpochMs.getTime();
|
||||||
|
|
||||||
while (currentIntervalStart < endUnixEpochMs) {
|
while (currentIntervalStart < endTime) {
|
||||||
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endUnixEpochMs);
|
const currentIntervalEnd = Math.min(currentIntervalStart + intervalMs, endTime);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const aggregationResult = await this.redisClient.sendCommand([
|
const aggregationResult = await this.redisClient.sendCommand([
|
||||||
@@ -182,8 +183,8 @@ export class RedisParkingRepository extends BaseRedisRepository implements Parki
|
|||||||
if (aggregationResult && aggregationResult.length > 0) {
|
if (aggregationResult && aggregationResult.length > 0) {
|
||||||
const [, averageValue] = aggregationResult[0];
|
const [, averageValue] = aggregationResult[0];
|
||||||
results.push({
|
results.push({
|
||||||
fromUnixEpochMs: currentIntervalStart,
|
fromUnixEpochMs: new Date(currentIntervalStart),
|
||||||
toUnixEpochMs: currentIntervalEnd,
|
toUnixEpochMs: new Date(currentIntervalEnd),
|
||||||
averageSpotsAvailable: parseFloat(averageValue)
|
averageSpotsAvailable: parseFloat(averageValue)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ describe.each(repositoryImplementations)('$name', (holder) => {
|
|||||||
describe("getHistoricalAveragesOfParkingStructureCounts", () => {
|
describe("getHistoricalAveragesOfParkingStructureCounts", () => {
|
||||||
it("should return empty array for non-existent structure or no data", async () => {
|
it("should return empty array for non-existent structure or no data", async () => {
|
||||||
const options: ParkingStructureCountOptions = {
|
const options: ParkingStructureCountOptions = {
|
||||||
startUnixEpochMs: 1000,
|
startUnixEpochMs: new Date(1000),
|
||||||
endUnixEpochMs: 2000,
|
endUnixEpochMs: new Date(2000),
|
||||||
intervalMs: 500
|
intervalMs: 500
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -183,8 +183,8 @@ describe.each(repositoryImplementations)('$name', (holder) => {
|
|||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const options: ParkingStructureCountOptions = {
|
const options: ParkingStructureCountOptions = {
|
||||||
startUnixEpochMs: now - 10000, // Look back 10 seconds
|
startUnixEpochMs: new Date(now - 10000), // Look back 10 seconds
|
||||||
endUnixEpochMs: now + 10000, // Look forward 10 seconds
|
endUnixEpochMs: new Date(now + 10000), // Look forward 10 seconds
|
||||||
intervalMs: 20000 // Single large interval
|
intervalMs: 20000 // Single large interval
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,6 +195,8 @@ describe.each(repositoryImplementations)('$name', (holder) => {
|
|||||||
if (result.length > 0) {
|
if (result.length > 0) {
|
||||||
expect(result[0]).toHaveProperty('fromUnixEpochMs');
|
expect(result[0]).toHaveProperty('fromUnixEpochMs');
|
||||||
expect(result[0]).toHaveProperty('toUnixEpochMs');
|
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]).toHaveProperty('averageSpotsAvailable');
|
||||||
expect(result[0].averageSpotsAvailable).toBeCloseTo(52.5);
|
expect(result[0].averageSpotsAvailable).toBeCloseTo(52.5);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user