diff --git a/package-lock.json b/package-lock.json index 59fac6d..7dd7cb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@apache-arrow/esnext-esm": "^12.0.1", "@cloudquery/plugin-pb-javascript": "^0.0.6", + "boolean": "^3.2.0", "yargs": "^17.7.2" }, "devDependencies": { @@ -975,6 +976,11 @@ "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", "dev": true }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" + }, "node_modules/bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", diff --git a/package.json b/package.json index 2820fbc..475de15 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "dependencies": { "@apache-arrow/esnext-esm": "^12.0.1", "@cloudquery/plugin-pb-javascript": "^0.0.6", + "boolean": "^3.2.0", "yargs": "^17.7.2" } } diff --git a/src/scalar/bool.test.ts b/src/scalar/bool.test.ts new file mode 100644 index 0000000..48047b4 --- /dev/null +++ b/src/scalar/bool.test.ts @@ -0,0 +1,35 @@ +import test from 'ava'; +import { DataType } from '@apache-arrow/esnext-esm'; +import { Bool } from './bool.js'; + +[null, undefined].forEach((v) => { + test(`should set values to false when ${v} is passed`, (t) => { + const b = new Bool(v); + t.is(b.Valid, false); + t.true(DataType.isBool(b.DataType)); + }); +}); + +[1, true, 'true', 'Y', 'y', 'TRUE', 'on', new Bool(true)].forEach((v, i) => { + test(`should support truthy value '${v}' (${i})`, (t) => { + const b = new Bool(v); + t.is(b.Valid, true); + t.is(b.Value, true); + t.true(DataType.isBool(b.DataType)); + t.is(b.toString(), 'true'); + }); +}); + +[0, false, 'false', 'N', 'n', 'FALSE', 'off', new Bool(false)].forEach((v, i) => { + test(`should support falsy value '${v}' (${i})`, (t) => { + const b = new Bool(v); + t.is(b.Valid, true); + t.is(b.Value, false); + t.true(DataType.isBool(b.DataType)); + t.is(b.toString(), 'false'); + }); +}); + +test('should throw when unable to set value', (t) => { + t.throws(() => new Bool({ value: {} }), { message: "Unable to set '[object Object]' as Bool" }); +}); diff --git a/src/scalar/bool.ts b/src/scalar/bool.ts new file mode 100644 index 0000000..e33972a --- /dev/null +++ b/src/scalar/bool.ts @@ -0,0 +1,54 @@ +import { Bool as ArrowBool } from '@apache-arrow/esnext-esm'; +import { boolean, isBooleanable } from 'boolean'; +import { isInvalid, NULL_VALUE } from './util.js'; + +export class Bool { + private _valid = false; + private _value = false; + + public constructor(v: unknown) { + this.Valid = v; + return this; + } + + public get DataType() { + return new ArrowBool(); + } + + public get Valid(): boolean { + return this._valid; + } + + public get Value(): boolean { + return this._value; + } + + public set Valid(value: unknown) { + if (isInvalid(value)) { + this._valid = false; + return; + } + + if (value instanceof Bool) { + this._valid = value.Valid; + this._value = value.Value; + return; + } + + if (isBooleanable(value)) { + this._value = boolean(value); + this._valid = true; + return; + } + + throw new Error(`Unable to set '${value}' as Bool`); + } + + public toString() { + if (this._valid) { + return String(this._value); + } + + return NULL_VALUE; + } +} diff --git a/src/scalar/util.ts b/src/scalar/util.ts new file mode 100644 index 0000000..12b7522 --- /dev/null +++ b/src/scalar/util.ts @@ -0,0 +1,3 @@ +export const NULL_VALUE = '(null)'; + +export const isInvalid = (value: unknown) => value === null || value === undefined;