This is an automated email from the ASF dual-hosted git repository.
wesm 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 d0284cb ARROW-2236: [JS] Add more complete set of predicates
d0284cb is described below
commit d0284cb1857456f6ecbd1f4ae96eee8b3a259794
Author: Brian Hulette <[email protected]>
AuthorDate: Fri Mar 9 10:32:36 2018 -0500
ARROW-2236: [JS] Add more complete set of predicates
Adds not, gt, lt, and neq
Author: Brian Hulette <[email protected]>
Closes #1683 from TheNeuralBit/js-more-predicates and squashes the
following commits:
707de827 <Brian Hulette> Use two letter names
56ecea38 <Brian Hulette> export packBools, import compiled code in
vector-test
32b26e3b <Brian Hulette> lint
57383277 <Brian Hulette> add externs
84895a00 <Brian Hulette> Add not, lt, gt, neq
---
js/src/Arrow.externs.js | 15 +++++++++++++--
js/src/Arrow.ts | 27 +++++++++++++++------------
js/src/predicate.ts | 25 +++++++++++++++++++++++--
js/test/unit/table-tests.ts | 38 +++++++++++++++++++++++++++-----------
js/test/unit/vector-tests.ts | 10 +++++-----
5 files changed, 83 insertions(+), 32 deletions(-)
diff --git a/js/src/Arrow.externs.js b/js/src/Arrow.externs.js
index a14f959..4932c67 100644
--- a/js/src/Arrow.externs.js
+++ b/js/src/Arrow.externs.js
@@ -74,17 +74,24 @@ var custom = function () {};
var Value = function() {};
/** @type {?} */
-Value.prototype.gteq;
+Value.prototype.ge;
/** @type {?} */
-Value.prototype.lteq;
+Value.prototype.le;
/** @type {?} */
Value.prototype.eq;
+/** @type {?} */
+Value.prototype.lt;
+/** @type {?} */
+Value.prototype.gt;
+/** @type {?} */
+Value.prototype.ne;
var Col = function() {};
/** @type {?} */
Col.prototype.bind;
var Or = function() {};
var And = function() {};
+var Not = function() {};
var GTeq = function () {};
/** @type {?} */
GTeq.prototype.and;
@@ -108,6 +115,8 @@ Predicate.prototype.and;
/** @type {?} */
Predicate.prototype.or;
/** @type {?} */
+Predicate.prototype.not;
+/** @type {?} */
Predicate.prototype.ands;
var Literal = function() {};
@@ -209,6 +218,8 @@ Int128.prototype.plus
/** @type {?} */
Int128.prototype.hex
+var packBools = function() {};
+
var Type = function() {};
/** @type {?} */
Type.NONE = function() {};
diff --git a/js/src/Arrow.ts b/js/src/Arrow.ts
index 4a0a2ac..23e8b99 100644
--- a/js/src/Arrow.ts
+++ b/js/src/Arrow.ts
@@ -18,7 +18,8 @@
import * as type_ from './type';
import * as data_ from './data';
import * as vector_ from './vector';
-import * as util_ from './util/int';
+import * as util_int_ from './util/int';
+import * as util_bit_ from './util/bit';
import * as visitor_ from './visitor';
import * as view_ from './vector/view';
import * as predicate_ from './predicate';
@@ -40,9 +41,10 @@ export { Table, DataFrame, NextFunc, BindFunc, CountByResult
};
export { Field, Schema, RecordBatch, Vector, Type };
export namespace util {
- export import Uint64 = util_.Uint64;
- export import Int64 = util_.Int64;
- export import Int128 = util_.Int128;
+ export import Uint64 = util_int_.Uint64;
+ export import Int64 = util_int_.Int64;
+ export import Int128 = util_int_.Int128;
+ export import packBools = util_bit_.packBools;
}
export namespace data {
@@ -173,6 +175,7 @@ export namespace predicate {
export import Or = predicate_.Or;
export import Col = predicate_.Col;
export import And = predicate_.And;
+ export import Not = predicate_.Not;
export import GTeq = predicate_.GTeq;
export import LTeq = predicate_.LTeq;
export import Value = predicate_.Value;
@@ -222,16 +225,16 @@ Table['empty'] = Table.empty;
Vector['create'] = Vector.create;
RecordBatch['from'] = RecordBatch.from;
-util_.Uint64['add'] = util_.Uint64.add;
-util_.Uint64['multiply'] = util_.Uint64.multiply;
+util_int_.Uint64['add'] = util_int_.Uint64.add;
+util_int_.Uint64['multiply'] = util_int_.Uint64.multiply;
-util_.Int64['add'] = util_.Int64.add;
-util_.Int64['multiply'] = util_.Int64.multiply;
-util_.Int64['fromString'] = util_.Int64.fromString;
+util_int_.Int64['add'] = util_int_.Int64.add;
+util_int_.Int64['multiply'] = util_int_.Int64.multiply;
+util_int_.Int64['fromString'] = util_int_.Int64.fromString;
-util_.Int128['add'] = util_.Int128.add;
-util_.Int128['multiply'] = util_.Int128.multiply;
-util_.Int128['fromString'] = util_.Int128.fromString;
+util_int_.Int128['add'] = util_int_.Int128.add;
+util_int_.Int128['multiply'] = util_int_.Int128.multiply;
+util_int_.Int128['fromString'] = util_int_.Int128.fromString;
data_.ChunkedData['computeOffsets'] = data_.ChunkedData.computeOffsets;
diff --git a/js/src/predicate.ts b/js/src/predicate.ts
index b177b4f..bff3938 100644
--- a/js/src/predicate.ts
+++ b/js/src/predicate.ts
@@ -26,14 +26,23 @@ export abstract class Value<T> {
if (!(other instanceof Value)) { other = new Literal(other); }
return new Equals(this, other);
}
- lteq(other: Value<T> | T): Predicate {
+ le(other: Value<T> | T): Predicate {
if (!(other instanceof Value)) { other = new Literal(other); }
return new LTeq(this, other);
}
- gteq(other: Value<T> | T): Predicate {
+ ge(other: Value<T> | T): Predicate {
if (!(other instanceof Value)) { other = new Literal(other); }
return new GTeq(this, other);
}
+ lt(other: Value<T> | T): Predicate {
+ return new Not(this.ge(other));
+ }
+ gt(other: Value<T> | T): Predicate {
+ return new Not(this.le(other));
+ }
+ ne(other: Value<T> | T): Predicate {
+ return new Not(this.eq(other));
+ }
}
export class Literal<T= any> extends Value<T> {
@@ -70,6 +79,7 @@ export abstract class Predicate {
abstract bind(batch: RecordBatch): PredicateFunc;
and(expr: Predicate): Predicate { return new And(this, expr); }
or(expr: Predicate): Predicate { return new Or(this, expr); }
+ not(): Predicate { return new Not(this); }
ands(): Predicate[] { return [this]; }
}
@@ -222,6 +232,17 @@ export class GTeq extends ComparisonPredicate {
}
}
+export class Not extends Predicate {
+ constructor(public readonly child: Predicate) {
+ super();
+ }
+
+ bind(batch: RecordBatch) {
+ const func = this.child.bind(batch);
+ return (idx: number, batch: RecordBatch) => !func(idx, batch);
+ }
+}
+
export class CustomPredicate extends Predicate {
constructor(private next: PredicateFunc, private bind_: (batch:
RecordBatch) => void) {
super();
diff --git a/js/test/unit/table-tests.ts b/js/test/unit/table-tests.ts
index 8a43381..37bbf62 100644
--- a/js/test/unit/table-tests.ts
+++ b/js/test/unit/table-tests.ts
@@ -327,27 +327,39 @@ describe(`Table`, () => {
const filter_tests = [
{
name: `filter on f32 >= 0`,
- filtered: table.filter(col('f32').gteq(0)),
+ filtered: table.filter(col('f32').ge(0)),
expected: values.filter((row) => row[F32] >= 0)
}, {
name: `filter on 0 <= f32`,
- filtered: table.filter(lit(0).lteq(col('f32'))),
+ filtered: table.filter(lit(0).le(col('f32'))),
expected: values.filter((row) => 0 <= row[F32])
}, {
name: `filter on i32 <= 0`,
- filtered: table.filter(col('i32').lteq(0)),
+ filtered: table.filter(col('i32').le(0)),
expected: values.filter((row) => row[I32] <= 0)
}, {
name: `filter on 0 >= i32`,
- filtered: table.filter(lit(0).gteq(col('i32'))),
+ filtered: table.filter(lit(0).ge(col('i32'))),
expected: values.filter((row) => 0 >= row[I32])
}, {
+ name: `filter on f32 < 0`,
+ filtered: table.filter(col('f32').lt(0)),
+ expected: values.filter((row) => row[F32] < 0)
+ }, {
+ name: `filter on i32 > 1 (empty)`,
+ filtered: table.filter(col('i32').gt(0)),
+ expected: values.filter((row) => row[I32] > 0)
+ }, {
name: `filter on f32 <= -.25 || f3 >= .25`,
- filtered:
table.filter(col('f32').lteq(-.25).or(col('f32').gteq(.25))),
+ filtered:
table.filter(col('f32').le(-.25).or(col('f32').ge(.25))),
expected: values.filter((row) => row[F32] <= -.25 ||
row[F32] >= .25)
}, {
+ name: `filter on !(f32 <= -.25 || f3 >= .25) (not)`,
+ filtered:
table.filter(col('f32').le(-.25).or(col('f32').ge(.25)).not()),
+ expected: values.filter((row) => !(row[F32] <= -.25 ||
row[F32] >= .25))
+ }, {
name: `filter method combines predicates (f32 >= 0 &&
i32 <= 0)`,
- filtered:
table.filter(col('i32').lteq(0)).filter(col('f32').gteq(0)),
+ filtered:
table.filter(col('i32').le(0)).filter(col('f32').ge(0)),
expected: values.filter((row) => row[I32] <= 0 && row[F32]
>= 0)
}, {
name: `filter on dictionary == 'a'`,
@@ -358,12 +370,16 @@ describe(`Table`, () => {
filtered: table.filter(lit('a').eq(col('dictionary'))),
expected: values.filter((row) => row[DICT] === 'a')
}, {
+ name: `filter on dictionary != 'b'`,
+ filtered: table.filter(col('dictionary').ne('b')),
+ expected: values.filter((row) => row[DICT] !== 'b')
+ }, {
name: `filter on f32 >= i32`,
- filtered: table.filter(col('f32').gteq(col('i32'))),
+ filtered: table.filter(col('f32').ge(col('i32'))),
expected: values.filter((row) => row[F32] >= row[I32])
}, {
name: `filter on f32 <= i32`,
- filtered: table.filter(col('f32').lteq(col('i32'))),
+ filtered: table.filter(col('f32').le(col('i32'))),
expected: values.filter((row) => row[F32] <= row[I32])
}, {
name: `filter on f32*i32 > 0 (custom predicate)`,
@@ -455,17 +471,17 @@ describe(`Table`, () => {
expect(selected.toString()).toEqual(expected);
});
test(`table.filter(..).count() on always false predicates returns
0`, () => {
- expect(table.filter(col('i32').gteq(100)).count()).toEqual(0);
+ expect(table.filter(col('i32').ge(100)).count()).toEqual(0);
expect(table.filter(col('dictionary').eq('z')).count()).toEqual(0);
});
describe(`lit-lit comparison`, () => {
test(`always-false count() returns 0`, () => {
expect(table.filter(lit('abc').eq('def')).count()).toEqual(0);
- expect(table.filter(lit(0).gteq(1)).count()).toEqual(0);
+ expect(table.filter(lit(0).ge(1)).count()).toEqual(0);
});
test(`always-true count() returns length`, () => {
expect(table.filter(lit('abc').eq('abc')).count()).toEqual(table.length);
-
expect(table.filter(lit(-100).lteq(0)).count()).toEqual(table.length);
+
expect(table.filter(lit(-100).le(0)).count()).toEqual(table.length);
});
});
describe(`col-col comparison`, () => {
diff --git a/js/test/unit/vector-tests.ts b/js/test/unit/vector-tests.ts
index 3eb3fbe..d25e0e9 100644
--- a/js/test/unit/vector-tests.ts
+++ b/js/test/unit/vector-tests.ts
@@ -17,13 +17,13 @@
import { TextEncoder } from 'text-encoding-utf-8';
import Arrow from '../Arrow';
-import { type, TypedArray, TypedArrayConstructor, Vector } from
'../../src/Arrow';
-import { packBools } from '../../src/util/bit'
+import { TypedArray, TypedArrayConstructor } from '../../src/Arrow';
const utf8Encoder = new TextEncoder('utf-8');
+const { packBools } = Arrow.util;
const { BoolData, FlatData, FlatListData, DictionaryData } = Arrow.data;
-const { IntVector, FloatVector, BoolVector, Utf8Vector, DictionaryVector } =
Arrow.vector;
+const { Vector, IntVector, FloatVector, BoolVector, Utf8Vector,
DictionaryVector } = Arrow.vector;
const {
Dictionary, Utf8, Bool,
Float16, Float32, Float64,
@@ -143,7 +143,7 @@ describe('Float16Vector', () => {
const values = concatTyped(Uint16Array, ...bytes);
const vector = bytes
.map((b) => new Uint16Array(b.buffer))
- .map((b) => new FloatVector<type.Float16>(new FlatData(new Float16(),
b.length, null, b)))
+ .map((b) => new FloatVector<Float16>(new FlatData(new Float16(),
b.length, null, b)))
.reduce((v: any, v2) => v.concat(v2));
const n = values.length;
const clamp = (x: number) => (x - 32767) / 32767;
@@ -336,7 +336,7 @@ describe(`DictionaryVector`, () => {
describe(`sliced`, () => {
basicVectorTests(vector.slice(10, 20), values.slice(10,20),
extras);
- })
+ });
});
describe(`index with nullCount > 0`, () => {
--
To stop receiving notification emails like this one, please contact
[email protected].