Skip to content

Commit 7e39769

Browse files
authored
feat: Add JSON scalar (#55)
1 parent d8474ce commit 7e39769

File tree

4 files changed

+93
-4
lines changed

4 files changed

+93
-4
lines changed

src/memdb/tables.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createColumn } from '../schema/column.js';
44
import { addCQIDsColumns } from '../schema/meta.js';
55
import { pathResolver, parentColumnResolver } from '../schema/resolvers.js';
66
import { createTable } from '../schema/table.js';
7+
import { JSONType } from '../types/json.js';
78

89
export const createTables = () => {
910
const allTables = [
@@ -12,15 +13,20 @@ export const createTables = () => {
1213
title: 'Table 1',
1314
description: 'Table 1 description',
1415
resolver: (clientMeta, parent, stream) => {
15-
stream.write({ id: 'id-1' });
16-
stream.write({ id: 'id-2' });
16+
stream.write({ id: 'id-1', json: '{ "a": 1 }' });
17+
stream.write({ id: 'id-2', json: [1, 2, 3] });
1718
return Promise.resolve();
1819
},
1920
columns: [
2021
createColumn({
2122
name: 'id',
2223
resolver: pathResolver('id'),
2324
}),
25+
createColumn({
26+
name: 'json',
27+
resolver: pathResolver('json'),
28+
type: new JSONType(),
29+
}),
2430
],
2531
}),
2632
createTable({

src/scalar/json.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { Utf8 as ArrowString } from '@apache-arrow/esnext-esm';
2+
3+
import { Scalar } from './scalar.js';
4+
import { isInvalid, NULL_VALUE } from './util.js';
5+
6+
const validate = (value: string) => {
7+
try {
8+
JSON.parse(value);
9+
return true;
10+
} catch {
11+
return false;
12+
}
13+
};
14+
15+
class JSONType implements Scalar<string> {
16+
private _valid = false;
17+
private _value = '';
18+
19+
public constructor(v?: unknown) {
20+
this.value = v;
21+
return this;
22+
}
23+
24+
public get dataType() {
25+
return new ArrowString();
26+
}
27+
28+
public get valid(): boolean {
29+
return this._valid;
30+
}
31+
32+
public get value(): string {
33+
return this._value;
34+
}
35+
36+
public set value(value: unknown) {
37+
if (isInvalid(value)) {
38+
this._valid = false;
39+
return;
40+
}
41+
42+
if (typeof value === 'string') {
43+
this._value = value;
44+
this._valid = validate(value);
45+
return;
46+
}
47+
48+
if (value instanceof Uint8Array) {
49+
this._value = new TextDecoder().decode(value);
50+
this._valid = validate(this._value);
51+
return;
52+
}
53+
54+
if (value instanceof JSONType) {
55+
this._value = value.value;
56+
this._valid = value.valid;
57+
return;
58+
}
59+
60+
try {
61+
this._value = JSON.stringify(value);
62+
this._valid = true;
63+
} catch {
64+
throw new Error(`Unable to set '${value}' as JSON`);
65+
}
66+
}
67+
68+
public toString() {
69+
if (this._valid) {
70+
return this._value;
71+
}
72+
73+
return NULL_VALUE;
74+
}
75+
}
76+
77+
export { JSONType as JSON };

src/scalar/scalar.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DataType, Precision } from '@apache-arrow/esnext-esm';
22

3+
import { JSONType } from '../types/json.js';
34
import { UUIDType } from '../types/uuid.js';
45

56
import { Bool } from './bool.js';
@@ -9,6 +10,7 @@ import { Float64 } from './float64.js';
910
import { Int16 } from './int16.js';
1011
import { Int32 } from './int32.js';
1112
import { Int64 } from './int64.js';
13+
import { JSON as JSONScalar } from './json.js';
1214
import { List } from './list.js';
1315
import { Text } from './text.js';
1416
import { Timestamp } from './timestamp.js';
@@ -93,5 +95,9 @@ export const newScalar = (dataType: DataType): Scalar<Stringable> => {
9395
return new UUID();
9496
}
9597

98+
if (dataType instanceof JSONType) {
99+
return new JSONScalar();
100+
}
101+
96102
return new Text();
97103
};

src/schema/meta.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Binary, TimeNanosecond } from '@apache-arrow/esnext-esm';
1+
import { Utf8, TimeNanosecond } from '@apache-arrow/esnext-esm';
22

33
import { UUIDType } from '../types/uuid.js';
44

@@ -45,7 +45,7 @@ export const cqSyncTimeColumn = createColumn({
4545
});
4646
export const cqSourceNameColumn = createColumn({
4747
name: '_cq_source_name',
48-
type: new Binary(),
48+
type: new Utf8(),
4949
description: 'Internal CQ row that references the source plugin name data was retrieved',
5050
ignoreInTests: true,
5151
});

0 commit comments

Comments
 (0)