( obj: Record<string, unknown>, path = '', )
| 14 | } |
| 15 | |
| 16 | export function toDots( |
| 17 | obj: Record<string, unknown>, |
| 18 | path = '', |
| 19 | ): Record<string, string> { |
| 20 | // Clickhouse breaks on insert if a property contains invalid surrogate pairs |
| 21 | function removeInvalidSurrogates(value: string): string { |
| 22 | const validSurrogatePairRegex = |
| 23 | /[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g; |
| 24 | return value.match(validSurrogatePairRegex)?.join('') || ''; |
| 25 | } |
| 26 | |
| 27 | return Object.entries(obj).reduce((acc, [key, value]) => { |
| 28 | if (typeof value === 'object' && value !== null) { |
| 29 | return { |
| 30 | ...acc, |
| 31 | ...toDots(value as Record<string, unknown>, `${path}${key}.`), |
| 32 | }; |
| 33 | } |
| 34 | |
| 35 | if (value === undefined || value === null || value === '') { |
| 36 | return acc; |
| 37 | } |
| 38 | |
| 39 | if (typeof value === 'string' && isMalformedJsonString(value)) { |
| 40 | // Skip it |
| 41 | return acc; |
| 42 | } |
| 43 | |
| 44 | // Fix nested json strings - but catch parse errors for malformed JSON |
| 45 | if (typeof value === 'string' && isValidJsonString(value)) { |
| 46 | try { |
| 47 | return { |
| 48 | ...acc, |
| 49 | ...toDots(JSON.parse(value), `${path}${key}.`), |
| 50 | }; |
| 51 | } catch { |
| 52 | // Skip it |
| 53 | return acc; |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | const cleanedValue = |
| 58 | typeof value === 'string' |
| 59 | ? removeInvalidSurrogates(value).trim() |
| 60 | : String(value); |
| 61 | |
| 62 | return { |
| 63 | ...acc, |
| 64 | [`${path}${key}`]: cleanedValue, |
| 65 | }; |
| 66 | }, {}); |
| 67 | } |
| 68 | |
| 69 | export function toObject( |
| 70 | obj: Record<string, string | undefined>, |
no test coverage detected