@nextgis/ngw-connector 1.9.2 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /** Bundle of @nextgis/ngw-connector; version: 1.9.2; author: NextGIS */
1
+ /** Bundle of @nextgis/ngw-connector; version: 1.11.2; author: NextGIS */
2
2
  var events = {exports: {}};
3
3
 
4
4
  var R = typeof Reflect === 'object' ? Reflect : null;
@@ -832,6 +832,23 @@ var CancelablePromise = CancelablePromise$1;
832
832
  */
833
833
  function defined(val) {
834
834
  return val !== undefined && val !== null;
835
+ }
836
+ /**
837
+ * from https://github.com/CesiumGS/cesium/blob/master/Source/Core/defined.js
838
+ *
839
+ * @param val - The object.
840
+ * @returns Returns true if the object is defined and not empty string, returns false otherwise.
841
+ *
842
+ * @example
843
+ * ```javascript
844
+ * full('foo') // true
845
+ * full('') // false
846
+ * full(undefined) // false
847
+ * full(0) // true
848
+ * ```
849
+ */
850
+ function full(val) {
851
+ return typeof val === 'string' ? !!val : defined(val);
835
852
  }
836
853
 
837
854
  function isEqual(a, b, o, p) {
@@ -900,13 +917,45 @@ function fixUrlStr(url) {
900
917
  return url.replace(/([^:]\/)\/+/g, '$1');
901
918
  }
902
919
 
920
+ /**
921
+ * @example
922
+ * ```javascript
923
+ * const cache1 = new Cache();
924
+ * cache1.add('foo', 'value');
925
+ *
926
+ * const cache2 = new Cache();
927
+ * cache2.match('foo'); // value
928
+ *
929
+ * const cache3 = new Cache({ namespace: 'foo' });
930
+ * cache3.match('foo'); // undefined
931
+ * ```
932
+ *
933
+ * @example
934
+ * ```javascript
935
+ * let COUNTER = 0;
936
+ * const createPromise = () => new Promise((res) => {
937
+ * COUNTER++
938
+ * setTimeout(() => res('Ok'), 300)
939
+ * });
940
+ *
941
+ * const cache = new Cache();
942
+ * for (let i = 0; i < 10; i++) {
943
+ * cache.add('foo', createPromise).then((data) => {
944
+ * console.log(data); // 'Ok'
945
+ * });
946
+ * }
947
+ * console.log(COUNTER); // 1
948
+ * ```
949
+ */
903
950
  class Cache$1 {
904
- constructor() {
951
+ constructor(options = {}) {
952
+ var _a;
905
953
  this.cache = [];
906
- if (Cache$1.instance) {
907
- return Cache$1.instance;
954
+ const namespace = (_a = options.namespace) !== null && _a !== void 0 ? _a : 'default';
955
+ if (Cache$1.instance[namespace]) {
956
+ return Cache$1.instance[namespace];
908
957
  }
909
- Cache$1.instance = this;
958
+ Cache$1.instance[namespace] = this;
910
959
  return this;
911
960
  }
912
961
  clean() {
@@ -915,8 +964,33 @@ class Cache$1 {
915
964
  all() {
916
965
  return this.cache;
917
966
  }
918
- add(key, valueToSet, options) {
919
- const exist = this._find(key, options);
967
+ /**
968
+ * Caching only a non-empty value.
969
+ *
970
+ * Useful for get or create strategy
971
+ * @example
972
+ * ```javascript
973
+ * const cache = new Cache();
974
+ * const getItemFunc = () => fetch(url).then((data) => {
975
+ * return data.json(); // undefined
976
+ * });
977
+ * const item = await cache.addFull('foo', getItemFunc);
978
+ * if (!item) {
979
+ * await createItem(); // 'New item'
980
+ * }
981
+ *
982
+ * // somewhere else in the code
983
+ * const item = await cache.addFull('foo', getItemFunc).then((resp) => {
984
+ * console.log(resp); // 'New item'
985
+ * })
986
+ *
987
+ * ```
988
+ */
989
+ addFull(key, valueToSet, props) {
990
+ return this.add(key, valueToSet, props, true);
991
+ }
992
+ add(key, valueToSet, props, onlyFull) {
993
+ const exist = this._find(key, props);
920
994
  if (!exist) {
921
995
  let value;
922
996
  if (valueToSet instanceof Function) {
@@ -925,18 +999,31 @@ class Cache$1 {
925
999
  else {
926
1000
  value = valueToSet;
927
1001
  }
928
- const options_ = options && JSON.parse(JSON.stringify(objectRemoveEmpty(options)));
1002
+ const props_ = props && JSON.parse(JSON.stringify(objectRemoveEmpty(props)));
929
1003
  const cacheItem = {
930
1004
  key,
931
1005
  value,
932
- options: options_,
1006
+ props: props_,
1007
+ // TODO: remove backward compatibility use only props
1008
+ options: props_,
933
1009
  };
1010
+ if (onlyFull && !full(value)) {
1011
+ return value;
1012
+ }
934
1013
  this.cache.push(cacheItem);
935
1014
  if (value instanceof Promise) {
936
1015
  value.catch((er) => {
937
- this.delete(key, options);
1016
+ this.delete(key, props);
938
1017
  throw er;
939
1018
  });
1019
+ if (onlyFull) {
1020
+ value.then((x) => {
1021
+ if (!full(x)) {
1022
+ this.delete(key, props);
1023
+ }
1024
+ return x;
1025
+ });
1026
+ }
940
1027
  return value;
941
1028
  }
942
1029
  return value;
@@ -945,40 +1032,49 @@ class Cache$1 {
945
1032
  return exist.value;
946
1033
  }
947
1034
  }
948
- match(key, options) {
949
- const cacheRecord = this._find(key, options);
1035
+ match(key, props) {
1036
+ const cacheRecord = this._find(key, props);
950
1037
  if (cacheRecord) {
951
1038
  return cacheRecord.value;
952
1039
  }
953
1040
  }
954
- matchAll(key, options) {
1041
+ matchAll(key, props) {
955
1042
  if (key) {
956
1043
  return this.cache
957
- .filter((x) => this._filter(x, key, options))
1044
+ .filter((x) => this._filter(x, key, props))
958
1045
  .map((x) => x.value);
959
1046
  }
960
1047
  return this.cache.map((x) => x.value);
961
1048
  }
962
- delete(key, options) {
963
- const exist = this.cache.filter((x) => this._filter(x, key, options));
1049
+ delete(keyOrItem, props) {
1050
+ let exist = [];
1051
+ if (typeof keyOrItem === 'string') {
1052
+ exist = this.cache.filter((x) => this._filter(x, keyOrItem, props));
1053
+ }
1054
+ else {
1055
+ exist.push(keyOrItem);
1056
+ }
964
1057
  for (const e of exist) {
965
1058
  const index = this.cache.indexOf(e);
966
1059
  this.cache.splice(index, 1);
967
1060
  }
968
1061
  }
969
- _find(key, options) {
970
- return this.cache.find((x) => this._filter(x, key, options));
1062
+ _find(key, props) {
1063
+ return this.cache.find((x) => this._filter(x, key, props));
971
1064
  }
972
- _filter(item, key, options) {
1065
+ _filter(item, key, props) {
973
1066
  if (item.key === key) {
974
- if (options) {
975
- return objectDeepEqual(item.options || {}, objectRemoveEmpty(options));
1067
+ if (props) {
1068
+ // TODO: remove backward compatibility
1069
+ const itemProps = item.props || item.options;
1070
+ return objectDeepEqual(itemProps || {}, objectRemoveEmpty(props));
976
1071
  }
977
1072
  return true;
978
1073
  }
979
1074
  return false;
980
1075
  }
981
- }
1076
+ }
1077
+ Cache$1.instance = {};
982
1078
 
983
1079
  /**
984
1080
  * Caching for asynchronous functions
@@ -1013,6 +1109,10 @@ class NetworkError extends Error {
1013
1109
  }
1014
1110
  }
1015
1111
 
1112
+ function isObject(val) {
1113
+ return Object.prototype.toString.call(val) === '[object Object]';
1114
+ }
1115
+
1016
1116
  let loadData;
1017
1117
  // @ts-ignore
1018
1118
  {
@@ -1046,7 +1146,7 @@ let loadData;
1046
1146
  }
1047
1147
  };
1048
1148
  xhr.onload = () => {
1049
- if ([401, 403, 404, 500].indexOf(xhr.status) !== -1) {
1149
+ if ([401, 403, 404, 422, 500].indexOf(xhr.status) !== -1) {
1050
1150
  error(new NgwError(getResponseText()));
1051
1151
  }
1052
1152
  processingResponse();
@@ -1101,7 +1201,7 @@ let loadData;
1101
1201
  data = new FormData();
1102
1202
  data.append('file', options.file);
1103
1203
  if (options.data) {
1104
- for (const d in data) {
1204
+ for (const d in options.data) {
1105
1205
  data.append(d, data[d]);
1106
1206
  }
1107
1207
  }
@@ -1187,28 +1287,36 @@ function removeConnector(connector) {
1187
1287
  }
1188
1288
  }
1189
1289
 
1190
- function isObject(val) {
1191
- return Object.prototype.toString.call(val) === '[object Object]';
1192
- }
1193
-
1290
+ const exclude = ['description'];
1194
1291
  /**
1292
+ * @remarks
1293
+ * https://docs.nextgis.ru/docs_ngweb_dev/doc/developer/resource.html#search-resources
1294
+ *
1195
1295
  * ```
1196
- * { keyname, parent: { id }} > { keyname, parent__id }
1296
+ * { keyname, owner_user: { id }} > { keyname, owner_user__id }
1197
1297
  * ```
1298
+ *
1198
1299
  * @param resource - Any property from NGW resource item
1199
1300
  */
1200
1301
  function resourceToQuery(resource, prefix = '') {
1201
1302
  prefix = prefix ? prefix + '__' : '';
1202
1303
  const query = {};
1203
- Object.entries(resource).forEach(([key, value]) => {
1204
- if (isObject(value)) {
1205
- const children = resourceToQuery(value, key);
1206
- Object.assign(query, children);
1207
- }
1208
- else if (defined(value)) {
1209
- query[prefix + key] = value;
1304
+ for (const [key, value] of Object.entries(resource)) {
1305
+ if (exclude.indexOf(key) === -1) {
1306
+ if (isObject(value)) {
1307
+ if (key === 'owner_user') {
1308
+ const children = resourceToQuery(value, key);
1309
+ Object.assign(query, children);
1310
+ }
1311
+ else if (key === 'parent' && 'id' in value) {
1312
+ query.parent_id = value.id;
1313
+ }
1314
+ }
1315
+ else if (defined(value)) {
1316
+ query[prefix + key] = value;
1317
+ }
1210
1318
  }
1211
- });
1319
+ }
1212
1320
  return query;
1213
1321
  }
1214
1322
 
@@ -1233,19 +1341,30 @@ class ResourcesControl {
1233
1341
  */
1234
1342
  getOne(resource, requestOptions) {
1235
1343
  const cache = new Cache();
1344
+ const forCache = {};
1345
+ const opt = { ...requestOptions, cache: false };
1346
+ if (typeof resource === 'string') {
1347
+ forCache.keyname = resource;
1348
+ }
1349
+ else if (typeof resource === 'number') {
1350
+ forCache.id = resource;
1351
+ }
1352
+ else if (isObject(resource)) {
1353
+ forCache.id = resource.id;
1354
+ }
1236
1355
  const makeRequest = () => {
1237
1356
  if (typeof resource === 'string') {
1238
- return this._fetchResourceBy({ keyname: resource }, requestOptions);
1357
+ return this._fetchResourceBy({ keyname: resource }, opt);
1239
1358
  }
1240
1359
  else if (typeof resource === 'number') {
1241
- return this._fetchResourceById(resource, requestOptions);
1360
+ return this._fetchResourceById(resource, opt);
1242
1361
  }
1243
1362
  else if (isObject(resource)) {
1244
- return this._fetchResourceBy(resource, requestOptions);
1363
+ return this._fetchResourceBy(resource, opt);
1245
1364
  }
1246
1365
  return CancelablePromise.resolve(undefined);
1247
1366
  };
1248
- return cache.add('resource', makeRequest, { resource });
1367
+ return cache.addFull('resource', makeRequest, forCache);
1249
1368
  }
1250
1369
  getOneOrFail(resource, requestOptions) {
1251
1370
  return this.getOne(resource, requestOptions).then((res) => {
@@ -1311,11 +1430,11 @@ class ResourcesControl {
1311
1430
  })
1312
1431
  .then((resources) => {
1313
1432
  if (resources) {
1314
- resources.forEach((x) => {
1433
+ for (const x of resources) {
1315
1434
  this.cache.add('resource.item', CancelablePromise.resolve(x), {
1316
1435
  id: x.resource.id,
1317
1436
  });
1318
- });
1437
+ }
1319
1438
  }
1320
1439
  return resources;
1321
1440
  });
@@ -1362,12 +1481,35 @@ class ResourcesControl {
1362
1481
  return this.getId(resource).then((id) => {
1363
1482
  if (id !== undefined) {
1364
1483
  return this.connector.delete('resource.item', null, { id }).then(() => {
1365
- this.cache.delete('resource.item', { id });
1484
+ this._cleanResourceItemCache(id);
1366
1485
  return undefined;
1367
1486
  });
1368
1487
  }
1369
1488
  });
1370
1489
  }
1490
+ async _cleanResourceItemCache(id) {
1491
+ const all = this.cache.all();
1492
+ const toDelete = [];
1493
+ for (const c of all) {
1494
+ const cid = c.options && c.options.id;
1495
+ if (['resource.item', 'resource'].includes(c.key) && cid !== undefined) {
1496
+ if (typeof cid === 'number') {
1497
+ if (cid === id) {
1498
+ toDelete.push(c);
1499
+ }
1500
+ }
1501
+ else {
1502
+ const rid = await this.getId(cid);
1503
+ if (rid === id) {
1504
+ toDelete.push(c);
1505
+ }
1506
+ }
1507
+ }
1508
+ }
1509
+ for (const d of toDelete) {
1510
+ this.cache.delete(d);
1511
+ }
1512
+ }
1371
1513
  _fetchResourceById(id, requestOptions) {
1372
1514
  const promise = () => this.connector.get('resource.item', requestOptions, { id });
1373
1515
  return this.cache
@@ -1571,7 +1713,7 @@ class NgwConnector$1 {
1571
1713
  headers: this.getAuthorizationHeaders(credentials),
1572
1714
  // withCredentials: true
1573
1715
  };
1574
- // Do not use request('auth.current_user') to avoid circular-references
1716
+ // Do not use apiRequest('auth.current_user') to avoid circular-references
1575
1717
  return this.makeQuery('/api/component/auth/current_user', {}, options)
1576
1718
  .then((data) => {
1577
1719
  this.user = data;
@@ -1729,7 +1871,7 @@ class NgwConnector$1 {
1729
1871
  }
1730
1872
  // remove double slash
1731
1873
  url = fixUrlStr(url);
1732
- return this._loadData(url, options);
1874
+ return this._loadData(encodeURI(url), options);
1733
1875
  }
1734
1876
  else {
1735
1877
  throw new Error('Empty `url` not allowed');
@@ -1830,7 +1972,7 @@ class NgwConnector$1 {
1830
1972
  else {
1831
1973
  // @ts-ignore
1832
1974
  {
1833
- console.warn(httpError);
1975
+ console.warn('DEV WARN', httpError);
1834
1976
  }
1835
1977
  const er = this._handleHttpError(httpError);
1836
1978
  if (er) {