-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtransform.ts
More file actions
74 lines (65 loc) · 2.37 KB
/
transform.ts
File metadata and controls
74 lines (65 loc) · 2.37 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
import type { DataType } from '@apache-arrow/esnext-esm';
import { Field, Utf8, Int64, Float64, Bool, List } from '@apache-arrow/esnext-esm';
import { TransformError } from '../errors/errors.js';
import type { Column } from '../schema/column.js';
import { createColumn } from '../schema/column.js';
import { JSONType } from '../types/json.js';
function defaultGetTypeFromValue(key: string, value: unknown): DataType | null {
switch (typeof value) {
case 'string': {
return new Utf8();
}
case 'number': {
return value % 1 === 0 ? new Int64() : new Float64();
}
case 'boolean': {
return new Bool();
}
case 'object': {
if (Array.isArray(value)) {
if (value.length === 0) return new JSONType(); // Empty array, can't infer type
// Assuming array of same type, getting type of first element
const elementType = defaultGetTypeFromValue(key + '.element', value[0]);
if (elementType === null) return new JSONType();
const field = new Field('element', elementType); // 'element' can be any name as it's just for internal representation
return new List(field);
} else {
return new JSONType();
}
}
default: {
throw new TransformError(`Unsupported type: ${typeof value}`, { props: { value } });
}
}
}
type Options = {
skipColumns?: string[];
primaryKeys?: string[];
getTypeFromValue?: (key: string, value: unknown) => DataType | null | undefined;
overrides?: Map<string, Column>;
};
export function objectToColumns(
object: Record<string, unknown>,
{
skipColumns = [],
primaryKeys = [],
getTypeFromValue = defaultGetTypeFromValue,
overrides = new Map(),
}: Options = {},
): Column[] {
return Object.entries(object)
.filter(([key]) => !skipColumns.includes(key))
.map(([key, value]): Column | null => {
if (overrides.has(key)) {
return overrides.get(key)!;
}
let type = getTypeFromValue(key, value);
if (type === undefined && getTypeFromValue !== defaultGetTypeFromValue) {
type = defaultGetTypeFromValue(key, value);
}
if (type === null || type === undefined) return null;
const isPrimaryKey = primaryKeys.includes(key);
return createColumn({ name: key, type, primaryKey: isPrimaryKey });
})
.filter((column): column is Column => column !== null); // This is a type-guard
}