Skip to content

Commit

Permalink
feat: Add JSON scalar (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
erezrokah committed Aug 11, 2023
1 parent d8474ce commit 7e39769
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
10 changes: 8 additions & 2 deletions src/memdb/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createColumn } from '../schema/column.js';
import { addCQIDsColumns } from '../schema/meta.js';
import { pathResolver, parentColumnResolver } from '../schema/resolvers.js';
import { createTable } from '../schema/table.js';
import { JSONType } from '../types/json.js';

export const createTables = () => {
const allTables = [
Expand All @@ -12,15 +13,20 @@ export const createTables = () => {
title: 'Table 1',
description: 'Table 1 description',
resolver: (clientMeta, parent, stream) => {
stream.write({ id: 'id-1' });
stream.write({ id: 'id-2' });
stream.write({ id: 'id-1', json: '{ "a": 1 }' });
stream.write({ id: 'id-2', json: [1, 2, 3] });
return Promise.resolve();
},
columns: [
createColumn({
name: 'id',
resolver: pathResolver('id'),
}),
createColumn({
name: 'json',
resolver: pathResolver('json'),
type: new JSONType(),
}),
],
}),
createTable({
Expand Down
77 changes: 77 additions & 0 deletions src/scalar/json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Utf8 as ArrowString } from '@apache-arrow/esnext-esm';

import { Scalar } from './scalar.js';
import { isInvalid, NULL_VALUE } from './util.js';

const validate = (value: string) => {
try {
JSON.parse(value);
return true;
} catch {
return false;
}
};

class JSONType implements Scalar<string> {
private _valid = false;
private _value = '';

public constructor(v?: unknown) {
this.value = v;
return this;
}

public get dataType() {
return new ArrowString();
}

public get valid(): boolean {
return this._valid;
}

public get value(): string {
return this._value;
}

public set value(value: unknown) {
if (isInvalid(value)) {
this._valid = false;
return;
}

if (typeof value === 'string') {
this._value = value;
this._valid = validate(value);
return;
}

if (value instanceof Uint8Array) {
this._value = new TextDecoder().decode(value);
this._valid = validate(this._value);
return;
}

if (value instanceof JSONType) {
this._value = value.value;
this._valid = value.valid;
return;
}

try {
this._value = JSON.stringify(value);
this._valid = true;
} catch {
throw new Error(`Unable to set '${value}' as JSON`);
}
}

public toString() {
if (this._valid) {
return this._value;
}

return NULL_VALUE;
}
}

export { JSONType as JSON };
6 changes: 6 additions & 0 deletions src/scalar/scalar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DataType, Precision } from '@apache-arrow/esnext-esm';

import { JSONType } from '../types/json.js';
import { UUIDType } from '../types/uuid.js';

import { Bool } from './bool.js';
Expand All @@ -9,6 +10,7 @@ import { Float64 } from './float64.js';
import { Int16 } from './int16.js';
import { Int32 } from './int32.js';
import { Int64 } from './int64.js';
import { JSON as JSONScalar } from './json.js';
import { List } from './list.js';
import { Text } from './text.js';
import { Timestamp } from './timestamp.js';
Expand Down Expand Up @@ -93,5 +95,9 @@ export const newScalar = (dataType: DataType): Scalar<Stringable> => {
return new UUID();
}

if (dataType instanceof JSONType) {
return new JSONScalar();
}

return new Text();
};
4 changes: 2 additions & 2 deletions src/schema/meta.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Binary, TimeNanosecond } from '@apache-arrow/esnext-esm';
import { Utf8, TimeNanosecond } from '@apache-arrow/esnext-esm';

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

Expand Down Expand Up @@ -45,7 +45,7 @@ export const cqSyncTimeColumn = createColumn({
});
export const cqSourceNameColumn = createColumn({
name: '_cq_source_name',
type: new Binary(),
type: new Utf8(),
description: 'Internal CQ row that references the source plugin name data was retrieved',
ignoreInTests: true,
});
Expand Down

0 comments on commit 7e39769

Please sign in to comment.