-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathwrapperAdapter.ts
More file actions
101 lines (85 loc) · 3.79 KB
/
wrapperAdapter.ts
File metadata and controls
101 lines (85 loc) · 3.79 KB
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
96
97
98
99
100
101
import { toString, isString, toNumber } from '../../utils/lang';
import { sanitizeBoolean as sBoolean } from '../../evaluator/value/sanitize';
import { ILogger } from '../../logger/types';
import { SplitError } from '../../utils/lang/errors';
import { ICustomStorageWrapper } from '../types';
import { LOG_PREFIX } from './constants';
// Sanitizers return the given value if it is of the expected type, or a new sanitized one if invalid.
// @TODO review or remove sanitizers. Could be expensive and error-prone for producer methods
function sanitizeBoolean(val: any): boolean {
return sBoolean(val) || false;
}
sanitizeBoolean.type = 'boolean';
function sanitizeNumber(val: any): number {
return toNumber(val);
}
sanitizeNumber.type = 'number';
function sanitizeArrayOfStrings(val: any): string[] {
if (!Array.isArray(val)) return []; // if not an array, returns a new empty one
if (val.every(isString)) return val; // if all items are valid, return the given array
return val.filter(isString); // otherwise, return a new array filtering the invalid items
}
sanitizeArrayOfStrings.type = 'Array<string>';
function sanitizeNullableString(val: any): string | null {
if (val === null) return val;
return toString(val); // if not null, sanitize value as an string
}
sanitizeNullableString.type = 'string | null';
function sanitizeArrayOfNullableStrings(val: any): (string | null)[] {
const isStringOrNull = (v: any) => v === null || isString(v);
if (!Array.isArray(val)) return [];
if (val.every(isStringOrNull)) return val;
return val.filter(isStringOrNull); // otherwise, return a new array with items sanitized
}
sanitizeArrayOfNullableStrings.type = 'Array<string | null>';
const METHODS_TO_PROMISE_WRAP: [string, undefined | { (val: any): any, type: string }][] = [
['get', sanitizeNullableString],
['set', sanitizeBoolean],
['getAndSet', sanitizeNullableString],
['del', sanitizeBoolean],
['getKeysByPrefix', sanitizeArrayOfStrings],
['getByPrefix', sanitizeArrayOfStrings],
['incr', sanitizeBoolean],
['decr', sanitizeBoolean],
['getMany', sanitizeArrayOfNullableStrings],
['pushItems', undefined],
['popItems', sanitizeArrayOfStrings],
['getItemsCount', sanitizeNumber],
['itemContains', sanitizeBoolean],
['connect', sanitizeBoolean],
['close', undefined],
];
/**
* Adapter of the Custom Storage Wrapper.
* Used to properly handle exception and rejected promise results: logs error and wrap them into SplitErrors.
*
* @param log logger instance
* @param wrapper custom storage wrapper to adapt
* @returns an adapted version of the given storage wrapper
*/
export function wrapperAdapter(log: ILogger, wrapper: ICustomStorageWrapper): ICustomStorageWrapper {
const wrapperAdapter: Record<string, Function> = {};
METHODS_TO_PROMISE_WRAP.forEach(([method, sanitizer]) => {
// Logs error and wraps it into an SplitError object (required to handle user callback errors in SDK readiness events)
function handleError(e: any) {
log.error(`${LOG_PREFIX} Wrapper '${method}' operation threw an error. Message: ${e}`);
return Promise.reject(new SplitError(e));
}
wrapperAdapter[method] = function () {
try {
// @ts-ignore
return wrapper[method].apply(wrapper, arguments).then((value => {
if (!sanitizer) return value;
const sanitizedValue = sanitizer(value);
// if value had to be sanitized, log a warning
if (sanitizedValue !== value) log.warn(`${LOG_PREFIX} Attempted to sanitize return value [${value}] of wrapper '${method}' operation which should be of type [${sanitizer.type}]. Sanitized and processed value => [${sanitizedValue}]`);
return sanitizedValue;
})).catch(handleError);
} catch (e) {
return handleError(e);
}
};
});
// @ts-ignore
return wrapperAdapter;
}