Picsur/backend/src/collections/preference-db/preference-common.service.ts

119 lines
3 KiB
TypeScript
Raw Normal View History

2022-04-13 14:33:07 +00:00
import { Injectable, Logger } from '@nestjs/common';
import {
2022-06-05 10:20:16 +00:00
DecodedPref,
PrefValueType,
2022-09-06 14:32:16 +00:00
PrefValueTypeStrings,
2022-04-13 14:33:07 +00:00
} from 'picsur-shared/dist/dto/preferences.dto';
import {
AsyncFailable,
Fail,
Failable,
2022-07-04 15:11:42 +00:00
FT,
2022-09-06 14:32:16 +00:00
HasFailed,
2022-04-13 14:33:07 +00:00
} from 'picsur-shared/dist/types';
type Enum = Record<string, string>;
type EnumValue<E> = E[keyof E];
type PrefValueTypeType<E extends Enum> = {
[key in EnumValue<E>]: PrefValueTypeStrings;
};
2022-06-27 15:16:42 +00:00
type EncodedPref = {
2022-04-13 14:33:07 +00:00
key: string;
value: string;
};
@Injectable()
export class PreferenceCommonService {
2022-09-02 15:18:22 +00:00
private readonly logger = new Logger(PreferenceCommonService.name);
2022-04-13 14:33:07 +00:00
2022-06-27 15:16:42 +00:00
// Preferences values are only validated upon encoding, not decoding
// The preference keys are always validated
// E is either the SysPreference or the UsrPreference enum
// the pref value types is the object containing the type of each key in E
public DecodePref<E extends Enum>(
preference: EncodedPref,
2022-04-13 14:33:07 +00:00
prefType: E,
prefValueTypes: PrefValueTypeType<E>,
): Failable<DecodedPref> {
const key = this.validatePrefKey(preference.key, prefType);
if (HasFailed(key)) return key;
const type = prefValueTypes[key];
switch (type) {
case 'string':
return {
key: preference.key,
value: preference.value,
type: 'string',
};
case 'number':
return {
key: preference.key,
value: parseInt(preference.value, 10),
type: 'number',
};
case 'boolean':
return {
key: preference.key,
2022-08-26 18:40:16 +00:00
value: preference.value === 'true',
2022-04-13 14:33:07 +00:00
type: 'boolean',
};
}
2022-07-04 15:11:42 +00:00
return Fail(FT.UsrValidation, 'Invalid preference value');
2022-04-13 14:33:07 +00:00
}
2022-06-27 15:16:42 +00:00
public async EncodePref<E extends Enum>(
2022-04-13 14:33:07 +00:00
key: string,
value: PrefValueType,
prefType: E,
prefValueTypes: PrefValueTypeType<E>,
2022-06-27 15:16:42 +00:00
): AsyncFailable<EncodedPref> {
2022-04-13 14:33:07 +00:00
const validatedKey = this.validatePrefKey(key, prefType);
if (HasFailed(validatedKey)) return validatedKey;
const valueType = prefValueTypes[validatedKey];
2022-06-27 15:16:42 +00:00
const validatedValue = this.encodePrefValue(value, valueType);
2022-04-13 14:33:07 +00:00
if (HasFailed(validatedValue)) return validatedValue;
return {
key: validatedKey,
value: validatedValue,
};
}
public validatePrefKey<E extends Enum, V extends EnumValue<E>>(
key: string,
prefType: E,
): Failable<V> {
const keysList = Object.values(prefType);
if (!keysList.includes(key)) {
2022-07-04 15:11:42 +00:00
return Fail(FT.UsrValidation, 'Invalid preference key');
2022-04-13 14:33:07 +00:00
}
return key as V;
}
2022-06-27 15:16:42 +00:00
public encodePrefValue(
2022-04-13 14:33:07 +00:00
value: PrefValueType,
expectedType: PrefValueTypeStrings,
): Failable<string> {
const type = typeof value;
2022-08-26 18:40:16 +00:00
if (type !== expectedType) {
2022-07-04 15:11:42 +00:00
return Fail(FT.UsrValidation, 'Invalid preference value');
2022-04-13 14:33:07 +00:00
}
switch (type) {
case 'string':
return value as string;
case 'number':
return value.toString();
case 'boolean':
return value ? 'true' : 'false';
}
2022-07-04 15:11:42 +00:00
return Fail(FT.UsrValidation, 'Invalid preference value');
2022-04-13 14:33:07 +00:00
}
}