utils.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /**
  2. * DevExtreme (data/odata/utils.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. function _typeof(obj) {
  11. "@babel/helpers - typeof";
  12. return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
  13. return typeof obj
  14. } : function(obj) {
  15. return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
  16. }, _typeof(obj)
  17. }
  18. var Class = require("../../core/class");
  19. var extend = require("../../core/utils/extend").extend;
  20. var typeUtils = require("../../core/utils/type");
  21. var iteratorUtils = require("../../core/utils/iterator");
  22. var each = require("../../core/utils/iterator").each;
  23. var ajax = require("../../core/utils/ajax");
  24. var _Guid = require("../../core/guid");
  25. var isDefined = typeUtils.isDefined;
  26. var isPlainObject = typeUtils.isPlainObject;
  27. var grep = require("../../core/utils/common").grep;
  28. var Deferred = require("../../core/utils/deferred").Deferred;
  29. var errors = require("../errors").errors;
  30. var dataUtils = require("../utils");
  31. var GUID_REGEX = /^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$/;
  32. var VERBOSE_DATE_REGEX = /^\/Date\((-?\d+)((\+|-)?(\d+)?)\)\/$/;
  33. var ISO8601_DATE_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[-+]{1}\d{2}(:?)(\d{2})?)?$/;
  34. var JSON_VERBOSE_MIME_TYPE = "application/json;odata=verbose";
  35. var makeArray = function(value) {
  36. return "string" === typeUtils.type(value) ? value.split() : value
  37. };
  38. var hasDot = function(x) {
  39. return /\./.test(x)
  40. };
  41. var pad = function(text, length, right) {
  42. text = String(text);
  43. while (text.length < length) {
  44. text = right ? text + "0" : "0" + text
  45. }
  46. return text
  47. };
  48. function formatISO8601(date, skipZeroTime, skipTimezone) {
  49. var bag = [];
  50. var isZeroTime = function() {
  51. return date.getHours() + date.getMinutes() + date.getSeconds() + date.getMilliseconds() < 1
  52. };
  53. var padLeft2 = function(text) {
  54. return pad(text, 2)
  55. };
  56. bag.push(date.getFullYear());
  57. bag.push("-");
  58. bag.push(padLeft2(date.getMonth() + 1));
  59. bag.push("-");
  60. bag.push(padLeft2(date.getDate()));
  61. if (!(skipZeroTime && isZeroTime())) {
  62. bag.push("T");
  63. bag.push(padLeft2(date.getHours()));
  64. bag.push(":");
  65. bag.push(padLeft2(date.getMinutes()));
  66. bag.push(":");
  67. bag.push(padLeft2(date.getSeconds()));
  68. if (date.getMilliseconds()) {
  69. bag.push(".");
  70. bag.push(pad(date.getMilliseconds(), 3))
  71. }
  72. if (!skipTimezone) {
  73. bag.push("Z")
  74. }
  75. }
  76. return bag.join("")
  77. }
  78. function parseISO8601(isoString) {
  79. var result = new Date(60 * new Date(0).getTimezoneOffset() * 1e3);
  80. var chunks = isoString.replace("Z", "").split("T");
  81. var date = /(\d{4})-(\d{2})-(\d{2})/.exec(chunks[0]);
  82. var time = /(\d{2}):(\d{2}):(\d{2})\.?(\d{0,7})?/.exec(chunks[1]);
  83. result.setFullYear(Number(date[1]));
  84. result.setMonth(Number(date[2]) - 1);
  85. result.setDate(Number(date[3]));
  86. if (Array.isArray(time) && time.length) {
  87. result.setHours(Number(time[1]));
  88. result.setMinutes(Number(time[2]));
  89. result.setSeconds(Number(time[3]));
  90. var fractional = (time[4] || "").slice(0, 3);
  91. fractional = pad(fractional, 3, true);
  92. result.setMilliseconds(Number(fractional))
  93. }
  94. return result
  95. }
  96. function isAbsoluteUrl(url) {
  97. return /^(?:[a-z]+:)?\/\//i.test(url)
  98. }
  99. function toAbsoluteUrl(basePath, relativePath) {
  100. var part;
  101. var baseParts = stripParams(basePath).split("/");
  102. var relativeParts = relativePath.split("/");
  103. function stripParams(url) {
  104. var index = url.indexOf("?");
  105. if (index > -1) {
  106. return url.substr(0, index)
  107. }
  108. return url
  109. }
  110. baseParts.pop();
  111. while (relativeParts.length) {
  112. part = relativeParts.shift();
  113. if (".." === part) {
  114. baseParts.pop()
  115. } else {
  116. baseParts.push(part)
  117. }
  118. }
  119. return baseParts.join("/")
  120. }
  121. var param = function(params) {
  122. var result = [];
  123. for (var name in params) {
  124. result.push(name + "=" + params[name])
  125. }
  126. return result.join("&")
  127. };
  128. var ajaxOptionsForRequest = function(protocolVersion, request, options) {
  129. request = extend({
  130. async: true,
  131. method: "get",
  132. url: "",
  133. params: {},
  134. payload: null,
  135. headers: {},
  136. timeout: 3e4
  137. }, request);
  138. options = options || {};
  139. var beforeSend = options.beforeSend;
  140. if (beforeSend) {
  141. beforeSend(request)
  142. }
  143. var method = (request.method || "get").toLowerCase();
  144. var isGet = "get" === method;
  145. var useJsonp = isGet && options.jsonp;
  146. var params = extend({}, request.params);
  147. var ajaxData = isGet ? params : formatPayload(request.payload);
  148. var qs = !isGet && param(params);
  149. var url = request.url;
  150. var contentType = !isGet && JSON_VERBOSE_MIME_TYPE;
  151. if (qs) {
  152. url += (url.indexOf("?") > -1 ? "&" : "?") + qs
  153. }
  154. if (useJsonp) {
  155. ajaxData.$format = "json"
  156. }
  157. return {
  158. url: url,
  159. data: ajaxData,
  160. dataType: useJsonp ? "jsonp" : "json",
  161. jsonp: useJsonp && "$callback",
  162. method: method,
  163. async: request.async,
  164. timeout: request.timeout,
  165. headers: request.headers,
  166. contentType: contentType,
  167. accepts: {
  168. json: [JSON_VERBOSE_MIME_TYPE, "text/plain"].join()
  169. },
  170. xhrFields: {
  171. withCredentials: options.withCredentials
  172. }
  173. };
  174. function formatPayload(payload) {
  175. return JSON.stringify(payload, function(key, value) {
  176. if (!(this[key] instanceof Date)) {
  177. return value
  178. }
  179. value = formatISO8601(this[key]);
  180. switch (protocolVersion) {
  181. case 2:
  182. return value.substr(0, value.length - 1);
  183. case 3:
  184. case 4:
  185. return value;
  186. default:
  187. throw errors.Error("E4002")
  188. }
  189. })
  190. }
  191. };
  192. var sendRequest = function sendRequest(protocolVersion, request, options) {
  193. var d = new Deferred;
  194. var ajaxOptions = ajaxOptionsForRequest(protocolVersion, request, options);
  195. ajax.sendRequest(ajaxOptions).always(function(obj, textStatus) {
  196. var transformOptions = {
  197. deserializeDates: options.deserializeDates,
  198. fieldTypes: options.fieldTypes
  199. };
  200. var tuple = interpretJsonFormat(obj, textStatus, transformOptions, ajaxOptions);
  201. var error = tuple.error;
  202. var data = tuple.data;
  203. var nextUrl = tuple.nextUrl;
  204. var extra;
  205. if (error) {
  206. if (error.message !== dataUtils.XHR_ERROR_UNLOAD) {
  207. d.reject(error)
  208. }
  209. } else {
  210. if (options.countOnly) {
  211. if (isFinite(tuple.count)) {
  212. d.resolve(tuple.count)
  213. } else {
  214. d.reject(new errors.Error("E4018"))
  215. }
  216. } else {
  217. if (nextUrl && !options.isPaged) {
  218. if (!isAbsoluteUrl(nextUrl)) {
  219. nextUrl = toAbsoluteUrl(ajaxOptions.url, nextUrl)
  220. }
  221. sendRequest(protocolVersion, {
  222. url: nextUrl
  223. }, options).fail(d.reject).done(function(nextData) {
  224. d.resolve(data.concat(nextData))
  225. })
  226. } else {
  227. if (isFinite(tuple.count)) {
  228. extra = {
  229. totalCount: tuple.count
  230. }
  231. }
  232. d.resolve(data, extra)
  233. }
  234. }
  235. }
  236. });
  237. return d.promise()
  238. };
  239. var formatDotNetError = function(errorObj) {
  240. var message;
  241. var currentError = errorObj;
  242. if ("message" in errorObj) {
  243. if (errorObj.message.value) {
  244. message = errorObj.message.value
  245. } else {
  246. message = errorObj.message
  247. }
  248. }
  249. while (currentError = currentError.innererror || currentError.internalexception) {
  250. message = currentError.message;
  251. if (currentError.internalexception && message.indexOf("inner exception") === -1) {
  252. break
  253. }
  254. }
  255. return message
  256. };
  257. var errorFromResponse = function(obj, textStatus, ajaxOptions) {
  258. if ("nocontent" === textStatus) {
  259. return null
  260. }
  261. var message = "Unknown error";
  262. var response = obj;
  263. var httpStatus = 200;
  264. var errorData = {
  265. requestOptions: ajaxOptions
  266. };
  267. if ("success" !== textStatus) {
  268. httpStatus = obj.status;
  269. message = dataUtils.errorMessageFromXhr(obj, textStatus);
  270. try {
  271. response = JSON.parse(obj.responseText)
  272. } catch (x) {}
  273. }
  274. var errorObj = response && (response.then && response || response.error || response["odata.error"] || response["@odata.error"]);
  275. if (errorObj) {
  276. message = formatDotNetError(errorObj) || message;
  277. errorData.errorDetails = errorObj;
  278. if (200 === httpStatus) {
  279. httpStatus = 500
  280. }
  281. var customCode = Number(errorObj.code);
  282. if (isFinite(customCode) && customCode >= 400) {
  283. httpStatus = customCode
  284. }
  285. }
  286. if (httpStatus >= 400 || 0 === httpStatus) {
  287. errorData.httpStatus = httpStatus;
  288. return extend(Error(message), errorData)
  289. }
  290. return null
  291. };
  292. var interpretJsonFormat = function(obj, textStatus, transformOptions, ajaxOptions) {
  293. var error = errorFromResponse(obj, textStatus, ajaxOptions);
  294. var value;
  295. if (error) {
  296. return {
  297. error: error
  298. }
  299. }
  300. if (!isPlainObject(obj)) {
  301. return {
  302. data: obj
  303. }
  304. }
  305. if ("d" in obj && (Array.isArray(obj.d) || typeUtils.isObject(obj.d))) {
  306. value = interpretVerboseJsonFormat(obj, textStatus)
  307. } else {
  308. value = interpretLightJsonFormat(obj, textStatus)
  309. }
  310. transformTypes(value, transformOptions);
  311. return value
  312. };
  313. var interpretVerboseJsonFormat = function(obj) {
  314. var data = obj.d;
  315. if (!isDefined(data)) {
  316. return {
  317. error: Error("Malformed or unsupported JSON response received")
  318. }
  319. }
  320. if (isDefined(data.results)) {
  321. data = data.results
  322. }
  323. return {
  324. data: data,
  325. nextUrl: obj.d.__next,
  326. count: parseInt(obj.d.__count, 10)
  327. }
  328. };
  329. var interpretLightJsonFormat = function(obj) {
  330. var data = obj;
  331. if (isDefined(data.value)) {
  332. data = data.value
  333. }
  334. return {
  335. data: data,
  336. nextUrl: obj["@odata.nextLink"],
  337. count: parseInt(obj["@odata.count"], 10)
  338. }
  339. };
  340. var EdmLiteral = Class.inherit({
  341. ctor: function(value) {
  342. this._value = value
  343. },
  344. valueOf: function() {
  345. return this._value
  346. }
  347. });
  348. var transformTypes = function transformTypes(obj, options) {
  349. options = options || {};
  350. each(obj, function(key, value) {
  351. if (null !== value && "object" === _typeof(value)) {
  352. if ("results" in value) {
  353. obj[key] = value.results
  354. }
  355. transformTypes(obj[key], options)
  356. } else {
  357. if ("string" === typeof value) {
  358. var fieldTypes = options.fieldTypes;
  359. var canBeGuid = !fieldTypes || "String" !== fieldTypes[key];
  360. if (canBeGuid && GUID_REGEX.test(value)) {
  361. obj[key] = new _Guid(value)
  362. }
  363. if (false !== options.deserializeDates) {
  364. if (value.match(VERBOSE_DATE_REGEX)) {
  365. var date = new Date(Number(RegExp.$1) + 60 * RegExp.$2 * 1e3);
  366. obj[key] = new Date(date.valueOf() + 60 * date.getTimezoneOffset() * 1e3)
  367. } else {
  368. if (ISO8601_DATE_REGEX.test(value)) {
  369. obj[key] = new Date(parseISO8601(obj[key]).valueOf())
  370. }
  371. }
  372. }
  373. }
  374. }
  375. })
  376. };
  377. var serializeDate = function(date) {
  378. return "datetime'" + formatISO8601(date, true, true) + "'"
  379. };
  380. var serializeString = function(value) {
  381. return "'" + value.replace(/'/g, "''") + "'"
  382. };
  383. var serializePropName = function(propName) {
  384. if (propName instanceof EdmLiteral) {
  385. return propName.valueOf()
  386. }
  387. return propName.replace(/\./g, "/")
  388. };
  389. var serializeValueV4 = function serializeValueV4(value) {
  390. if (value instanceof Date) {
  391. return formatISO8601(value, false, false)
  392. }
  393. if (value instanceof _Guid) {
  394. return value.valueOf()
  395. }
  396. if (Array.isArray(value)) {
  397. return "[" + value.map(function(item) {
  398. return serializeValueV4(item)
  399. }).join(",") + "]"
  400. }
  401. return serializeValueV2(value)
  402. };
  403. var serializeValueV2 = function(value) {
  404. if (value instanceof Date) {
  405. return serializeDate(value)
  406. }
  407. if (value instanceof _Guid) {
  408. return "guid'" + value + "'"
  409. }
  410. if (value instanceof EdmLiteral) {
  411. return value.valueOf()
  412. }
  413. if ("string" === typeof value) {
  414. return serializeString(value)
  415. }
  416. return String(value)
  417. };
  418. var serializeValue = function(value, protocolVersion) {
  419. switch (protocolVersion) {
  420. case 2:
  421. case 3:
  422. return serializeValueV2(value);
  423. case 4:
  424. return serializeValueV4(value);
  425. default:
  426. throw errors.Error("E4002")
  427. }
  428. };
  429. var serializeKey = function(key, protocolVersion) {
  430. if (isPlainObject(key)) {
  431. var parts = [];
  432. each(key, function(k, v) {
  433. parts.push(serializePropName(k) + "=" + serializeValue(v, protocolVersion))
  434. });
  435. return parts.join()
  436. }
  437. return serializeValue(key, protocolVersion)
  438. };
  439. var keyConverters = {
  440. String: function(value) {
  441. return value + ""
  442. },
  443. Int32: function(value) {
  444. return Math.floor(value)
  445. },
  446. Int64: function(value) {
  447. if (value instanceof EdmLiteral) {
  448. return value
  449. }
  450. return new EdmLiteral(value + "L")
  451. },
  452. Guid: function(value) {
  453. if (value instanceof _Guid) {
  454. return value
  455. }
  456. return new _Guid(value)
  457. },
  458. Boolean: function(value) {
  459. return !!value
  460. },
  461. Single: function(value) {
  462. if (value instanceof EdmLiteral) {
  463. return value
  464. }
  465. return new EdmLiteral(value + "f")
  466. },
  467. Decimal: function(value) {
  468. if (value instanceof EdmLiteral) {
  469. return value
  470. }
  471. return new EdmLiteral(value + "m")
  472. }
  473. };
  474. var convertPrimitiveValue = function(type, value) {
  475. if (null === value) {
  476. return null
  477. }
  478. var converter = keyConverters[type];
  479. if (!converter) {
  480. throw errors.Error("E4014", type)
  481. }
  482. return converter(value)
  483. };
  484. var generateSelect = function(oDataVersion, select) {
  485. if (!select) {
  486. return
  487. }
  488. if (oDataVersion < 4) {
  489. return serializePropName(select.join())
  490. }
  491. return grep(select, hasDot, true).join()
  492. };
  493. var generateExpand = function(oDataVersion, expand, select) {
  494. var generatorV2 = function() {
  495. var hash = {};
  496. if (expand) {
  497. iteratorUtils.each(makeArray(expand), function() {
  498. hash[serializePropName(this)] = 1
  499. })
  500. }
  501. if (select) {
  502. iteratorUtils.each(makeArray(select), function() {
  503. var path = this.split(".");
  504. if (path.length < 2) {
  505. return
  506. }
  507. path.pop();
  508. hash[serializePropName(path.join("."))] = 1
  509. })
  510. }
  511. return iteratorUtils.map(hash, function(k, v) {
  512. return v
  513. }).join()
  514. };
  515. var generatorV4 = function() {
  516. var format = function(hash) {
  517. var formatCore = function formatCore(hash) {
  518. var result = "";
  519. var selectValue = [];
  520. var expandValue = [];
  521. iteratorUtils.each(hash, function(key, value) {
  522. if (Array.isArray(value)) {
  523. [].push.apply(selectValue, value)
  524. }
  525. if (isPlainObject(value)) {
  526. expandValue.push(key + formatCore(value))
  527. }
  528. });
  529. if (selectValue.length || expandValue.length) {
  530. result += "(";
  531. if (selectValue.length) {
  532. result += "$select=" + iteratorUtils.map(selectValue, serializePropName).join()
  533. }
  534. if (expandValue.length) {
  535. if (selectValue.length) {
  536. result += ";"
  537. }
  538. result += "$expand=" + iteratorUtils.map(expandValue, serializePropName).join()
  539. }
  540. result += ")"
  541. }
  542. return result
  543. };
  544. var result = [];
  545. iteratorUtils.each(hash, function(key, value) {
  546. result.push(key + formatCore(value))
  547. });
  548. return result.join()
  549. };
  550. var parseTree = function(exprs, root, stepper) {
  551. var parseCore = function parseCore(exprParts, root, stepper) {
  552. var result = stepper(root, exprParts.shift(), exprParts);
  553. if (false === result) {
  554. return
  555. }
  556. parseCore(exprParts, result, stepper)
  557. };
  558. iteratorUtils.each(exprs, function(_, x) {
  559. parseCore(x.split("."), root, stepper)
  560. })
  561. };
  562. var hash = {};
  563. if (expand || select) {
  564. if (expand) {
  565. parseTree(makeArray(expand), hash, function(node, key, path) {
  566. node[key] = node[key] || {};
  567. if (!path.length) {
  568. return false
  569. }
  570. return node[key]
  571. })
  572. }
  573. if (select) {
  574. parseTree(grep(makeArray(select), hasDot), hash, function(node, key, path) {
  575. if (!path.length) {
  576. node[key] = node[key] || [];
  577. node[key].push(key);
  578. return false
  579. }
  580. return node[key] = node[key] || {}
  581. })
  582. }
  583. return format(hash)
  584. }
  585. };
  586. if (oDataVersion < 4) {
  587. return generatorV2()
  588. }
  589. return generatorV4()
  590. };
  591. exports.sendRequest = sendRequest;
  592. exports.serializePropName = serializePropName;
  593. exports.serializeValue = serializeValue;
  594. exports.serializeKey = serializeKey;
  595. exports.keyConverters = keyConverters;
  596. exports.convertPrimitiveValue = convertPrimitiveValue;
  597. exports.generateExpand = generateExpand;
  598. exports.generateSelect = generateSelect;
  599. exports.EdmLiteral = EdmLiteral;