-
Notifications
You must be signed in to change notification settings - Fork 4
/
serializers.ts
95 lines (83 loc) · 3.04 KB
/
serializers.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
export interface Serializer<V> {
readonly deserialize: (value: string | null) => V | undefined | null
readonly serialize: (value?: V) => string | undefined | null
}
const join = (value: readonly unknown[], separator: string) =>
value.join(separator)
const split = (value: string | null, separator: string) =>
value?.split(separator).filter((str) => str.trim() !== '') || []
const intSerializer: Serializer<number> = {
deserialize: (value: string | null): number | null => {
if (value === null) {
return value
}
const num = parseInt(value, 10)
return Number.isNaN(num) ? null : num
},
serialize: (value?: number): string => String(value),
}
const floatSerializer: Serializer<number> = {
deserialize: (value: string | null): number | null => {
if (value === null) {
return value
}
const num = parseFloat(value)
return Number.isNaN(num) ? null : num
},
serialize: (value?: number): string => String(value),
}
const stringSerializer: Serializer<string> = {
deserialize: (value: string | null): string | null =>
value === null ? null : String(value),
serialize: (value?: string): string => String(value),
}
export const arrayStringSerializer: (
separator: string
) => Serializer<readonly string[]> = (separator: string) => ({
deserialize: (value: string | null): readonly string[] | null =>
split(value, separator),
serialize: (value?: readonly string[]): string | null =>
value ? join(value, separator) : null,
})
export const arrayIntSerializer: (
separator: string
) => Serializer<readonly number[]> = (separator: string) => ({
deserialize: (value: string | null): readonly number[] | null =>
split(value, separator).map(intSerializer.deserialize) as readonly number[],
serialize: (value?: readonly number[]): string | null =>
value ? join(value, separator) : null,
})
export const arrayFloatSerializer: (
separator: string
) => Serializer<readonly number[]> = (separator: string) => ({
deserialize: (value: string | null): readonly number[] | null =>
split(value, separator).map(
floatSerializer.deserialize
) as readonly number[],
serialize: (value?: readonly number[]): string | null =>
value ? join(value, separator) : null,
})
const dateSerializer = (
locale: string = 'en-us',
timeZone: string = 'UTC'
): Serializer<Date> => ({
deserialize: (value: string | null): Date =>
value ? new Date(value) : new Date(),
serialize: (value?: Date): string | undefined =>
value?.toLocaleDateString(locale, { timeZone }),
})
const booleanSerializer: Serializer<boolean> = {
deserialize: (value: string | null): boolean => value === '1',
serialize: (value?: boolean): string => (value ? '1' : '0'),
}
export const DEFAULT_SEPARATOR = '_'
export const serializers = {
arrayFloat: arrayFloatSerializer(DEFAULT_SEPARATOR),
arrayInt: arrayIntSerializer(DEFAULT_SEPARATOR),
arrayString: arrayStringSerializer(DEFAULT_SEPARATOR),
boolean: booleanSerializer,
date: dateSerializer,
float: floatSerializer,
int: intSerializer,
string: stringSerializer,
}