From 6cd25464474c8bbe8d64438faaa12571f805311a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksa=20Siri=C5=A1ki?= <31509435+aleksasiriski@users.noreply.github.com> Date: Wed, 1 Jan 2025 19:09:12 +0100 Subject: [PATCH] fix(stats): show all building even if empty and count per type --- .../insideCountPerBuilding.svelte | 59 ++++++++++++++++++- src/lib/server/db/person.ts | 29 ++++++--- src/lib/types/person.ts | 10 ++++ 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/src/lib/components/custom/inside_counter/insideCountPerBuilding.svelte b/src/lib/components/custom/inside_counter/insideCountPerBuilding.svelte index 2700860..422efc0 100644 --- a/src/lib/components/custom/inside_counter/insideCountPerBuilding.svelte +++ b/src/lib/components/custom/inside_counter/insideCountPerBuilding.svelte @@ -1,26 +1,79 @@ - + {#each allTypes as { type }} + + {/each} - {#each data as { building, insideCount }} + {#each buildings as { building, types }} - + {#each types as { insideCount }} + + {/each} {/each} diff --git a/src/lib/server/db/person.ts b/src/lib/server/db/person.ts index 26d0d45..175df54 100644 --- a/src/lib/server/db/person.ts +++ b/src/lib/server/db/person.ts @@ -7,7 +7,7 @@ import { isInside } from '../isInside'; import { DB as db } from './connect'; import { capitalizeString, sanitizeString } from '$lib/utils/sanitize'; import { building } from './schema/building'; -import type { PersonType } from '$lib/types/person'; +import { isPersonType, type PersonType } from '$lib/types/person'; // Gets all persons using optional filters export async function getPersons( @@ -178,6 +178,7 @@ export async function getPersons( // Gets the count of all persons that are inside, per building export async function getPersonsCountPerBuilding(): Promise< { + type: PersonType | null; building: string; insideCount: number; }[] @@ -185,27 +186,41 @@ export async function getPersonsCountPerBuilding(): Promise< try { const personInsideSubquery = db .select({ - personId: personEntry.personId, + personId: person.id, + type: person.type, entryBuilding: personEntry.building, maxEntryTimestamp: max(personEntry.timestamp), maxExitTimestamp: max(personExit.timestamp) }) - .from(personEntry) - .leftJoin(personExit, eq(personEntry.personId, personExit.personId)) - .groupBy(personEntry.personId, personEntry.building) + .from(person) + .leftJoin(personEntry, eq(personEntry.personId, person.id)) + .leftJoin(personExit, eq(personExit.personId, person.id)) + .groupBy(person.id, person.type, personEntry.building) .having(({ maxEntryTimestamp, maxExitTimestamp }) => or(isNull(maxExitTimestamp), gt(maxEntryTimestamp, maxExitTimestamp)) ) .as('person_inside'); - return await db + const persons = await db .select({ + type: personInsideSubquery.type, building: building.name, insideCount: count(personInsideSubquery.personId) }) .from(building) .leftJoin(personInsideSubquery, eq(building.name, personInsideSubquery.entryBuilding)) - .groupBy(building.name); + .groupBy(personInsideSubquery.type, building.name); + + return persons.map((p) => { + if (p.type !== null && !isPersonType(p.type)) { + throw new Error('Invalid type from DB (not PersonType)'); + } + return { + type: p.type, + building: p.building, + insideCount: p.insideCount + }; + }); } catch (err: unknown) { throw new Error( `Failed to get inside count of persons from database: ${(err as Error).message}}` diff --git a/src/lib/types/person.ts b/src/lib/types/person.ts index 83d331f..3619032 100644 --- a/src/lib/types/person.ts +++ b/src/lib/types/person.ts @@ -4,6 +4,16 @@ export type PersonType = 'Student' | 'Employee'; export const Student: PersonType = 'Student'; export const Employee: PersonType = 'Employee'; +export function isPersonType(s: string): s is PersonType { + switch (s) { + case Student: + case Employee: + return true; + default: + return false; + } +} + export type Person = { id: number; type: PersonType;
BuildingPeople{type}
{building}{insideCount}{insideCount}