This is an automated email from the ASF dual-hosted git repository.

domoritz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 5c0fa712fa GH-39435: [JS] Add Vector.nullable (#39436)
5c0fa712fa is described below

commit 5c0fa712faec0b2997b5970890c076011f96de77
Author: Dominik Moritz <[email protected]>
AuthorDate: Thu Jan 4 03:12:04 2024 +0200

    GH-39435: [JS] Add Vector.nullable (#39436)
---
 js/src/table.ts             |  2 +-
 js/src/util/chunk.ts        |  5 +++++
 js/src/vector.ts            |  8 ++++++++
 js/test/unit/table-tests.ts | 18 ++++++++++--------
 4 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/js/src/table.ts b/js/src/table.ts
index 00f4a4cfe0..e719b7ca9d 100644
--- a/js/src/table.ts
+++ b/js/src/table.ts
@@ -114,7 +114,7 @@ export class Table<T extends TypeMap = any> {
                 } else if (typeof x === 'object') {
                     const keys = Object.keys(x) as (keyof T)[];
                     const vecs = keys.map((k) => new Vector([x[k]]));
-                    const batchSchema = schema ?? new Schema(keys.map((k, i) 
=> new Field(String(k), vecs[i].type, vecs[i].nullCount > 0)));
+                    const batchSchema = schema ?? new Schema(keys.map((k, i) 
=> new Field(String(k), vecs[i].type, vecs[i].nullable)));
                     const [, batches] = 
distributeVectorsIntoRecordBatches(batchSchema, vecs);
                     return batches.length === 0 ? [new RecordBatch(x)] : 
batches;
                 }
diff --git a/js/src/util/chunk.ts b/js/src/util/chunk.ts
index 6098b04243..36620627f1 100644
--- a/js/src/util/chunk.ts
+++ b/js/src/util/chunk.ts
@@ -51,6 +51,11 @@ export class ChunkedIterator<T extends DataType> implements 
IterableIterator<T['
     }
 }
 
+/** @ignore */
+export function computeChunkNullable<T extends DataType>(chunks: 
ReadonlyArray<Data<T>>) {
+    return chunks.some(chunk => chunk.nullable);
+}
+
 /** @ignore */
 export function computeChunkNullCounts<T extends DataType>(chunks: 
ReadonlyArray<Data<T>>) {
     return chunks.reduce((nullCount, chunk) => nullCount + chunk.nullCount, 0);
diff --git a/js/src/vector.ts b/js/src/vector.ts
index 7e1caa3435..8b94b14e3f 100644
--- a/js/src/vector.ts
+++ b/js/src/vector.ts
@@ -24,6 +24,7 @@ import { BigIntArray, TypedArray, TypedArrayDataType } from 
'./interfaces.js';
 import {
     isChunkedValid,
     computeChunkOffsets,
+    computeChunkNullable,
     computeChunkNullCounts,
     sliceChunks,
     wrapChunkedCall1,
@@ -132,6 +133,13 @@ export class Vector<T extends DataType = any> {
         return this.data.reduce((byteLength, data) => byteLength + 
data.byteLength, 0);
     }
 
+    /**
+     * Whether this Vector's elements can contain null values.
+     */
+    public get nullable() {
+        return computeChunkNullable(this.data);
+    }
+
     /**
      * The number of null elements in this Vector.
      */
diff --git a/js/test/unit/table-tests.ts b/js/test/unit/table-tests.ts
index 094988c052..ffda47f473 100644
--- a/js/test/unit/table-tests.ts
+++ b/js/test/unit/table-tests.ts
@@ -139,30 +139,32 @@ describe(`Table`, () => {
             const i32 = makeVector([i32s]);
             expect(i32).toHaveLength(i32s.length);
             expect(i32.nullCount).toBe(0);
+            expect(i32.nullable).toBe(true);
 
             const table = new Table({ i32 });
             const i32Field = table.schema.fields[0];
 
             expect(i32Field.name).toBe('i32');
             expect(i32).toHaveLength(i32s.length);
-            expect(i32Field.nullable).toBe(false);
+            expect(i32Field.nullable).toBe(true);
             expect(i32.nullCount).toBe(0);
 
             expect(i32).toEqualVector(makeVector(i32s));
         });
 
-        test(`creates a new Table from a Typed Array and force nullable`, () 
=> {
+        test(`creates a new Table from a Typed Array and force not nullable`, 
() => {
             const i32s = new Int32Array(arange(new Array<number>(10)));
             const i32 = makeVector([i32s]);
             expect(i32).toHaveLength(i32s.length);
             expect(i32.nullCount).toBe(0);
+            expect(i32.nullable).toBe(true);
 
-            const table = new Table(new Schema([new Field('i32', new Int32, 
true)]), { i32 });
+            const table = new Table(new Schema([new Field('i32', new Int32, 
false)]), { i32 });
             const i32Field = table.schema.fields[0];
 
             expect(i32Field.name).toBe('i32');
             expect(i32).toHaveLength(i32s.length);
-            expect(i32Field.nullable).toBe(true);
+            expect(i32Field.nullable).toBe(false);
             expect(i32.nullCount).toBe(0);
 
             expect(i32).toEqualVector(makeVector(i32s));
@@ -187,8 +189,8 @@ describe(`Table`, () => {
             expect(f32Field.name).toBe('f32');
             expect(i32).toHaveLength(i32s.length);
             expect(f32).toHaveLength(f32s.length);
-            expect(i32Field.nullable).toBe(false);
-            expect(f32Field.nullable).toBe(false);
+            expect(i32Field.nullable).toBe(true);
+            expect(f32Field.nullable).toBe(true);
             expect(i32.nullCount).toBe(0);
             expect(f32.nullCount).toBe(0);
 
@@ -222,7 +224,7 @@ describe(`Table`, () => {
 
             expect(i32Vector).toHaveLength(i32s.length);
             expect(f32Vector).toHaveLength(i32s.length); // new length should 
be the same as the longest sibling
-            expect(i32Field.nullable).toBe(false);
+            expect(i32Field.nullable).toBe(true);
             expect(f32Field.nullable).toBe(true); // true, with 12 additional 
nulls
             expect(i32Vector.nullCount).toBe(0);
             expect(f32Vector.nullCount).toBe(i32s.length - f32s.length);
@@ -264,7 +266,7 @@ describe(`Table`, () => {
             expect(f32RenamedField.name).toBe('f32Renamed');
             expect(i32Renamed).toHaveLength(i32s.length);
             expect(f32Renamed).toHaveLength(i32s.length); // new length should 
be the same as the longest sibling
-            expect(i32RenamedField.nullable).toBe(false);
+            expect(i32RenamedField.nullable).toBe(true);
             expect(f32RenamedField.nullable).toBe(true); // true, with 4 
additional nulls
             expect(i32Renamed.nullCount).toBe(0);
             expect(f32Renamed.nullCount).toBe(i32s.length - f32s.length);

Reply via email to