UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

479 lines (375 loc) • 14.4 kB
"use strict"; var typeUtils = require("../../core/utils/type"), iteratorUtils = require("../../core/utils/iterator"), extend = require("../../core/utils/extend").extend, queryAdapters = require("../query_adapters"), odataUtils = require("./utils"), serializePropName = odataUtils.serializePropName, errors = require("../errors").errors, dataUtils = require("../utils"), isFunction = typeUtils.isFunction, isPlainObject = typeUtils.isPlainObject, grep = require("../../core/utils/common").grep; var DEFAULT_PROTOCOL_VERSION = 2; var makeArray = function makeArray(value) { return typeUtils.type(value) === "string" ? value.split() : value; }; var compileCriteria = function () { var protocolVersion, fieldTypes; var createBinaryOperationFormatter = function createBinaryOperationFormatter(op) { return function (prop, val) { return prop + " " + op + " " + val; }; }; var createStringFuncFormatter = function createStringFuncFormatter(op, reverse) { return function (prop, val) { var bag = [op, "("]; if (reverse) { bag.push(val, ",", prop); } else { bag.push(prop, ",", val); } bag.push(")"); return bag.join(""); }; }; var formatters = { "=": createBinaryOperationFormatter("eq"), "<>": createBinaryOperationFormatter("ne"), ">": createBinaryOperationFormatter("gt"), ">=": createBinaryOperationFormatter("ge"), "<": createBinaryOperationFormatter("lt"), "<=": createBinaryOperationFormatter("le"), "startswith": createStringFuncFormatter("startswith"), "endswith": createStringFuncFormatter("endswith") }; var formattersV2 = extend({}, formatters, { "contains": createStringFuncFormatter("substringof", true), "notcontains": createStringFuncFormatter("not substringof", true) }); var formattersV4 = extend({}, formatters, { "contains": createStringFuncFormatter("contains"), "notcontains": createStringFuncFormatter("not contains") }); var compileBinary = function compileBinary(criteria) { criteria = dataUtils.normalizeBinaryCriterion(criteria); var op = criteria[1], formatters = protocolVersion === 4 ? formattersV4 : formattersV2, formatter = formatters[op.toLowerCase()]; if (!formatter) { throw errors.Error("E4003", op); } var fieldName = criteria[0], value = criteria[2]; if (fieldTypes && fieldTypes[fieldName]) { value = odataUtils.convertPrimitiveValue(fieldTypes[fieldName], value); } return formatter(serializePropName(fieldName), odataUtils.serializeValue(value, protocolVersion)); }; var compileUnary = function compileUnary(criteria) { var op = criteria[0], crit = compileCore(criteria[1]); if (op === "!") { return "not (" + crit + ")"; } throw errors.Error("E4003", op); }; var compileGroup = function compileGroup(criteria) { var bag = [], groupOperator, nextGroupOperator; iteratorUtils.each(criteria, function (index, criterion) { if (Array.isArray(criterion)) { if (bag.length > 1 && groupOperator !== nextGroupOperator) { throw new errors.Error("E4019"); } bag.push("(" + compileCore(criterion) + ")"); groupOperator = nextGroupOperator; nextGroupOperator = "and"; } else { nextGroupOperator = dataUtils.isConjunctiveOperator(this) ? "and" : "or"; } }); return bag.join(" " + groupOperator + " "); }; var compileCore = function compileCore(criteria) { if (Array.isArray(criteria[0])) { return compileGroup(criteria); } if (dataUtils.isUnaryOperation(criteria)) { return compileUnary(criteria); } return compileBinary(criteria); }; return function (criteria, version, types) { fieldTypes = types; protocolVersion = version; return compileCore(criteria); }; }(); var createODataQueryAdapter = function createODataQueryAdapter(queryOptions) { var _sorting = [], _criteria = [], _expand = queryOptions.expand, _select, _skip, _take, _countQuery, _oDataVersion = queryOptions.version || DEFAULT_PROTOCOL_VERSION; var hasSlice = function hasSlice() { return _skip || _take !== undefined; }; var hasFunction = function hasFunction(criterion) { for (var i = 0; i < criterion.length; i++) { if (isFunction(criterion[i])) { return true; } if (Array.isArray(criterion[i]) && hasFunction(criterion[i])) { return true; } } return false; }; var generateSelectExpand = function generateSelectExpand() { var hasDot = function hasDot(x) { return (/\./.test(x) ); }; var generateSelect = function generateSelect() { if (!_select) { return; } if (_oDataVersion < 4) { return serializePropName(_select.join()); } return grep(_select, hasDot, true).join(); }; var generateExpand = function generateExpand() { var generatorV2 = function generatorV2() { var hash = {}; if (_expand) { iteratorUtils.each(makeArray(_expand), function () { hash[serializePropName(this)] = 1; }); } if (_select) { iteratorUtils.each(makeArray(_select), function () { var path = this.split("."); if (path.length < 2) { return; } path.pop(); hash[serializePropName(path.join("."))] = 1; }); } return iteratorUtils.map(hash, function (k, v) { return v; }).join(); }; var generatorV4 = function generatorV4() { var format = function format(hash) { var formatCore = function formatCore(hash) { var result = "", select = [], expand = []; iteratorUtils.each(hash, function (key, value) { if (Array.isArray(value)) { [].push.apply(select, value); } if (isPlainObject(value)) { expand.push(key + formatCore(value)); } }); if (select.length || expand.length) { result += "("; if (select.length) { result += "$select=" + iteratorUtils.map(select, serializePropName).join(); } if (expand.length) { if (select.length) { result += ";"; } result += "$expand=" + iteratorUtils.map(expand, serializePropName).join(); } result += ")"; } return result; }; var result = []; iteratorUtils.each(hash, function (key, value) { result.push(key + formatCore(value)); }); return result.join(); }; var parseTree = function parseTree(exprs, root, stepper) { var parseCore = function parseCore(exprParts, root, stepper) { var result = stepper(root, exprParts.shift(), exprParts); if (result === false) { return; } parseCore(exprParts, result, stepper); }; iteratorUtils.each(exprs, function (_, x) { parseCore(x.split("."), root, stepper); }); }; var hash = {}; if (_expand || _select) { if (_expand) { parseTree(makeArray(_expand), hash, function (node, key, path) { node[key] = node[key] || {}; if (!path.length) { return false; } return node[key]; }); } if (_select) { parseTree(grep(makeArray(_select), hasDot), hash, function (node, key, path) { if (!path.length) { node[key] = node[key] || []; node[key].push(key); return false; } return node[key] = node[key] || {}; }); } return format(hash); } }; if (_oDataVersion < 4) { return generatorV2(); } return generatorV4(); }; var tuple = { "$select": generateSelect() || undefined, "$expand": generateExpand() || undefined }; return tuple; }; var requestData = function requestData() { var result = {}; if (!_countQuery) { if (_sorting.length) { result["$orderby"] = _sorting.join(","); } if (_skip) { result["$skip"] = _skip; } if (_take !== undefined) { result["$top"] = _take; } var tuple = generateSelectExpand(); result["$select"] = tuple["$select"]; result["$expand"] = tuple["$expand"]; } if (_criteria.length) { var criteria = _criteria.length < 2 ? _criteria[0] : _criteria, fieldTypes = queryOptions && queryOptions.fieldTypes; result["$filter"] = compileCriteria(criteria, _oDataVersion, fieldTypes); } if (_countQuery) { result["$top"] = 0; } if (queryOptions.requireTotalCount || _countQuery) { // todo: tests!!! if (_oDataVersion !== 4) { result["$inlinecount"] = "allpages"; } else { result["$count"] = "true"; } } return result; }; function tryLiftSelect(tasks) { var selectIndex = -1; for (var i = 0; i < tasks.length; i++) { if (tasks[i].name === "select") { selectIndex = i; break; } } if (selectIndex < 0 || !isFunction(tasks[selectIndex].args[0])) return; var nextTask = tasks[1 + selectIndex]; if (!nextTask || nextTask.name !== "slice") return; tasks[1 + selectIndex] = tasks[selectIndex]; tasks[selectIndex] = nextTask; } return { optimize: function optimize(tasks) { tryLiftSelect(tasks); }, exec: function exec(url) { return odataUtils.sendRequest(_oDataVersion, { url: url, params: extend(requestData(), queryOptions && queryOptions.params) }, { beforeSend: queryOptions.beforeSend, jsonp: queryOptions.jsonp, withCredentials: queryOptions.withCredentials, countOnly: _countQuery, deserializeDates: queryOptions.deserializeDates, fieldTypes: queryOptions.fieldTypes, isPaged: isFinite(_take) }); }, multiSort: function multiSort(args) { var rules; if (hasSlice()) { return false; } for (var i = 0; i < args.length; i++) { var getter = args[i][0], desc = !!args[i][1], rule; if (typeof getter !== "string") { return false; } rule = serializePropName(getter); if (desc) { rule += " desc"; } rules = rules || []; rules.push(rule); } _sorting = rules; }, slice: function slice(skipCount, takeCount) { if (hasSlice()) { return false; } _skip = skipCount; _take = takeCount; }, filter: function filter(criterion) { if (hasSlice()) { return false; } if (!Array.isArray(criterion)) { criterion = [].slice.call(arguments); } if (hasFunction(criterion)) { return false; } if (_criteria.length) { _criteria.push("and"); } _criteria.push(criterion); }, select: function select(expr) { if (_select || isFunction(expr)) { return false; } if (!Array.isArray(expr)) { expr = [].slice.call(arguments); } _select = expr; }, count: function count() { _countQuery = true; } }; }; queryAdapters.odata = createODataQueryAdapter; exports.odata = createODataQueryAdapter;