| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- /**
- * DevExtreme (data/array_query.js)
- * Version: 19.1.16
- * Build date: Tue Oct 18 2022
- *
- * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
- * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
- */
- "use strict";
- var Class = require("../core/class");
- var typeUtils = require("../core/utils/type");
- var iteratorUtils = require("../core/utils/iterator");
- var compileGetter = require("../core/utils/data").compileGetter;
- var toComparable = require("../core/utils/data").toComparable;
- var Deferred = require("../core/utils/deferred").Deferred;
- var errorsModule = require("./errors");
- var dataUtils = require("./utils");
- var Iterator = Class.inherit({
- toArray: function() {
- var result = [];
- this.reset();
- while (this.next()) {
- result.push(this.current())
- }
- return result
- },
- countable: function() {
- return false
- }
- });
- var ArrayIterator = Iterator.inherit({
- ctor: function(array) {
- this.array = array;
- this.index = -1
- },
- next: function() {
- if (this.index + 1 < this.array.length) {
- this.index++;
- return true
- }
- return false
- },
- current: function() {
- return this.array[this.index]
- },
- reset: function() {
- this.index = -1
- },
- toArray: function() {
- return this.array.slice(0)
- },
- countable: function() {
- return true
- },
- count: function() {
- return this.array.length
- }
- });
- var WrappedIterator = Iterator.inherit({
- ctor: function(iter) {
- this.iter = iter
- },
- next: function() {
- return this.iter.next()
- },
- current: function() {
- return this.iter.current()
- },
- reset: function() {
- return this.iter.reset()
- }
- });
- var MapIterator = WrappedIterator.inherit({
- ctor: function(iter, mapper) {
- this.callBase(iter);
- this.index = -1;
- this.mapper = mapper
- },
- current: function() {
- return this.mapper(this.callBase(), this.index)
- },
- next: function() {
- var hasNext = this.callBase();
- if (hasNext) {
- this.index++
- }
- return hasNext
- }
- });
- var defaultCompare = function(xValue, yValue) {
- xValue = toComparable(xValue);
- yValue = toComparable(yValue);
- if (null === xValue && null !== yValue) {
- return -1
- }
- if (null !== xValue && null === yValue) {
- return 1
- }
- if (void 0 === xValue && void 0 !== yValue) {
- return 1
- }
- if (void 0 !== xValue && void 0 === yValue) {
- return -1
- }
- if (xValue < yValue) {
- return -1
- }
- if (xValue > yValue) {
- return 1
- }
- return 0
- };
- var SortIterator = Iterator.inherit({
- ctor: function(iter, getter, desc, compare) {
- if (!(iter instanceof MapIterator)) {
- iter = new MapIterator(iter, this._wrap)
- }
- this.iter = iter;
- this.rules = [{
- getter: getter,
- desc: desc,
- compare: compare
- }]
- },
- thenBy: function(getter, desc, compare) {
- var result = new SortIterator(this.sortedIter || this.iter, getter, desc, compare);
- if (!this.sortedIter) {
- result.rules = this.rules.concat(result.rules)
- }
- return result
- },
- next: function() {
- this._ensureSorted();
- return this.sortedIter.next()
- },
- current: function() {
- this._ensureSorted();
- return this.sortedIter.current()
- },
- reset: function() {
- delete this.sortedIter
- },
- countable: function() {
- return this.sortedIter || this.iter.countable()
- },
- count: function() {
- if (this.sortedIter) {
- return this.sortedIter.count()
- }
- return this.iter.count()
- },
- _ensureSorted: function() {
- var that = this;
- if (that.sortedIter) {
- return
- }
- iteratorUtils.each(that.rules, function() {
- this.getter = compileGetter(this.getter)
- });
- that.sortedIter = new MapIterator(new ArrayIterator(this.iter.toArray().sort(function(x, y) {
- return that._compare(x, y)
- })), that._unwrap)
- },
- _wrap: function(record, index) {
- return {
- index: index,
- value: record
- }
- },
- _unwrap: function(wrappedItem) {
- return wrappedItem.value
- },
- _compare: function(x, y) {
- var xIndex = x.index;
- var yIndex = y.index;
- x = x.value;
- y = y.value;
- if (x === y) {
- return xIndex - yIndex
- }
- for (var i = 0, rulesCount = this.rules.length; i < rulesCount; i++) {
- var rule = this.rules[i];
- var xValue = rule.getter(x);
- var yValue = rule.getter(y);
- var compare = rule.compare || defaultCompare;
- var compareResult = compare(xValue, yValue);
- if (compareResult) {
- return rule.desc ? -compareResult : compareResult
- }
- }
- return xIndex - yIndex
- }
- });
- var compileCriteria = function() {
- var compileGroup = function(crit) {
- var ops = [];
- var isConjunctiveOperator = false;
- var isConjunctiveNextOperator = false;
- iteratorUtils.each(crit, function() {
- if (Array.isArray(this) || typeUtils.isFunction(this)) {
- if (ops.length > 1 && isConjunctiveOperator !== isConjunctiveNextOperator) {
- throw new errorsModule.errors.Error("E4019")
- }
- ops.push(compileCriteria(this));
- isConjunctiveOperator = isConjunctiveNextOperator;
- isConjunctiveNextOperator = true
- } else {
- isConjunctiveNextOperator = dataUtils.isConjunctiveOperator(this)
- }
- });
- return function(d) {
- var result = isConjunctiveOperator;
- for (var i = 0; i < ops.length; i++) {
- if (ops[i](d) !== isConjunctiveOperator) {
- result = !isConjunctiveOperator;
- break
- }
- }
- return result
- }
- };
- var toString = function(value) {
- return typeUtils.isDefined(value) ? value.toString() : ""
- };
- var compileBinary = function(crit) {
- crit = dataUtils.normalizeBinaryCriterion(crit);
- var getter = compileGetter(crit[0]);
- var op = crit[1];
- var value = crit[2];
- value = toComparable(value);
- switch (op.toLowerCase()) {
- case "=":
- return compileEquals(getter, value);
- case "<>":
- return compileEquals(getter, value, true);
- case ">":
- return function(obj) {
- return toComparable(getter(obj)) > value
- };
- case "<":
- return function(obj) {
- return toComparable(getter(obj)) < value
- };
- case ">=":
- return function(obj) {
- return toComparable(getter(obj)) >= value
- };
- case "<=":
- return function(obj) {
- return toComparable(getter(obj)) <= value
- };
- case "startswith":
- return function(obj) {
- return 0 === toComparable(toString(getter(obj))).indexOf(value)
- };
- case "endswith":
- return function(obj) {
- var getterValue = toComparable(toString(getter(obj)));
- var searchValue = toString(value);
- if (getterValue.length < searchValue.length) {
- return false
- }
- var index = getterValue.lastIndexOf(value);
- return index !== -1 && index === getterValue.length - value.length
- };
- case "contains":
- return function(obj) {
- return toComparable(toString(getter(obj))).indexOf(value) > -1
- };
- case "notcontains":
- return function(obj) {
- return toComparable(toString(getter(obj))).indexOf(value) === -1
- }
- }
- throw errorsModule.errors.Error("E4003", op)
- };
- function compileEquals(getter, value, negate) {
- return function(obj) {
- obj = toComparable(getter(obj));
- var result = useStrictComparison(value) ? obj === value : obj == value;
- if (negate) {
- result = !result
- }
- return result
- }
- }
- function useStrictComparison(value) {
- return "" === value || 0 === value || false === value
- }
- function compileUnary(crit) {
- var op = crit[0];
- var criteria = compileCriteria(crit[1]);
- if ("!" === op) {
- return function(obj) {
- return !criteria(obj)
- }
- }
- throw errorsModule.errors.Error("E4003", op)
- }
- return function(crit) {
- if (typeUtils.isFunction(crit)) {
- return crit
- }
- if (dataUtils.isGroupCriterion(crit)) {
- return compileGroup(crit)
- }
- if (dataUtils.isUnaryOperation(crit)) {
- return compileUnary(crit)
- }
- return compileBinary(crit)
- }
- }();
- var FilterIterator = WrappedIterator.inherit({
- ctor: function(iter, criteria) {
- this.callBase(iter);
- this.criteria = compileCriteria(criteria)
- },
- next: function() {
- while (this.iter.next()) {
- if (this.criteria(this.current())) {
- return true
- }
- }
- return false
- }
- });
- var GroupIterator = Iterator.inherit({
- ctor: function(iter, getter) {
- this.iter = iter;
- this.getter = getter
- },
- next: function() {
- this._ensureGrouped();
- return this.groupedIter.next()
- },
- current: function() {
- this._ensureGrouped();
- return this.groupedIter.current()
- },
- reset: function() {
- delete this.groupedIter
- },
- countable: function() {
- return !!this.groupedIter
- },
- count: function() {
- return this.groupedIter.count()
- },
- _ensureGrouped: function() {
- if (this.groupedIter) {
- return
- }
- var hash = {};
- var keys = [];
- var iter = this.iter;
- var getter = compileGetter(this.getter);
- iter.reset();
- while (iter.next()) {
- var current = iter.current();
- var key = getter(current);
- if (key in hash) {
- hash[key].push(current)
- } else {
- hash[key] = [current];
- keys.push(key)
- }
- }
- this.groupedIter = new ArrayIterator(iteratorUtils.map(keys, function(key) {
- return {
- key: key,
- items: hash[key]
- }
- }))
- }
- });
- var SelectIterator = WrappedIterator.inherit({
- ctor: function(iter, getter) {
- this.callBase(iter);
- this.getter = compileGetter(getter)
- },
- current: function() {
- return this.getter(this.callBase())
- },
- countable: function() {
- return this.iter.countable()
- },
- count: function() {
- return this.iter.count()
- }
- });
- var SliceIterator = WrappedIterator.inherit({
- ctor: function(iter, skip, take) {
- this.callBase(iter);
- this.skip = Math.max(0, skip);
- this.take = Math.max(0, take);
- this.pos = 0
- },
- next: function() {
- if (this.pos >= this.skip + this.take) {
- return false
- }
- while (this.pos < this.skip && this.iter.next()) {
- this.pos++
- }
- this.pos++;
- return this.iter.next()
- },
- reset: function() {
- this.callBase();
- this.pos = 0
- },
- countable: function() {
- return this.iter.countable()
- },
- count: function() {
- return Math.min(this.iter.count() - this.skip, this.take)
- }
- });
- var arrayQueryImpl = function arrayQueryImpl(iter, queryOptions) {
- queryOptions = queryOptions || {};
- if (!(iter instanceof Iterator)) {
- iter = new ArrayIterator(iter)
- }
- var handleError = function(error) {
- var handler = queryOptions.errorHandler;
- if (handler) {
- handler(error)
- }
- errorsModule._errorHandler(error)
- };
- var aggregateCore = function(aggregator) {
- var d = (new Deferred).fail(handleError);
- var seed;
- var step = aggregator.step;
- var finalize = aggregator.finalize;
- try {
- iter.reset();
- if ("seed" in aggregator) {
- seed = aggregator.seed
- } else {
- seed = iter.next() ? iter.current() : NaN
- }
- var accumulator = seed;
- while (iter.next()) {
- accumulator = step(accumulator, iter.current())
- }
- d.resolve(finalize ? finalize(accumulator) : accumulator)
- } catch (x) {
- d.reject(x)
- }
- return d.promise()
- };
- var aggregate = function(seed, step, finalize) {
- if (arguments.length < 2) {
- return aggregateCore({
- step: arguments[0]
- })
- }
- return aggregateCore({
- seed: seed,
- step: step,
- finalize: finalize
- })
- };
- var standardAggregate = function(name) {
- return aggregateCore(dataUtils.aggregators[name])
- };
- var select = function(getter) {
- if (!typeUtils.isFunction(getter) && !Array.isArray(getter)) {
- getter = [].slice.call(arguments)
- }
- return chainQuery(new SelectIterator(iter, getter))
- };
- var selectProp = function(name) {
- return select(compileGetter(name))
- };
- var chainQuery = function(iter) {
- return arrayQueryImpl(iter, queryOptions)
- };
- return {
- toArray: function() {
- return iter.toArray()
- },
- enumerate: function() {
- var d = (new Deferred).fail(handleError);
- try {
- d.resolve(iter.toArray())
- } catch (x) {
- d.reject(x)
- }
- return d.promise()
- },
- sortBy: function(getter, desc, compare) {
- return chainQuery(new SortIterator(iter, getter, desc, compare))
- },
- thenBy: function(getter, desc, compare) {
- if (iter instanceof SortIterator) {
- return chainQuery(iter.thenBy(getter, desc, compare))
- }
- throw errorsModule.errors.Error("E4004")
- },
- filter: function(criteria) {
- if (!Array.isArray(criteria)) {
- criteria = [].slice.call(arguments)
- }
- return chainQuery(new FilterIterator(iter, criteria))
- },
- slice: function(skip, take) {
- if (void 0 === take) {
- take = Number.MAX_VALUE
- }
- return chainQuery(new SliceIterator(iter, skip, take))
- },
- select: select,
- groupBy: function(getter) {
- return chainQuery(new GroupIterator(iter, getter))
- },
- aggregate: aggregate,
- count: function() {
- if (iter.countable()) {
- var d = (new Deferred).fail(handleError);
- try {
- d.resolve(iter.count())
- } catch (x) {
- d.reject(x)
- }
- return d.promise()
- }
- return standardAggregate("count")
- },
- sum: function(getter) {
- if (getter) {
- return selectProp(getter).sum()
- }
- return standardAggregate("sum")
- },
- min: function(getter) {
- if (getter) {
- return selectProp(getter).min()
- }
- return standardAggregate("min")
- },
- max: function(getter) {
- if (getter) {
- return selectProp(getter).max()
- }
- return standardAggregate("max")
- },
- avg: function(getter) {
- if (getter) {
- return selectProp(getter).avg()
- }
- return standardAggregate("avg")
- }
- }
- };
- module.exports = arrayQueryImpl;
|