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

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


The following commit(s) were added to refs/heads/master by this push:
     new eedf69540b ARROW-16209: [JS] Support setting arbitrary symbols on 
Tables
eedf69540b is described below

commit eedf69540b6ac5ae6555dcffbf0d3320b4b7a89c
Author: Dominik Moritz <[email protected]>
AuthorDate: Mon Apr 18 21:13:33 2022 -0400

    ARROW-16209: [JS] Support setting arbitrary symbols on Tables
    
    Fixes https://github.com/vega/vega-lite/issues/8105
    
    Similar to https://github.com/apache/arrow/pull/12906 but only allows 
symbols and only allows them on structs.
    
    Closes #12907 from domoritz/dom/set-symbol
    
    Authored-by: Dominik Moritz <[email protected]>
    Signed-off-by: Dominik Moritz <[email protected]>
---
 js/src/Arrow.dom.ts              |  2 +-
 js/src/Arrow.ts                  |  1 +
 js/src/builder/struct.ts         |  8 +++----
 js/src/row/struct.ts             |  4 +++-
 js/src/visitor/get.ts            |  4 ++--
 js/test/unit/row/struct-tests.ts | 49 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/js/src/Arrow.dom.ts b/js/src/Arrow.dom.ts
index 75efb3d22b..d2c44cfe44 100644
--- a/js/src/Arrow.dom.ts
+++ b/js/src/Arrow.dom.ts
@@ -34,7 +34,7 @@ RecordBatchFileWriter['throughDOM'] = 
recordBatchWriterThroughDOMStream;
 RecordBatchStreamWriter['throughDOM'] = recordBatchWriterThroughDOMStream;
 
 export type {
-    TypeMap,
+    TypeMap, StructRowProxy,
     ReadableSource, WritableSink,
     ArrowJSONLike, FileHandle, Readable, Writable, ReadableWritable, 
ReadableDOMStreamOptions,
 } from './Arrow.js';
diff --git a/js/src/Arrow.ts b/js/src/Arrow.ts
index bf87ed6177..4f41ede107 100644
--- a/js/src/Arrow.ts
+++ b/js/src/Arrow.ts
@@ -59,6 +59,7 @@ export { Schema, Field } from './schema.js';
 
 export { MapRow } from './row/map.js';
 export { StructRow } from './row/struct.js';
+export type { StructRowProxy } from './row/struct.js';
 
 export { Builder } from './builder.js';
 export { makeBuilder, vectorFromArray, builderThroughIterable, 
builderThroughAsyncIterable } from './factories.js';
diff --git a/js/src/builder/struct.ts b/js/src/builder/struct.ts
index c645efdeae..e1beb3d380 100644
--- a/js/src/builder/struct.ts
+++ b/js/src/builder/struct.ts
@@ -24,11 +24,11 @@ import { Struct, TypeMap } from '../type.js';
 /** @ignore */
 export class StructBuilder<T extends TypeMap = any, TNull = any> extends 
Builder<Struct<T>, TNull> {
     public setValue(index: number, value: Struct<T>['TValue']) {
-        const children = this.children;
+        const { children, type } = this;
         switch (Array.isArray(value) || value.constructor) {
-            case true: return this.type.children.forEach((_, i) => 
children[i].set(index, value[i]));
-            case Map: return this.type.children.forEach((f, i) => 
children[i].set(index, value.get(f.name)));
-            default: return this.type.children.forEach((f, i) => 
children[i].set(index, value[f.name]));
+            case true: return type.children.forEach((_, i) => 
children[i].set(index, value[i]));
+            case Map: return type.children.forEach((f, i) => 
children[i].set(index, value.get(f.name)));
+            default: return type.children.forEach((f, i) => 
children[i].set(index, value[f.name]));
         }
     }
 
diff --git a/js/src/row/struct.ts b/js/src/row/struct.ts
index 483a435670..094f6a4b11 100644
--- a/js/src/row/struct.ts
+++ b/js/src/row/struct.ts
@@ -27,6 +27,8 @@ import { instance as setVisitor } from '../visitor/set.js';
 
 export type StructRowProxy<T extends TypeMap = any> = StructRow<T> & {
     [P in keyof T]: T[P]['TValue'];
+} & {
+    [key: symbol]: any;
 };
 
 export class StructRow<T extends TypeMap = any> {
@@ -149,7 +151,7 @@ class StructRowProxyHandler<T extends TypeMap = any> 
implements ProxyHandler<Str
             setVisitor.visit(row[kParent].children[idx], row[kRowIndex], val);
             // Cache key/val lookups
             return Reflect.set(row, key, val);
-        } else if (Reflect.has(row, key)) {
+        } else if (Reflect.has(row, key) || typeof key === 'symbol') {
             return Reflect.set(row, key, val);
         }
         return false;
diff --git a/js/src/visitor/get.ts b/js/src/visitor/get.ts
index 8f6cd7fed2..12f8325470 100644
--- a/js/src/visitor/get.ts
+++ b/js/src/visitor/get.ts
@@ -20,7 +20,7 @@ import { BN } from '../util/bn.js';
 import { Vector } from '../vector.js';
 import { Visitor } from '../visitor.js';
 import { MapRow } from '../row/map.js';
-import { StructRow } from '../row/struct.js';
+import { StructRow, StructRowProxy } from '../row/struct.js';
 import { decodeUtf8 } from '../util/utf8.js';
 import { TypeToDataType } from '../interfaces.js';
 import { uint16ToFloat64 } from '../util/math.js';
@@ -228,7 +228,7 @@ const getMap = <T extends Map_>(data: Data<T>, index: 
number): T['TValue'] => {
 
 /** @ignore */
 const getStruct = <T extends Struct>(data: Data<T>, index: number): 
T['TValue'] => {
-    return new StructRow(data, index);
+    return new StructRow(data, index) as StructRowProxy<T['TValue']>;
 };
 
 /* istanbul ignore next */
diff --git a/js/test/unit/row/struct-tests.ts b/js/test/unit/row/struct-tests.ts
new file mode 100644
index 0000000000..2ba6d34bbd
--- /dev/null
+++ b/js/test/unit/row/struct-tests.ts
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import { Field, Float32, makeData, Struct, StructRow, StructRowProxy } from 
'apache-arrow';
+
+function makeStructRow() {
+    const struct = makeData({
+        type: new Struct<{ foo: Float32 }>([
+            new Field('foo', new Float32())
+        ]),
+    });
+    return new StructRow(struct, 0) as StructRowProxy<{ foo: Float32 }>;
+}
+
+describe('StructRow', () => {
+    test('Can set existing property', () => {
+        const row = makeStructRow();
+        row.foo = 42;
+        expect(row.foo).toBe(42);
+    });
+
+    test('Can set arbitrary symbols', () => {
+        const row = makeStructRow();
+        const s = Symbol.for('mySymbol');
+        row[s] = 42;
+        expect(row[s]).toBe(42);
+    });
+
+    test('Cannot set arbitrary property', () => {
+        const row = makeStructRow();
+        expect(() => {
+            (row as any).bar = 42;
+        }).toThrow();
+    });
+});

Reply via email to