More typesafe NodeSortField definition.

This commit is contained in:
baldo 2022-08-23 21:01:58 +02:00
parent 91690509d3
commit 66fb4e5004
4 changed files with 45 additions and 17 deletions

View file

@ -18,6 +18,7 @@ import { forConstraint } from "../shared/validation/validator";
import {
Domain,
DurationSeconds,
filterUndefinedFromJSON,
Hostname,
isBoolean,
isDomain,
@ -438,7 +439,7 @@ async function sendMonitoringMailsBatched(
node.nickname + " <" + node.email + ">",
mailType,
{
node: node,
node: filterUndefinedFromJSON(node),
lastSeen: nodeState.last_seen,
disableUrl: monitoringDisableUrl(monitoringToken),
}

View file

@ -19,6 +19,7 @@ import {
CreateOrUpdateNode,
EmailAddress,
FastdKey,
filterUndefinedFromJSON,
Hostname,
isFastdKey,
isHostname,
@ -504,7 +505,7 @@ async function sendMonitoringConfirmationMail(
node.nickname + " <" + node.email + ">",
MailType.MONITORING_CONFIRMATION,
{
node: node,
node: filterUndefinedFromJSON(node),
confirmUrl: confirmUrl,
disableUrl: disableUrl,
}

View file

@ -11,6 +11,19 @@ export function parseJSON(str: string): JSONValue {
return json;
}
export function filterUndefinedFromJSON(obj: {
[key: string]: JSONValue | undefined;
}): JSONObject {
const result: JSONObject = {};
for (const [key, value] of Object.entries(obj)) {
if (value !== undefined) {
result[key] = value;
}
}
return result;
}
export type JSONValue =
| null
| string
@ -403,8 +416,8 @@ export type BaseNode = {
nickname: Nickname;
email: EmailAddress;
hostname: Hostname;
coords?: Coordinates;
key?: FastdKey;
coords: Coordinates | undefined;
key: FastdKey | undefined;
mac: MAC;
};
@ -506,11 +519,10 @@ export const isDomain = toIsNewtype(isString, "" as Domain);
/**
* Represents a node in the context of a Freifunk site and domain.
*/
export type DomainSpecificNodeResponse = Record<NodeSortField, any> &
NodeResponse & {
site?: Site;
domain?: Domain;
onlineState?: OnlineState;
export type DomainSpecificNodeResponse = NodeResponse & {
site: Site | undefined;
domain: Domain | undefined;
onlineState: OnlineState | undefined;
};
export function isDomainSpecificNodeResponse(
@ -549,7 +561,8 @@ export function isMonitoringResponse(arg: unknown): arg is MonitoringResponse {
);
}
export enum NodeSortField {
// noinspection JSUnusedGlobalSymbols
enum NodeSortFieldEnum {
HOSTNAME = "hostname",
NICKNAME = "nickname",
EMAIL = "email",
@ -563,7 +576,17 @@ export enum NodeSortField {
MONITORING_STATE = "monitoringState",
}
export const isNodeSortField = toIsEnum(NodeSortField);
export type NodeSortField = keyof Pick<
DomainSpecificNodeResponse,
NodeSortFieldEnum
>;
export function isNodeSortField(arg: unknown): arg is NodeSortField {
if (!isString(arg)) {
return false;
}
return Object.values(NodeSortFieldEnum).includes(arg as NodeSortField);
}
export type NodesFilter = {
hasKey?: boolean;

View file

@ -286,12 +286,15 @@ export function filter<E>(
);
}
export function sort<T extends Record<S, unknown>, S extends string>(
entities: T[],
isSortField: TypeGuard<S>,
export function sort<
Type extends { [Key in SortField]: unknown },
SortField extends string
>(
entities: Type[],
isSortField: TypeGuard<SortField>,
restParams: RestParams
): T[] {
const sortField: S | undefined = isSortField(restParams._sortField)
): Type[] {
const sortField: SortField | undefined = isSortField(restParams._sortField)
? restParams._sortField
: undefined;
if (!sortField) {