query_adapter.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /**
  2. * DevExtreme (data/odata/query_adapter.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var typeUtils = require("../../core/utils/type");
  11. var iteratorUtils = require("../../core/utils/iterator");
  12. var config = require("../../core/config");
  13. var extend = require("../../core/utils/extend").extend;
  14. var queryAdapters = require("../query_adapters");
  15. var odataUtils = require("./utils");
  16. var serializePropName = odataUtils.serializePropName;
  17. var errors = require("../errors").errors;
  18. var dataUtils = require("../utils");
  19. var isFunction = typeUtils.isFunction;
  20. var DEFAULT_PROTOCOL_VERSION = 2;
  21. var compileCriteria = function() {
  22. var protocolVersion;
  23. var forceLowerCase;
  24. var fieldTypes;
  25. var createBinaryOperationFormatter = function(op) {
  26. return function(prop, val) {
  27. return prop + " " + op + " " + val
  28. }
  29. };
  30. var createStringFuncFormatter = function(op, reverse) {
  31. return function(prop, val) {
  32. var bag = [op, "("];
  33. if (forceLowerCase) {
  34. prop = prop.indexOf("tolower(") === -1 ? "tolower(" + prop + ")" : prop;
  35. val = val.toLowerCase()
  36. }
  37. if (reverse) {
  38. bag.push(val, ",", prop)
  39. } else {
  40. bag.push(prop, ",", val)
  41. }
  42. bag.push(")");
  43. return bag.join("")
  44. }
  45. };
  46. var formatters = {
  47. "=": createBinaryOperationFormatter("eq"),
  48. "<>": createBinaryOperationFormatter("ne"),
  49. ">": createBinaryOperationFormatter("gt"),
  50. ">=": createBinaryOperationFormatter("ge"),
  51. "<": createBinaryOperationFormatter("lt"),
  52. "<=": createBinaryOperationFormatter("le"),
  53. startswith: createStringFuncFormatter("startswith"),
  54. endswith: createStringFuncFormatter("endswith")
  55. };
  56. var formattersV2 = extend({}, formatters, {
  57. contains: createStringFuncFormatter("substringof", true),
  58. notcontains: createStringFuncFormatter("not substringof", true)
  59. });
  60. var formattersV4 = extend({}, formatters, {
  61. contains: createStringFuncFormatter("contains"),
  62. notcontains: createStringFuncFormatter("not contains")
  63. });
  64. var compileBinary = function(criteria) {
  65. criteria = dataUtils.normalizeBinaryCriterion(criteria);
  66. var op = criteria[1];
  67. var formatters = 4 === protocolVersion ? formattersV4 : formattersV2;
  68. var formatter = formatters[op.toLowerCase()];
  69. if (!formatter) {
  70. throw errors.Error("E4003", op)
  71. }
  72. var fieldName = criteria[0];
  73. var value = criteria[2];
  74. if (fieldTypes && fieldTypes[fieldName]) {
  75. value = odataUtils.convertPrimitiveValue(fieldTypes[fieldName], value)
  76. }
  77. return formatter(serializePropName(fieldName), odataUtils.serializeValue(value, protocolVersion))
  78. };
  79. var compileUnary = function(criteria) {
  80. var op = criteria[0];
  81. var crit = compileCore(criteria[1]);
  82. if ("!" === op) {
  83. return "not (" + crit + ")"
  84. }
  85. throw errors.Error("E4003", op)
  86. };
  87. var compileGroup = function(criteria) {
  88. var bag = [];
  89. var groupOperator;
  90. var nextGroupOperator;
  91. iteratorUtils.each(criteria, function(index, criterion) {
  92. if (Array.isArray(criterion)) {
  93. if (bag.length > 1 && groupOperator !== nextGroupOperator) {
  94. throw new errors.Error("E4019")
  95. }
  96. bag.push("(" + compileCore(criterion) + ")");
  97. groupOperator = nextGroupOperator;
  98. nextGroupOperator = "and"
  99. } else {
  100. nextGroupOperator = dataUtils.isConjunctiveOperator(this) ? "and" : "or"
  101. }
  102. });
  103. return bag.join(" " + groupOperator + " ")
  104. };
  105. var compileCore = function(criteria) {
  106. if (Array.isArray(criteria[0])) {
  107. return compileGroup(criteria)
  108. }
  109. if (dataUtils.isUnaryOperation(criteria)) {
  110. return compileUnary(criteria)
  111. }
  112. return compileBinary(criteria)
  113. };
  114. return function(criteria, version, types, filterToLower) {
  115. fieldTypes = types;
  116. forceLowerCase = typeUtils.isDefined(filterToLower) ? filterToLower : config().oDataFilterToLower;
  117. protocolVersion = version;
  118. return compileCore(criteria)
  119. }
  120. }();
  121. var createODataQueryAdapter = function(queryOptions) {
  122. var _sorting = [];
  123. var _criteria = [];
  124. var _expand = queryOptions.expand;
  125. var _select;
  126. var _skip;
  127. var _take;
  128. var _countQuery;
  129. var _oDataVersion = queryOptions.version || DEFAULT_PROTOCOL_VERSION;
  130. var hasSlice = function() {
  131. return _skip || void 0 !== _take
  132. };
  133. var hasFunction = function hasFunction(criterion) {
  134. for (var i = 0; i < criterion.length; i++) {
  135. if (isFunction(criterion[i])) {
  136. return true
  137. }
  138. if (Array.isArray(criterion[i]) && hasFunction(criterion[i])) {
  139. return true
  140. }
  141. }
  142. return false
  143. };
  144. var requestData = function() {
  145. var result = {};
  146. if (!_countQuery) {
  147. if (_sorting.length) {
  148. result.$orderby = _sorting.join(",")
  149. }
  150. if (_skip) {
  151. result.$skip = _skip
  152. }
  153. if (void 0 !== _take) {
  154. result.$top = _take
  155. }
  156. result.$select = odataUtils.generateSelect(_oDataVersion, _select) || void 0;
  157. result.$expand = odataUtils.generateExpand(_oDataVersion, _expand, _select) || void 0
  158. }
  159. if (_criteria.length) {
  160. var criteria = _criteria.length < 2 ? _criteria[0] : _criteria;
  161. var fieldTypes = queryOptions && queryOptions.fieldTypes;
  162. var filterToLower = queryOptions && queryOptions.filterToLower;
  163. result.$filter = compileCriteria(criteria, _oDataVersion, fieldTypes, filterToLower)
  164. }
  165. if (_countQuery) {
  166. result.$top = 0
  167. }
  168. if (queryOptions.requireTotalCount || _countQuery) {
  169. if (4 !== _oDataVersion) {
  170. result.$inlinecount = "allpages"
  171. } else {
  172. result.$count = "true"
  173. }
  174. }
  175. return result
  176. };
  177. function tryLiftSelect(tasks) {
  178. var selectIndex = -1;
  179. for (var i = 0; i < tasks.length; i++) {
  180. if ("select" === tasks[i].name) {
  181. selectIndex = i;
  182. break
  183. }
  184. }
  185. if (selectIndex < 0 || !isFunction(tasks[selectIndex].args[0])) {
  186. return
  187. }
  188. var nextTask = tasks[1 + selectIndex];
  189. if (!nextTask || "slice" !== nextTask.name) {
  190. return
  191. }
  192. tasks[1 + selectIndex] = tasks[selectIndex];
  193. tasks[selectIndex] = nextTask
  194. }
  195. return {
  196. optimize: function(tasks) {
  197. tryLiftSelect(tasks)
  198. },
  199. exec: function(url) {
  200. return odataUtils.sendRequest(_oDataVersion, {
  201. url: url,
  202. params: extend(requestData(), queryOptions && queryOptions.params)
  203. }, {
  204. beforeSend: queryOptions.beforeSend,
  205. jsonp: queryOptions.jsonp,
  206. withCredentials: queryOptions.withCredentials,
  207. countOnly: _countQuery,
  208. deserializeDates: queryOptions.deserializeDates,
  209. fieldTypes: queryOptions.fieldTypes,
  210. isPaged: isFinite(_take)
  211. })
  212. },
  213. multiSort: function(args) {
  214. var rules;
  215. if (hasSlice()) {
  216. return false
  217. }
  218. for (var i = 0; i < args.length; i++) {
  219. var getter = args[i][0];
  220. var desc = !!args[i][1];
  221. var rule;
  222. if ("string" !== typeof getter) {
  223. return false
  224. }
  225. rule = serializePropName(getter);
  226. if (desc) {
  227. rule += " desc"
  228. }
  229. rules = rules || [];
  230. rules.push(rule)
  231. }
  232. _sorting = rules
  233. },
  234. slice: function(skipCount, takeCount) {
  235. if (hasSlice()) {
  236. return false
  237. }
  238. _skip = skipCount;
  239. _take = takeCount
  240. },
  241. filter: function(criterion) {
  242. if (hasSlice()) {
  243. return false
  244. }
  245. if (!Array.isArray(criterion)) {
  246. criterion = [].slice.call(arguments)
  247. }
  248. if (hasFunction(criterion)) {
  249. return false
  250. }
  251. if (_criteria.length) {
  252. _criteria.push("and")
  253. }
  254. _criteria.push(criterion)
  255. },
  256. select: function(expr) {
  257. if (_select || isFunction(expr)) {
  258. return false
  259. }
  260. if (!Array.isArray(expr)) {
  261. expr = [].slice.call(arguments)
  262. }
  263. _select = expr
  264. },
  265. count: function() {
  266. _countQuery = true
  267. }
  268. }
  269. };
  270. queryAdapters.odata = createODataQueryAdapter;
  271. exports.odata = createODataQueryAdapter;