@epam/uui-db 5.3.0-rc.0 → 5.3.0

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.
Files changed (103) hide show
  1. package/benchmark/results/filter.json +39 -0
  2. package/benchmark/results/pkLookup.json +39 -0
  3. package/benchmark/results/pkUpdate-10.json +51 -0
  4. package/benchmark/results/pkUpdate-100.json +51 -0
  5. package/benchmark/results/pkUpdate-1000.json +51 -0
  6. package/benchmark/results/pkUpdate-10000.json +51 -0
  7. package/benchmark/results/pkUpdate-100000.json +51 -0
  8. package/benchmark/results/pkUpdate-1000000.json +51 -0
  9. package/benchmark/results/query-10.json +63 -0
  10. package/benchmark/results/query-100.json +63 -0
  11. package/benchmark/results/query-1000.json +63 -0
  12. package/benchmark/results/query-10000.json +63 -0
  13. package/benchmark/results/query-100000.json +63 -0
  14. package/benchmark/results/sorting.json +33 -0
  15. package/build/package.json +69 -0
  16. package/build/readme.md +17 -0
  17. package/{stats.html → build/stats.html} +1 -1
  18. package/globals.d.ts +9 -0
  19. package/index.tsx +1 -0
  20. package/package.json +4 -4
  21. package/src/Db.ts +89 -0
  22. package/src/DbRef.ts +254 -0
  23. package/src/DbTable.ts +264 -0
  24. package/src/IxSet.ts +251 -0
  25. package/src/ListLoadingTracker.ts +131 -0
  26. package/src/Loader.ts +96 -0
  27. package/src/Scheduler.ts +72 -0
  28. package/src/SimpleLoadingTracker.ts +17 -0
  29. package/src/__benchmarks__/filter.ts +50 -0
  30. package/src/__benchmarks__/index.ts +5 -0
  31. package/src/__benchmarks__/pkLookup.ts +33 -0
  32. package/src/__benchmarks__/pkUpdate.ts +75 -0
  33. package/src/__benchmarks__/query.ts +101 -0
  34. package/src/__benchmarks__/sorting.ts +33 -0
  35. package/src/__benchmarks__/testData.ts +15 -0
  36. package/src/__tests__/ListLoadingTracker.test.ts +83 -0
  37. package/src/__tests__/Scheduler.test.ts +24 -0
  38. package/src/__tests__/TaskDb.ts +187 -0
  39. package/src/__tests__/db.test.ts +293 -0
  40. package/src/__tests__/dbRef.test.ts +100 -0
  41. package/src/__tests__/dbTable.test.ts +15 -0
  42. package/src/__tests__/dbViews.test.ts +76 -0
  43. package/src/__tests__/ixSet.perf.test.ts +129 -0
  44. package/src/__tests__/ixSet.test.ts +73 -0
  45. package/src/__tests__/listLoader.test.ts +85 -0
  46. package/src/__tests__/loader.test.ts +92 -0
  47. package/src/__tests__/patchHelpers.test.ts +202 -0
  48. package/src/__tests__/tempIds.test.ts +98 -0
  49. package/src/index.ts +8 -0
  50. package/src/patchHelpers.ts +254 -0
  51. package/src/reactHooks.ts +28 -0
  52. package/src/tempIds.tsx +236 -0
  53. package/src/types.ts +126 -0
  54. package/src/utils.ts +34 -0
  55. package/tsconfig.json +12 -0
  56. /package/{index.d.ts → build/index.d.ts} +0 -0
  57. /package/{index.d.ts.map → build/index.d.ts.map} +0 -0
  58. /package/{index.esm.js → build/index.esm.js} +0 -0
  59. /package/{index.esm.js.map → build/index.esm.js.map} +0 -0
  60. /package/{index.js → build/index.js} +0 -0
  61. /package/{index.js.map → build/index.js.map} +0 -0
  62. /package/{src → build/src}/Db.d.ts +0 -0
  63. /package/{src → build/src}/Db.d.ts.map +0 -0
  64. /package/{src → build/src}/DbRef.d.ts +0 -0
  65. /package/{src → build/src}/DbRef.d.ts.map +0 -0
  66. /package/{src → build/src}/DbTable.d.ts +0 -0
  67. /package/{src → build/src}/DbTable.d.ts.map +0 -0
  68. /package/{src → build/src}/IxSet.d.ts +0 -0
  69. /package/{src → build/src}/IxSet.d.ts.map +0 -0
  70. /package/{src → build/src}/ListLoadingTracker.d.ts +0 -0
  71. /package/{src → build/src}/ListLoadingTracker.d.ts.map +0 -0
  72. /package/{src → build/src}/Loader.d.ts +0 -0
  73. /package/{src → build/src}/Loader.d.ts.map +0 -0
  74. /package/{src → build/src}/Scheduler.d.ts +0 -0
  75. /package/{src → build/src}/Scheduler.d.ts.map +0 -0
  76. /package/{src → build/src}/SimpleLoadingTracker.d.ts +0 -0
  77. /package/{src → build/src}/SimpleLoadingTracker.d.ts.map +0 -0
  78. /package/{src → build/src}/__benchmarks__/filter.d.ts +0 -0
  79. /package/{src → build/src}/__benchmarks__/filter.d.ts.map +0 -0
  80. /package/{src → build/src}/__benchmarks__/index.d.ts +0 -0
  81. /package/{src → build/src}/__benchmarks__/index.d.ts.map +0 -0
  82. /package/{src → build/src}/__benchmarks__/pkLookup.d.ts +0 -0
  83. /package/{src → build/src}/__benchmarks__/pkLookup.d.ts.map +0 -0
  84. /package/{src → build/src}/__benchmarks__/pkUpdate.d.ts +0 -0
  85. /package/{src → build/src}/__benchmarks__/pkUpdate.d.ts.map +0 -0
  86. /package/{src → build/src}/__benchmarks__/query.d.ts +0 -0
  87. /package/{src → build/src}/__benchmarks__/query.d.ts.map +0 -0
  88. /package/{src → build/src}/__benchmarks__/sorting.d.ts +0 -0
  89. /package/{src → build/src}/__benchmarks__/sorting.d.ts.map +0 -0
  90. /package/{src → build/src}/__benchmarks__/testData.d.ts +0 -0
  91. /package/{src → build/src}/__benchmarks__/testData.d.ts.map +0 -0
  92. /package/{src → build/src}/index.d.ts +0 -0
  93. /package/{src → build/src}/index.d.ts.map +0 -0
  94. /package/{src → build/src}/patchHelpers.d.ts +0 -0
  95. /package/{src → build/src}/patchHelpers.d.ts.map +0 -0
  96. /package/{src → build/src}/reactHooks.d.ts +0 -0
  97. /package/{src → build/src}/reactHooks.d.ts.map +0 -0
  98. /package/{src → build/src}/tempIds.d.ts +0 -0
  99. /package/{src → build/src}/tempIds.d.ts.map +0 -0
  100. /package/{src → build/src}/types.d.ts +0 -0
  101. /package/{src → build/src}/types.d.ts.map +0 -0
  102. /package/{src → build/src}/utils.d.ts +0 -0
  103. /package/{src → build/src}/utils.d.ts.map +0 -0
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "Find N entities in 100000 dataset by departmentId, sorted by name",
3
+ "date": "2020-06-10T00:31:03.956Z",
4
+ "version": "1.0.0",
5
+ "results": [
6
+ {
7
+ "name": "Array - scan",
8
+ "ops": 1830,
9
+ "margin": 4.74,
10
+ "percentSlower": 99.91
11
+ },
12
+ {
13
+ "name": "Array - with filterPredicate/orderComparer",
14
+ "ops": 668,
15
+ "margin": 3.19,
16
+ "percentSlower": 99.97
17
+ },
18
+ {
19
+ "name": "BTree - toArray/scan",
20
+ "ops": 183,
21
+ "margin": 5.36,
22
+ "percentSlower": 99.99
23
+ },
24
+ {
25
+ "name": "I.Map - iterable.filter.sort, then toArray",
26
+ "ops": 50,
27
+ "margin": 2.33,
28
+ "percentSlower": 100
29
+ },
30
+ {
31
+ "name": "I.Map - toArray, then filter/sort",
32
+ "ops": 36,
33
+ "margin": 14.94,
34
+ "percentSlower": 100
35
+ },
36
+ {
37
+ "name": "IxSet - with indexes",
38
+ "ops": 76943,
39
+ "margin": 7.77,
40
+ "percentSlower": 96.16
41
+ },
42
+ {
43
+ "name": "IxSet - no indexes",
44
+ "ops": 135,
45
+ "margin": 8.63,
46
+ "percentSlower": 99.99
47
+ },
48
+ {
49
+ "name": "DbTable - with index",
50
+ "ops": 2003311,
51
+ "margin": 4.35,
52
+ "percentSlower": 0
53
+ }
54
+ ],
55
+ "fastest": {
56
+ "name": "DbTable - with index",
57
+ "index": 7
58
+ },
59
+ "slowest": {
60
+ "name": "I.Map - toArray, then filter/sort",
61
+ "index": 4
62
+ }
63
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "Sort array",
3
+ "date": "2020-04-27T23:07:24.758Z",
4
+ "version": "1.0.0",
5
+ "results": [
6
+ {
7
+ "name": "array.sort, hard-coded",
8
+ "ops": 2645,
9
+ "margin": 2.18,
10
+ "percentSlower": 0
11
+ },
12
+ {
13
+ "name": "_.sort, hard-coded",
14
+ "ops": 464,
15
+ "margin": 1.96,
16
+ "percentSlower": 82.46
17
+ },
18
+ {
19
+ "name": "array.sort, getOrderComparer",
20
+ "ops": 1939,
21
+ "margin": 0.47,
22
+ "percentSlower": 26.69
23
+ }
24
+ ],
25
+ "fastest": {
26
+ "name": "array.sort, hard-coded",
27
+ "index": 0
28
+ },
29
+ "slowest": {
30
+ "name": "_.sort, hard-coded",
31
+ "index": 1
32
+ }
33
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@epam/uui-db",
3
+ "version": "5.3.0",
4
+ "description": "UUI - client-side relational state cache",
5
+ "author": "EPAM",
6
+ "license": "MIT",
7
+ "module": "index.esm.js",
8
+ "main": "index.js",
9
+ "typings": "index.d.ts",
10
+ "scripts": {
11
+ "build": "node ../uui-build/scripts/buildModule",
12
+ "perf": "npx ts-node -T ./src/__benchmarks__/index.ts",
13
+ "perf-prof": "node -r ts-node/register/transpile-only --prof ./src/__benchmarks__/index.ts",
14
+ "prepublish": "yarn build"
15
+ },
16
+ "dependencies": {
17
+ "@epam/uui-core": "5.3.0",
18
+ "@types/lodash.countby": "4.6.6",
19
+ "@types/lodash.filter": "4.6.6",
20
+ "@types/lodash.foreach": "4.5.6",
21
+ "@types/lodash.groupby": "4.6.6",
22
+ "@types/lodash.isempty": "4.4.6",
23
+ "@types/lodash.isequal": "4.5.5",
24
+ "@types/lodash.map": "4.6.13",
25
+ "@types/lodash.merge": "4.6.6",
26
+ "@types/lodash.orderby": "4.6.6",
27
+ "@types/lodash.pick": "4.4.6",
28
+ "@types/lodash.range": "3.2.6",
29
+ "@types/lodash.sortby": "4.7.6",
30
+ "@types/lodash.transform": "4.6.6",
31
+ "@types/lodash.zip": "4.2.6",
32
+ "@types/shallowequal": "^1.1.1",
33
+ "immutable": "3.8.2",
34
+ "lodash.countby": "4.6.0",
35
+ "lodash.filter": "4.6.0",
36
+ "lodash.foreach": "4.5.0",
37
+ "lodash.groupby": "4.6.0",
38
+ "lodash.isempty": "4.4.0",
39
+ "lodash.isequal": "4.5.0",
40
+ "lodash.map": "4.6.0",
41
+ "lodash.merge": "4.6.2",
42
+ "lodash.orderby": "4.6.0",
43
+ "lodash.pick": "4.4.0",
44
+ "lodash.range": "3.2.0",
45
+ "lodash.sortby": "4.7.0",
46
+ "lodash.transform": "4.6.0",
47
+ "lodash.zip": "4.2.0",
48
+ "shallowequal": "^1.1.0",
49
+ "sorted-btree": "^1.2.1"
50
+ },
51
+ "devDependencies": {
52
+ "@types/benchmark": "^1.0.31",
53
+ "benny": "^3.6.14",
54
+ "ts-node": "10.9.1"
55
+ },
56
+ "peerDependencies": {
57
+ "prop-types": "*",
58
+ "react": ">=16.0.0",
59
+ "react-dom": ">=16.0.0"
60
+ },
61
+ "repository": {
62
+ "type": "git",
63
+ "url": "https://github.com/epam/UUI"
64
+ },
65
+ "gitHead": "e5bbda766f5bdfd7c42a3c62c34afd9c03fffedd",
66
+ "publishConfig": {
67
+ "directory": "build"
68
+ }
69
+ }
@@ -0,0 +1,17 @@
1
+ # UUI DB package
2
+
3
+ This package is a part of [EPAM UUI](https://github.com/epam/UUI) library.
4
+
5
+ @epam/uui-db is an experimental state-management solution. It maintains immutable relational database on client, provides means to load data from server, update it both from client, and save it to server asynchronously with UI operations.
6
+
7
+ ## Features
8
+
9
+ - relation data model for state, providing a normalized storage for UI state
10
+ - data loading from server, with automatic GraphQL response normalization into tables
11
+ - synchronous and transactional updates of state from UI
12
+ - asynchronous bi-directional state synchronization between UI and server. UI changes in terms of 'patches' are batched and sent to server. Server can also push updates to UI state
13
+ - GIT-like branch-rebase approach to handle state concurrency
14
+ - tables can be indexed to speed-up queries
15
+ - Views to build arbitrary state projections
16
+ - subscriptions to subscribe parts of UI to changes in Views
17
+
@@ -4818,7 +4818,7 @@ var drawChart = (function (exports) {
4818
4818
  </script>
4819
4819
  <script>
4820
4820
  /*<!--*/
4821
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.esm.js","children":[{"name":"build/rollup:/@epam/uui-db","children":[{"name":"src","children":[{"uid":"416a-54","name":"types.ts"},{"uid":"416a-56","name":"utils.ts"},{"uid":"416a-58","name":"Db.ts"},{"uid":"416a-62","name":"DbTable.ts"},{"uid":"416a-64","name":"patchHelpers.ts"},{"uid":"416a-66","name":"tempIds.tsx"},{"uid":"416a-68","name":"Loader.ts"},{"uid":"416a-70","name":"SimpleLoadingTracker.ts"},{"uid":"416a-72","name":"ListLoadingTracker.ts"},{"uid":"416a-74","name":"DbRef.ts"},{"uid":"416a-76","name":"reactHooks.ts"}]},{"name":"node_modules/tslib/tslib.es6.js","uid":"416a-60"}]}]}],"isRoot":true},"nodeParts":{"416a-54":{"renderedLength":232,"gzipLength":0,"brotliLength":0,"metaUid":"416a-53"},"416a-56":{"renderedLength":777,"gzipLength":0,"brotliLength":0,"metaUid":"416a-55"},"416a-58":{"renderedLength":2104,"gzipLength":0,"brotliLength":0,"metaUid":"416a-57"},"416a-60":{"renderedLength":2229,"gzipLength":0,"brotliLength":0,"metaUid":"416a-59"},"416a-62":{"renderedLength":6566,"gzipLength":0,"brotliLength":0,"metaUid":"416a-61"},"416a-64":{"renderedLength":6098,"gzipLength":0,"brotliLength":0,"metaUid":"416a-63"},"416a-66":{"renderedLength":6249,"gzipLength":0,"brotliLength":0,"metaUid":"416a-65"},"416a-68":{"renderedLength":2277,"gzipLength":0,"brotliLength":0,"metaUid":"416a-67"},"416a-70":{"renderedLength":291,"gzipLength":0,"brotliLength":0,"metaUid":"416a-69"},"416a-72":{"renderedLength":2894,"gzipLength":0,"brotliLength":0,"metaUid":"416a-71"},"416a-74":{"renderedLength":5956,"gzipLength":0,"brotliLength":0,"metaUid":"416a-73"},"416a-76":{"renderedLength":442,"gzipLength":0,"brotliLength":0,"metaUid":"416a-75"}},"nodeMetas":{"416a-53":{"id":"/build/rollup:/@epam/uui-db/src/types.ts","moduleParts":{"index.esm.js":"416a-54"},"imported":[],"importedBy":[]},"416a-55":{"id":"/build/rollup:/@epam/uui-db/src/utils.ts","moduleParts":{"index.esm.js":"416a-56"},"imported":[],"importedBy":[]},"416a-57":{"id":"/build/rollup:/@epam/uui-db/src/Db.ts","moduleParts":{"index.esm.js":"416a-58"},"imported":[],"importedBy":[]},"416a-59":{"id":"/build/rollup:/@epam/uui-db/node_modules/tslib/tslib.es6.js","moduleParts":{"index.esm.js":"416a-60"},"imported":[],"importedBy":[]},"416a-61":{"id":"/build/rollup:/@epam/uui-db/src/DbTable.ts","moduleParts":{"index.esm.js":"416a-62"},"imported":[],"importedBy":[]},"416a-63":{"id":"/build/rollup:/@epam/uui-db/src/patchHelpers.ts","moduleParts":{"index.esm.js":"416a-64"},"imported":[],"importedBy":[]},"416a-65":{"id":"/build/rollup:/@epam/uui-db/src/tempIds.tsx","moduleParts":{"index.esm.js":"416a-66"},"imported":[],"importedBy":[]},"416a-67":{"id":"/build/rollup:/@epam/uui-db/src/Loader.ts","moduleParts":{"index.esm.js":"416a-68"},"imported":[],"importedBy":[]},"416a-69":{"id":"/build/rollup:/@epam/uui-db/src/SimpleLoadingTracker.ts","moduleParts":{"index.esm.js":"416a-70"},"imported":[],"importedBy":[]},"416a-71":{"id":"/build/rollup:/@epam/uui-db/src/ListLoadingTracker.ts","moduleParts":{"index.esm.js":"416a-72"},"imported":[],"importedBy":[]},"416a-73":{"id":"/build/rollup:/@epam/uui-db/src/DbRef.ts","moduleParts":{"index.esm.js":"416a-74"},"imported":[],"importedBy":[]},"416a-75":{"id":"/build/rollup:/@epam/uui-db/src/reactHooks.ts","moduleParts":{"index.esm.js":"416a-76"},"imported":[],"importedBy":[]},"416a-77":{"id":"/index.tsx","moduleParts":{},"imported":[{"uid":"416a-78"}],"importedBy":[],"isEntry":true},"416a-78":{"id":"/src/index.ts","moduleParts":{},"imported":[{"uid":"416a-79"},{"uid":"416a-80"},{"uid":"416a-81"},{"uid":"416a-82"},{"uid":"416a-83"},{"uid":"416a-84"},{"uid":"416a-85"},{"uid":"416a-86"}],"importedBy":[{"uid":"416a-77"}]},"416a-79":{"id":"/src/types.ts","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-78"},{"uid":"416a-85"}]},"416a-80":{"id":"/src/Db.ts","moduleParts":{},"imported":[{"uid":"416a-84"},{"uid":"416a-87"}],"importedBy":[{"uid":"416a-78"}]},"416a-81":{"id":"/src/DbTable.ts","moduleParts":{},"imported":[{"uid":"416a-88"},{"uid":"416a-89"},{"uid":"416a-90"}],"importedBy":[{"uid":"416a-78"}]},"416a-82":{"id":"/src/DbRef.ts","moduleParts":{},"imported":[{"uid":"416a-88"},{"uid":"416a-85"},{"uid":"416a-83"},{"uid":"416a-84"},{"uid":"416a-91"},{"uid":"416a-92"},{"uid":"416a-90"},{"uid":"416a-93"},{"uid":"416a-94"}],"importedBy":[{"uid":"416a-78"}]},"416a-83":{"id":"/src/tempIds.tsx","moduleParts":{},"imported":[{"uid":"416a-84"}],"importedBy":[{"uid":"416a-78"},{"uid":"416a-82"}]},"416a-84":{"id":"/src/utils.ts","moduleParts":{},"imported":[{"uid":"416a-95"},{"uid":"416a-96"},{"uid":"416a-97"},{"uid":"416a-87"}],"importedBy":[{"uid":"416a-78"},{"uid":"416a-80"},{"uid":"416a-82"},{"uid":"416a-83"},{"uid":"416a-85"}]},"416a-85":{"id":"/src/patchHelpers.ts","moduleParts":{},"imported":[{"uid":"416a-79"},{"uid":"416a-89"},{"uid":"416a-84"},{"uid":"416a-98"},{"uid":"416a-99"},{"uid":"416a-100"},{"uid":"416a-101"},{"uid":"416a-102"},{"uid":"416a-103"},{"uid":"416a-104"}],"importedBy":[{"uid":"416a-78"},{"uid":"416a-82"}]},"416a-86":{"id":"/src/reactHooks.ts","moduleParts":{},"imported":[{"uid":"416a-105"}],"importedBy":[{"uid":"416a-78"}]},"416a-87":{"id":"lodash.isequal","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-80"},{"uid":"416a-84"}],"isExternal":true},"416a-88":{"id":"/Users/Aliaksei_Manetau/WebstormProjects/uui/node_modules/tslib/tslib.es6.js","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-81"},{"uid":"416a-82"},{"uid":"416a-94"}]},"416a-89":{"id":"immutable","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-81"},{"uid":"416a-85"}],"isExternal":true},"416a-90":{"id":"@epam/uui-core","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-81"},{"uid":"416a-82"}],"isExternal":true},"416a-91":{"id":"lodash.isempty","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-82"}],"isExternal":true},"416a-92":{"id":"/src/Loader.ts","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-82"}]},"416a-93":{"id":"/src/SimpleLoadingTracker.ts","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-82"}]},"416a-94":{"id":"/src/ListLoadingTracker.ts","moduleParts":{},"imported":[{"uid":"416a-88"}],"importedBy":[{"uid":"416a-82"}]},"416a-95":{"id":"shallowequal","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-84"}],"isExternal":true},"416a-96":{"id":"lodash.zip","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-84"}],"isExternal":true},"416a-97":{"id":"lodash.transform","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-84"}],"isExternal":true},"416a-98":{"id":"lodash.groupby","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-99":{"id":"lodash.map","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-100":{"id":"lodash.merge","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-101":{"id":"lodash.countby","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-102":{"id":"lodash.filter","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-103":{"id":"lodash.foreach","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-104":{"id":"lodash.pick","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-85"}],"isExternal":true},"416a-105":{"id":"react","moduleParts":{},"imported":[],"importedBy":[{"uid":"416a-86"}],"isExternal":true}},"env":{"rollup":"3.26.2"},"options":{"gzip":false,"brotli":false,"sourcemap":true}};
4821
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.esm.js","children":[{"name":"build/rollup:/@epam/uui-db","children":[{"name":"src","children":[{"uid":"d5ef-54","name":"types.ts"},{"uid":"d5ef-56","name":"utils.ts"},{"uid":"d5ef-58","name":"Db.ts"},{"uid":"d5ef-62","name":"DbTable.ts"},{"uid":"d5ef-64","name":"patchHelpers.ts"},{"uid":"d5ef-66","name":"tempIds.tsx"},{"uid":"d5ef-68","name":"Loader.ts"},{"uid":"d5ef-70","name":"SimpleLoadingTracker.ts"},{"uid":"d5ef-72","name":"ListLoadingTracker.ts"},{"uid":"d5ef-74","name":"DbRef.ts"},{"uid":"d5ef-76","name":"reactHooks.ts"}]},{"name":"node_modules/tslib/tslib.es6.js","uid":"d5ef-60"}]}]}],"isRoot":true},"nodeParts":{"d5ef-54":{"renderedLength":232,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-53"},"d5ef-56":{"renderedLength":777,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-55"},"d5ef-58":{"renderedLength":2104,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-57"},"d5ef-60":{"renderedLength":2229,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-59"},"d5ef-62":{"renderedLength":6566,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-61"},"d5ef-64":{"renderedLength":6098,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-63"},"d5ef-66":{"renderedLength":6249,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-65"},"d5ef-68":{"renderedLength":2277,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-67"},"d5ef-70":{"renderedLength":291,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-69"},"d5ef-72":{"renderedLength":2894,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-71"},"d5ef-74":{"renderedLength":5956,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-73"},"d5ef-76":{"renderedLength":442,"gzipLength":0,"brotliLength":0,"metaUid":"d5ef-75"}},"nodeMetas":{"d5ef-53":{"id":"/build/rollup:/@epam/uui-db/src/types.ts","moduleParts":{"index.esm.js":"d5ef-54"},"imported":[],"importedBy":[]},"d5ef-55":{"id":"/build/rollup:/@epam/uui-db/src/utils.ts","moduleParts":{"index.esm.js":"d5ef-56"},"imported":[],"importedBy":[]},"d5ef-57":{"id":"/build/rollup:/@epam/uui-db/src/Db.ts","moduleParts":{"index.esm.js":"d5ef-58"},"imported":[],"importedBy":[]},"d5ef-59":{"id":"/build/rollup:/@epam/uui-db/node_modules/tslib/tslib.es6.js","moduleParts":{"index.esm.js":"d5ef-60"},"imported":[],"importedBy":[]},"d5ef-61":{"id":"/build/rollup:/@epam/uui-db/src/DbTable.ts","moduleParts":{"index.esm.js":"d5ef-62"},"imported":[],"importedBy":[]},"d5ef-63":{"id":"/build/rollup:/@epam/uui-db/src/patchHelpers.ts","moduleParts":{"index.esm.js":"d5ef-64"},"imported":[],"importedBy":[]},"d5ef-65":{"id":"/build/rollup:/@epam/uui-db/src/tempIds.tsx","moduleParts":{"index.esm.js":"d5ef-66"},"imported":[],"importedBy":[]},"d5ef-67":{"id":"/build/rollup:/@epam/uui-db/src/Loader.ts","moduleParts":{"index.esm.js":"d5ef-68"},"imported":[],"importedBy":[]},"d5ef-69":{"id":"/build/rollup:/@epam/uui-db/src/SimpleLoadingTracker.ts","moduleParts":{"index.esm.js":"d5ef-70"},"imported":[],"importedBy":[]},"d5ef-71":{"id":"/build/rollup:/@epam/uui-db/src/ListLoadingTracker.ts","moduleParts":{"index.esm.js":"d5ef-72"},"imported":[],"importedBy":[]},"d5ef-73":{"id":"/build/rollup:/@epam/uui-db/src/DbRef.ts","moduleParts":{"index.esm.js":"d5ef-74"},"imported":[],"importedBy":[]},"d5ef-75":{"id":"/build/rollup:/@epam/uui-db/src/reactHooks.ts","moduleParts":{"index.esm.js":"d5ef-76"},"imported":[],"importedBy":[]},"d5ef-77":{"id":"/index.tsx","moduleParts":{},"imported":[{"uid":"d5ef-78"}],"importedBy":[],"isEntry":true},"d5ef-78":{"id":"/src/index.ts","moduleParts":{},"imported":[{"uid":"d5ef-79"},{"uid":"d5ef-80"},{"uid":"d5ef-81"},{"uid":"d5ef-82"},{"uid":"d5ef-83"},{"uid":"d5ef-84"},{"uid":"d5ef-85"},{"uid":"d5ef-86"}],"importedBy":[{"uid":"d5ef-77"}]},"d5ef-79":{"id":"/src/types.ts","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-78"},{"uid":"d5ef-85"}]},"d5ef-80":{"id":"/src/Db.ts","moduleParts":{},"imported":[{"uid":"d5ef-84"},{"uid":"d5ef-87"}],"importedBy":[{"uid":"d5ef-78"}]},"d5ef-81":{"id":"/src/DbTable.ts","moduleParts":{},"imported":[{"uid":"d5ef-88"},{"uid":"d5ef-89"},{"uid":"d5ef-90"}],"importedBy":[{"uid":"d5ef-78"}]},"d5ef-82":{"id":"/src/DbRef.ts","moduleParts":{},"imported":[{"uid":"d5ef-88"},{"uid":"d5ef-85"},{"uid":"d5ef-83"},{"uid":"d5ef-84"},{"uid":"d5ef-91"},{"uid":"d5ef-92"},{"uid":"d5ef-90"},{"uid":"d5ef-93"},{"uid":"d5ef-94"}],"importedBy":[{"uid":"d5ef-78"}]},"d5ef-83":{"id":"/src/tempIds.tsx","moduleParts":{},"imported":[{"uid":"d5ef-84"}],"importedBy":[{"uid":"d5ef-78"},{"uid":"d5ef-82"}]},"d5ef-84":{"id":"/src/utils.ts","moduleParts":{},"imported":[{"uid":"d5ef-95"},{"uid":"d5ef-96"},{"uid":"d5ef-97"},{"uid":"d5ef-87"}],"importedBy":[{"uid":"d5ef-78"},{"uid":"d5ef-80"},{"uid":"d5ef-82"},{"uid":"d5ef-83"},{"uid":"d5ef-85"}]},"d5ef-85":{"id":"/src/patchHelpers.ts","moduleParts":{},"imported":[{"uid":"d5ef-79"},{"uid":"d5ef-89"},{"uid":"d5ef-84"},{"uid":"d5ef-98"},{"uid":"d5ef-99"},{"uid":"d5ef-100"},{"uid":"d5ef-101"},{"uid":"d5ef-102"},{"uid":"d5ef-103"},{"uid":"d5ef-104"}],"importedBy":[{"uid":"d5ef-78"},{"uid":"d5ef-82"}]},"d5ef-86":{"id":"/src/reactHooks.ts","moduleParts":{},"imported":[{"uid":"d5ef-105"}],"importedBy":[{"uid":"d5ef-78"}]},"d5ef-87":{"id":"lodash.isequal","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-80"},{"uid":"d5ef-84"}],"isExternal":true},"d5ef-88":{"id":"/Users/Aliaksei_Manetau/WebstormProjects/UUI_new/node_modules/tslib/tslib.es6.js","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-81"},{"uid":"d5ef-82"},{"uid":"d5ef-94"}]},"d5ef-89":{"id":"immutable","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-81"},{"uid":"d5ef-85"}],"isExternal":true},"d5ef-90":{"id":"@epam/uui-core","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-81"},{"uid":"d5ef-82"}],"isExternal":true},"d5ef-91":{"id":"lodash.isempty","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-82"}],"isExternal":true},"d5ef-92":{"id":"/src/Loader.ts","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-82"}]},"d5ef-93":{"id":"/src/SimpleLoadingTracker.ts","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-82"}]},"d5ef-94":{"id":"/src/ListLoadingTracker.ts","moduleParts":{},"imported":[{"uid":"d5ef-88"}],"importedBy":[{"uid":"d5ef-82"}]},"d5ef-95":{"id":"shallowequal","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-84"}],"isExternal":true},"d5ef-96":{"id":"lodash.zip","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-84"}],"isExternal":true},"d5ef-97":{"id":"lodash.transform","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-84"}],"isExternal":true},"d5ef-98":{"id":"lodash.groupby","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-99":{"id":"lodash.map","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-100":{"id":"lodash.merge","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-101":{"id":"lodash.countby","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-102":{"id":"lodash.filter","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-103":{"id":"lodash.foreach","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-104":{"id":"lodash.pick","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-85"}],"isExternal":true},"d5ef-105":{"id":"react","moduleParts":{},"imported":[],"importedBy":[{"uid":"d5ef-86"}],"isExternal":true}},"env":{"rollup":"3.26.2"},"options":{"gzip":false,"brotli":false,"sourcemap":true}};
4822
4822
 
4823
4823
  const run = () => {
4824
4824
  const width = window.innerWidth;
package/globals.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ /// <reference path="../uui_globals.d.ts" />
2
+
3
+ declare module 'jsurl';
4
+ declare module 'query-string';
5
+ declare module 'draft-js-plugins-editor';
6
+ declare module 'draft-js-clear-formatting';
7
+ declare module 'draft-convert';
8
+ declare module 'draft-js-plugins-utils';
9
+ declare module 'draft-js/lib/*';
package/index.tsx ADDED
@@ -0,0 +1 @@
1
+ export * from './src';
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@epam/uui-db",
3
- "version": "5.3.0-rc.0",
3
+ "version": "5.3.0",
4
4
  "description": "UUI - client-side relational state cache",
5
5
  "author": "EPAM",
6
6
  "license": "MIT",
7
- "module": "index.esm.js",
8
7
  "main": "index.js",
8
+ "epam:uui:main": "build/index.esm.js",
9
9
  "typings": "index.d.ts",
10
10
  "scripts": {
11
11
  "build": "node ../uui-build/scripts/buildModule",
@@ -14,7 +14,7 @@
14
14
  "prepublish": "yarn build"
15
15
  },
16
16
  "dependencies": {
17
- "@epam/uui-core": "5.3.0-rc.0",
17
+ "@epam/uui-core": "5.3.0",
18
18
  "@types/lodash.countby": "4.6.6",
19
19
  "@types/lodash.filter": "4.6.6",
20
20
  "@types/lodash.foreach": "4.5.6",
@@ -66,4 +66,4 @@
66
66
  "publishConfig": {
67
67
  "directory": "build"
68
68
  }
69
- }
69
+ }
package/src/Db.ts ADDED
@@ -0,0 +1,89 @@
1
+ import {
2
+ DbPatch, DbTablesSet, DbTableEntityByTable, DbView, DbRelationType, ViewCacheItem,
3
+ } from './types';
4
+ import { objectKeys, defaultCompareViewDependencies, difference } from './utils';
5
+ import isEqual from 'lodash.isequal';
6
+
7
+ type ViewCache = Map<DbView<any, any, any, any>, Map<string, ViewCacheItem>>;
8
+
9
+ export abstract class Db<TTables extends DbTablesSet<TTables>> {
10
+ private viewCache: ViewCache = new Map();
11
+ constructor(public tables: TTables, reusedCache?: ViewCache) {
12
+ if (reusedCache) {
13
+ this.viewCache = new Map(reusedCache);
14
+ } else {
15
+ this.viewCache = new Map();
16
+ }
17
+ }
18
+
19
+ private update(mutate: (db: this) => void): this {
20
+ const clone = new (this.constructor as any)(this.tables, this.viewCache);
21
+ clone.tables = { ...this.tables };
22
+ mutate(clone);
23
+ return clone;
24
+ }
25
+
26
+ public with(patch: DbPatch<TTables>): this {
27
+ return this.update((db) => {
28
+ objectKeys(db.tables).forEach((entityName) => {
29
+ if (patch[entityName]) {
30
+ db.tables[entityName] = db.tables[entityName].with(patch[entityName]);
31
+ }
32
+ });
33
+ });
34
+ }
35
+
36
+ /* Views (cached db projections) */
37
+
38
+ valueAbsent = Symbol('ValueAbsent');
39
+ public runView<TResult, TParams = void, TDependencies = void>(view: DbView<this, TResult, TParams, TDependencies>, params?: TParams) {
40
+ let cache = this.viewCache.get(view);
41
+
42
+ if (!cache) {
43
+ cache = new Map();
44
+ this.viewCache.set(view, cache);
45
+ }
46
+
47
+ const key = view.getKey ? view.getKey(params) : JSON.stringify(params);
48
+
49
+ let cacheItem: ViewCacheItem = cache.get(key);
50
+
51
+ if (!cacheItem) {
52
+ cacheItem = {
53
+ dependencies: this.valueAbsent,
54
+ currentValue: this.valueAbsent,
55
+ computedOnDb: this.valueAbsent,
56
+ };
57
+ cache.set(key, cacheItem);
58
+ }
59
+
60
+ let shouldUpdate = this !== cacheItem.computedOnDb;
61
+ let dependencies: any = this.valueAbsent;
62
+
63
+ if (view.getDependencies) {
64
+ const compare = view.compareDependencies || defaultCompareViewDependencies;
65
+ dependencies = view.getDependencies(this, params);
66
+ shouldUpdate = !compare(cacheItem.dependencies, dependencies);
67
+ }
68
+
69
+ const previousValue = cacheItem.currentValue;
70
+
71
+ if (shouldUpdate) {
72
+ cacheItem.dependencies = dependencies;
73
+ const newValue = view.compute(this, params, dependencies);
74
+ cacheItem.computedOnDb = this;
75
+
76
+ const compareResults = view.compareResults || isEqual;
77
+
78
+ if (!compareResults(previousValue, newValue)) {
79
+ if (view.traceDiff) {
80
+ console.debug(difference(previousValue, newValue));
81
+ }
82
+
83
+ cacheItem.currentValue = newValue;
84
+ }
85
+ }
86
+
87
+ return cacheItem.currentValue as TResult;
88
+ }
89
+ }
package/src/DbRef.ts ADDED
@@ -0,0 +1,254 @@
1
+ import { Db } from './Db';
2
+ import {
3
+ DbPatch, DbTablesSet, ServerError, DbSaveResponse, DbView, ViewCacheItem, DbSubscription, DbPkFieldType,
4
+ } from './types';
5
+ import {
6
+ makeCumulativePatch, unionPatches, mergeEntityPatches, flattenResponse,
7
+ } from './patchHelpers';
8
+ import { TempIdMap, IClientIdsMap } from './tempIds';
9
+ import { objectKeys, defaultCompareViewDependencies, difference } from './utils';
10
+ import isEmpty from 'lodash.isempty';
11
+ import { Loader, LoaderOptions } from './Loader';
12
+ import { DataQuery, LazyDataSourceApiResponse, batch } from '@epam/uui-core';
13
+ import { SimpleLoadingTracker } from './SimpleLoadingTracker';
14
+ import { ListLoadingTracker, ListLoadingTrackerOptions } from './ListLoadingTracker';
15
+
16
+ export class DbRef<TTables extends DbTablesSet<TTables>, TDb extends Db<TTables>> {
17
+ private base: TDb;
18
+ private log: { patch: DbPatch<TTables> }[] = [];
19
+ private autoSave = true;
20
+ private savedPoint = 0;
21
+ private tempIdMap: TempIdMap<TTables>;
22
+ public db: TDb;
23
+ protected throttleSaveMs = 1000;
24
+ public readonly idMap: IClientIdsMap;
25
+ constructor(public blank: TDb) {
26
+ this.db = blank;
27
+ this.base = blank;
28
+ this.tempIdMap = new TempIdMap(blank);
29
+ this.idMap = this.tempIdMap;
30
+
31
+ window.addEventListener('beforeunload', this.handleBeforeUnload);
32
+ }
33
+
34
+ /** Saves all committed patches. Useful only if autoSave is off. */
35
+ public save() {
36
+ return this.enqueueSave();
37
+ }
38
+
39
+ public getAutoSave() {
40
+ return this.autoSave;
41
+ }
42
+
43
+ public setAutoSave(val: boolean) {
44
+ if (this.autoSave != val) {
45
+ this.autoSave = val;
46
+ this.autoSave && this.enqueueSave();
47
+ this.update();
48
+ }
49
+ }
50
+
51
+ public revert() {
52
+ this.db = this.base;
53
+ this.log = this.log.slice(0, this.savedPoint);
54
+ this.update();
55
+ }
56
+
57
+ /** Concrete DbRef instances should override and implement their save logic in this method */
58
+ protected savePatch(patch: DbPatch<TTables>): Promise<DbSaveResponse<TTables>> {
59
+ return Promise.resolve({ submit: {} });
60
+ }
61
+
62
+ /* Db Update logic */
63
+
64
+ public commit(patch: DbPatch<TTables>): void {
65
+ const dbBeforeUpdate = this.db.with(patch);
66
+ patch = this.beforeUpdate(patch, dbBeforeUpdate.tables, this.db.tables);
67
+ patch = mergeEntityPatches(this.db.tables, patch);
68
+ this.log.push({ patch });
69
+ this.db = this.db.with(patch);
70
+
71
+ this.autoSave && this.enqueueSave(null, { throttleMs: this.throttleSaveMs });
72
+ this.update();
73
+ }
74
+
75
+ private beforeUpdate(patch: DbPatch<TTables>, tables: TTables, prevTables: TTables): DbPatch<TTables> {
76
+ let patchAndDependencies: DbPatch<TTables> = {};
77
+
78
+ objectKeys(tables)
79
+ .filter((entityName) => patch[entityName] && !tables[entityName].schema.beforeUpdate)
80
+ .forEach((entityName) => {
81
+ patchAndDependencies[entityName] = patch[entityName];
82
+ });
83
+
84
+ objectKeys(tables)
85
+ .filter((entityName) => patch[entityName] && tables[entityName].schema.beforeUpdate)
86
+ .forEach((entityName) => {
87
+ const schema = tables[entityName].schema;
88
+ const { beforeUpdate } = schema;
89
+ const context = {
90
+ clientIdsMap: this.tempIdMap,
91
+ schema,
92
+ tables,
93
+ prevTables,
94
+ };
95
+
96
+ const results = patch[entityName].map((e) => beforeUpdate(e, context));
97
+ const updatedPatch = { [entityName]: results.map((result) => result.entity) } as DbPatch<TTables>;
98
+ const dependentEntityPatchesForUpdate = unionPatches(results.filter((result) => result.dependentEntities).map((result) => result.dependentEntities));
99
+ const dependentEntityPatches = this.beforeUpdate(dependentEntityPatchesForUpdate, tables, prevTables);
100
+
101
+ patchAndDependencies = mergeEntityPatches(tables, unionPatches([
102
+ patchAndDependencies, updatedPatch, dependentEntityPatches,
103
+ ]));
104
+ });
105
+ return patchAndDependencies;
106
+ }
107
+
108
+ public commitFetch(patch: DbPatch<TTables>): void {
109
+ patch = this.tempIdMap.serverToClientPatch(patch);
110
+ this.rebase(this.base.with(patch));
111
+ this.update();
112
+ }
113
+
114
+ private rebase(newBase: TDb) {
115
+ this.base = newBase;
116
+ this.db = newBase;
117
+ for (let n = this.savedPoint; n < this.log.length; n++) {
118
+ this.db = this.db.with(this.log[n].patch);
119
+ }
120
+ }
121
+
122
+ private makeCumulativePatch() {
123
+ const lastLogEntry = this.log.length;
124
+ const logEntriesToSave = this.log.slice(this.savedPoint, lastLogEntry);
125
+ let cumulativePatch = makeCumulativePatch(
126
+ this.db,
127
+ logEntriesToSave.map((t) => t.patch),
128
+ this.tempIdMap,
129
+ );
130
+ cumulativePatch = this.tempIdMap.clientToServerPatch(cumulativePatch);
131
+
132
+ return cumulativePatch;
133
+ }
134
+
135
+ private applyResponse(response: DbSaveResponse<TTables>, newSavedPoint: number) {
136
+ this.tempIdMap.appendServerMapping(response);
137
+
138
+ let serverPatch = flattenResponse(response.submit, this.db.tables);
139
+ serverPatch = mergeEntityPatches(this.db.tables, serverPatch);
140
+ this.savedPoint = newSavedPoint;
141
+ this.base = this.db;
142
+ this.commitFetch(serverPatch);
143
+ }
144
+
145
+ /* Update subscriptions (aka live views) */
146
+
147
+ private lastSubscriptionId = 1;
148
+ private subscriptions: Map<number, DbSubscription<any, any>> = new Map();
149
+ public subscribe<TValue, TParams, TDependencies>(
150
+ view: DbView<TDb, TValue, TParams, TDependencies>,
151
+ params: TParams,
152
+ onUpdate: (newValue: TValue) => any,
153
+ ): DbSubscription<TValue, TParams> {
154
+ const id = this.lastSubscriptionId++;
155
+
156
+ const subscription: DbSubscription<TValue, TParams> = {
157
+ update: (subscriptionParams: TParams) => {
158
+ subscription.currentParams = subscriptionParams;
159
+ subscription.currentValue = this.db.runView(view, subscriptionParams);
160
+ return subscription.currentValue;
161
+ },
162
+ currentParams: null,
163
+ currentValue: null,
164
+ onUpdate,
165
+ unsubscribe: () => {
166
+ this.subscriptions.delete(id);
167
+ },
168
+ };
169
+
170
+ subscription.update(params);
171
+
172
+ this.subscriptions.set(id, subscription);
173
+
174
+ return subscription;
175
+ }
176
+
177
+ updateHandlers: (() => any)[] = [];
178
+ public onUpdate(handler: () => any) {
179
+ this.subscribe(
180
+ {
181
+ compute: (db) => db,
182
+ compareResults: (a, b) => a === b,
183
+ },
184
+ null,
185
+ handler,
186
+ );
187
+ }
188
+
189
+ private update() {
190
+ this.subscriptions.forEach((subscription) => {
191
+ const previousValue = subscription.currentValue;
192
+ subscription.update(subscription.currentParams);
193
+ if (subscription.currentValue !== previousValue && subscription.onUpdate) {
194
+ subscription.onUpdate(subscription.currentValue);
195
+ }
196
+ });
197
+ }
198
+
199
+ /* Error Subscriptions */
200
+
201
+ public saveErrorHandlers: ((request: DbPatch<TTables>, error: any) => void)[] = [];
202
+ public onSaveError(handler: (request: DbPatch<TTables>, error: any) => void) {
203
+ this.saveErrorHandlers.push(handler);
204
+ }
205
+
206
+ private saveError(request: DbPatch<TTables>, error: any) {
207
+ this.saveErrorHandlers.forEach((handler) => handler(request, error));
208
+ }
209
+
210
+ /* Save scheduling */
211
+
212
+ private enqueueSave = batch(async () => {
213
+ const cumulativePatch = this.makeCumulativePatch();
214
+ const lastLogEntry = this.log.length;
215
+ if (isEmpty(cumulativePatch)) {
216
+ return;
217
+ }
218
+ try {
219
+ const response = await this.savePatch(cumulativePatch);
220
+ this.applyResponse(response, lastLogEntry);
221
+ this.update();
222
+ } catch (error) {
223
+ this.saveError(cumulativePatch, error);
224
+ this.update();
225
+ throw error;
226
+ }
227
+ });
228
+
229
+ private handleBeforeUnload = (e: BeforeUnloadEvent) => {
230
+ if (this.enqueueSave.isBusy) {
231
+ e.returnValue = false;
232
+ return false;
233
+ }
234
+ };
235
+
236
+ loaders: Loader<TTables, any, any>[] = [];
237
+ protected makeLoader<TResponse, TRequest>(options: LoaderOptions<TTables, TResponse, TRequest>) {
238
+ const loader = new Loader<TTables, TResponse, TRequest>(this as any, () => new SimpleLoadingTracker<TRequest, TResponse>(), options);
239
+ this.loaders.push(loader);
240
+ return loader;
241
+ }
242
+
243
+ protected makeListLoader<TItem, TResponse = DataQuery<TItem>, TRequest extends DataQuery<TItem> = DataQuery<TItem>>(
244
+ options: LoaderOptions<TTables, TResponse, TRequest> & ListLoadingTrackerOptions<TItem, TResponse>,
245
+ ) {
246
+ const loader = new Loader<TTables, TResponse, TRequest>(this as any, () => new ListLoadingTracker<TItem, TRequest, TResponse>(), options);
247
+ this.loaders.push(loader);
248
+ return loader;
249
+ }
250
+
251
+ reload() {
252
+ this.loaders = [];
253
+ }
254
+ }