Spaces:
Sleeping
Sleeping
// 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 { DictionaryVector } from '../vector/dictionary'; | |
/** @ignore */ | |
export class Value { | |
eq(other) { | |
if (!(other instanceof Value)) { | |
other = new Literal(other); | |
} | |
return new Equals(this, other); | |
} | |
le(other) { | |
if (!(other instanceof Value)) { | |
other = new Literal(other); | |
} | |
return new LTeq(this, other); | |
} | |
ge(other) { | |
if (!(other instanceof Value)) { | |
other = new Literal(other); | |
} | |
return new GTeq(this, other); | |
} | |
lt(other) { | |
return new Not(this.ge(other)); | |
} | |
gt(other) { | |
return new Not(this.le(other)); | |
} | |
ne(other) { | |
return new Not(this.eq(other)); | |
} | |
} | |
/** @ignore */ | |
export class Literal extends Value { | |
constructor(v) { | |
super(); | |
this.v = v; | |
} | |
} | |
/** @ignore */ | |
export class Col extends Value { | |
constructor(name) { | |
super(); | |
this.name = name; | |
} | |
bind(batch) { | |
if (!this.colidx) { | |
// Assume column index doesn't change between calls to bind | |
//this.colidx = cols.findIndex(v => v.name.indexOf(this.name) != -1); | |
this.colidx = -1; | |
const fields = batch.schema.fields; | |
for (let idx = -1; ++idx < fields.length;) { | |
if (fields[idx].name === this.name) { | |
this.colidx = idx; | |
break; | |
} | |
} | |
if (this.colidx < 0) { | |
throw new Error(`Failed to bind Col "${this.name}"`); | |
} | |
} | |
const vec = this.vector = batch.getChildAt(this.colidx); | |
return (idx) => vec.get(idx); | |
} | |
} | |
/** @ignore */ | |
export class Predicate { | |
and(...expr) { return new And(this, ...expr); } | |
or(...expr) { return new Or(this, ...expr); } | |
not() { return new Not(this); } | |
} | |
/** @ignore */ | |
export class ComparisonPredicate extends Predicate { | |
constructor(left, right) { | |
super(); | |
this.left = left; | |
this.right = right; | |
} | |
bind(batch) { | |
if (this.left instanceof Literal) { | |
if (this.right instanceof Literal) { | |
return this._bindLitLit(batch, this.left, this.right); | |
} | |
else { // right is a Col | |
return this._bindLitCol(batch, this.left, this.right); | |
} | |
} | |
else { // left is a Col | |
if (this.right instanceof Literal) { | |
return this._bindColLit(batch, this.left, this.right); | |
} | |
else { // right is a Col | |
return this._bindColCol(batch, this.left, this.right); | |
} | |
} | |
} | |
} | |
/** @ignore */ | |
export class CombinationPredicate extends Predicate { | |
constructor(...children) { | |
super(); | |
this.children = children; | |
} | |
} | |
// add children to prototype so it doesn't get mangled in es2015/umd | |
CombinationPredicate.prototype.children = Object.freeze([]); // freeze for safety | |
/** @ignore */ | |
export class And extends CombinationPredicate { | |
constructor(...children) { | |
// Flatten any Ands | |
children = children.reduce((accum, p) => { | |
return accum.concat(p instanceof And ? p.children : p); | |
}, []); | |
super(...children); | |
} | |
bind(batch) { | |
const bound = this.children.map((p) => p.bind(batch)); | |
return (idx, batch) => bound.every((p) => p(idx, batch)); | |
} | |
} | |
/** @ignore */ | |
export class Or extends CombinationPredicate { | |
constructor(...children) { | |
// Flatten any Ors | |
children = children.reduce((accum, p) => { | |
return accum.concat(p instanceof Or ? p.children : p); | |
}, []); | |
super(...children); | |
} | |
bind(batch) { | |
const bound = this.children.map((p) => p.bind(batch)); | |
return (idx, batch) => bound.some((p) => p(idx, batch)); | |
} | |
} | |
/** @ignore */ | |
export class Equals extends ComparisonPredicate { | |
_bindLitLit(_batch, left, right) { | |
const rtrn = left.v == right.v; | |
return () => rtrn; | |
} | |
_bindColCol(batch, left, right) { | |
const left_func = left.bind(batch); | |
const right_func = right.bind(batch); | |
return (idx, batch) => left_func(idx, batch) == right_func(idx, batch); | |
} | |
_bindColLit(batch, col, lit) { | |
const col_func = col.bind(batch); | |
if (col.vector instanceof DictionaryVector) { | |
let key; | |
const vector = col.vector; | |
if (vector.dictionary !== this.lastDictionary) { | |
key = vector.reverseLookup(lit.v); | |
this.lastDictionary = vector.dictionary; | |
this.lastKey = key; | |
} | |
else { | |
key = this.lastKey; | |
} | |
if (key === -1) { | |
// the value doesn't exist in the dictionary - always return | |
// false | |
// TODO: special-case of PredicateFunc that encapsulates this | |
// "always false" behavior. That way filtering operations don't | |
// have to bother checking | |
return () => false; | |
} | |
else { | |
return (idx) => { | |
return vector.getKey(idx) === key; | |
}; | |
} | |
} | |
else { | |
return (idx, cols) => col_func(idx, cols) == lit.v; | |
} | |
} | |
_bindLitCol(batch, lit, col) { | |
// Equals is commutative | |
return this._bindColLit(batch, col, lit); | |
} | |
} | |
/** @ignore */ | |
export class LTeq extends ComparisonPredicate { | |
_bindLitLit(_batch, left, right) { | |
const rtrn = left.v <= right.v; | |
return () => rtrn; | |
} | |
_bindColCol(batch, left, right) { | |
const left_func = left.bind(batch); | |
const right_func = right.bind(batch); | |
return (idx, cols) => left_func(idx, cols) <= right_func(idx, cols); | |
} | |
_bindColLit(batch, col, lit) { | |
const col_func = col.bind(batch); | |
return (idx, cols) => col_func(idx, cols) <= lit.v; | |
} | |
_bindLitCol(batch, lit, col) { | |
const col_func = col.bind(batch); | |
return (idx, cols) => lit.v <= col_func(idx, cols); | |
} | |
} | |
/** @ignore */ | |
export class GTeq extends ComparisonPredicate { | |
_bindLitLit(_batch, left, right) { | |
const rtrn = left.v >= right.v; | |
return () => rtrn; | |
} | |
_bindColCol(batch, left, right) { | |
const left_func = left.bind(batch); | |
const right_func = right.bind(batch); | |
return (idx, cols) => left_func(idx, cols) >= right_func(idx, cols); | |
} | |
_bindColLit(batch, col, lit) { | |
const col_func = col.bind(batch); | |
return (idx, cols) => col_func(idx, cols) >= lit.v; | |
} | |
_bindLitCol(batch, lit, col) { | |
const col_func = col.bind(batch); | |
return (idx, cols) => lit.v >= col_func(idx, cols); | |
} | |
} | |
/** @ignore */ | |
export class Not extends Predicate { | |
constructor(child) { | |
super(); | |
this.child = child; | |
} | |
bind(batch) { | |
const func = this.child.bind(batch); | |
return (idx, batch) => !func(idx, batch); | |
} | |
} | |
/** @ignore */ | |
export class CustomPredicate extends Predicate { | |
constructor(next, bind_) { | |
super(); | |
this.next = next; | |
this.bind_ = bind_; | |
} | |
bind(batch) { | |
this.bind_(batch); | |
return this.next; | |
} | |
} | |
export function lit(v) { return new Literal(v); } | |
export function col(n) { return new Col(n); } | |
export function and(...p) { return new And(...p); } | |
export function or(...p) { return new Or(...p); } | |
export function custom(next, bind) { | |
return new CustomPredicate(next, bind); | |
} | |
//# sourceMappingURL=predicate.mjs.map | |