@gooddata/sdk-backend-base 9.6.0-alpha.6 → 9.6.0-alpha.7
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.
- package/esm/cachingBackend/index.js +269 -260
- package/esm/cachingBackend/index.js.map +1 -1
- package/esm/customBackend/execution.js +107 -94
- package/esm/customBackend/execution.js.map +1 -1
- package/esm/customBackend/index.js +102 -95
- package/esm/customBackend/index.js.map +1 -1
- package/esm/customBackend/workspace.js +3 -0
- package/esm/customBackend/workspace.js.map +1 -1
- package/esm/decoratedBackend/analyticalWorkspace.js +3 -0
- package/esm/decoratedBackend/analyticalWorkspace.js.map +1 -1
- package/esm/decoratedBackend/attributes.js +1 -0
- package/esm/decoratedBackend/attributes.js.map +1 -1
- package/esm/decoratedBackend/catalog.js +5 -0
- package/esm/decoratedBackend/catalog.js.map +1 -1
- package/esm/decoratedBackend/dashboards.js +2 -0
- package/esm/decoratedBackend/dashboards.js.map +1 -1
- package/esm/decoratedBackend/elements.js +32 -6
- package/esm/decoratedBackend/elements.js.map +1 -1
- package/esm/decoratedBackend/execution.js +32 -13
- package/esm/decoratedBackend/execution.js.map +1 -1
- package/esm/decoratedBackend/index.js +4 -0
- package/esm/decoratedBackend/index.js.map +1 -1
- package/esm/decoratedBackend/organization.js +3 -0
- package/esm/decoratedBackend/organization.js.map +1 -1
- package/esm/decoratedBackend/organizations.js +2 -0
- package/esm/decoratedBackend/organizations.js.map +1 -1
- package/esm/decoratedBackend/securitySettings.js +2 -0
- package/esm/decoratedBackend/securitySettings.js.map +1 -1
- package/esm/decoratedBackend/workspaceSettings.js +1 -0
- package/esm/decoratedBackend/workspaceSettings.js.map +1 -1
- package/esm/dummyBackend/index.js +34 -10
- package/esm/dummyBackend/index.js.map +1 -1
- package/esm/eventingBackend/index.js +47 -44
- package/esm/eventingBackend/index.js.map +1 -1
- package/esm/ldmFactories/builder.js +2 -0
- package/esm/ldmFactories/builder.js.map +1 -1
- package/esm/ldmFactories/catalog/attributeFactory.js +1 -1
- package/esm/ldmFactories/catalog/attributeFactory.js.map +1 -1
- package/esm/ldmFactories/catalog/measureFactory.js +1 -1
- package/esm/ldmFactories/catalog/measureFactory.js.map +1 -1
- package/esm/ldmFactories/dashboard/insightWidgetFactory.js +5 -3
- package/esm/ldmFactories/dashboard/insightWidgetFactory.js.map +1 -1
- package/esm/ldmFactories/dashboard/kpiWidgetFactory.js +17 -9
- package/esm/ldmFactories/dashboard/kpiWidgetFactory.js.map +1 -1
- package/esm/ldmFactories/dashboard/widgetFactory.js +18 -18
- package/esm/ldmFactories/dashboard/widgetFactory.js.map +1 -1
- package/esm/normalizingBackend/index.js +79 -58
- package/esm/normalizingBackend/index.js.map +1 -1
- package/esm/normalizingBackend/normalizer.js +317 -297
- package/esm/normalizingBackend/normalizer.js.map +1 -1
- package/esm/toolkit/auth.js +33 -32
- package/esm/toolkit/auth.js.map +1 -1
- package/esm/toolkit/execution.js +2 -0
- package/esm/toolkit/execution.js.map +1 -1
- package/esm/toolkit/paging.js +48 -38
- package/esm/toolkit/paging.js.map +1 -1
- package/esm/toolkit/pluginUrlValidation.js +1 -2
- package/esm/toolkit/pluginUrlValidation.js.map +1 -1
- package/esm/workspaceSettingsBackend/index.js +11 -2
- package/esm/workspaceSettingsBackend/index.js.map +1 -1
- package/package.json +8 -10
|
@@ -19,32 +19,33 @@ import { DecoratedWorkspaceSettingsService } from "../decoratedBackend/workspace
|
|
|
19
19
|
// Execution caching
|
|
20
20
|
//
|
|
21
21
|
class WithExecutionCaching extends DecoratedPreparedExecution {
|
|
22
|
+
ctx;
|
|
22
23
|
constructor(decorated, ctx) {
|
|
23
24
|
super(decorated);
|
|
24
25
|
this.ctx = ctx;
|
|
25
|
-
this.execute = async () => {
|
|
26
|
-
const cacheKey = this.fingerprint();
|
|
27
|
-
const cache = this.ctx.caches.execution;
|
|
28
|
-
let cacheEntry = cache.get(cacheKey);
|
|
29
|
-
if (!cacheEntry) {
|
|
30
|
-
const result = super
|
|
31
|
-
.execute()
|
|
32
|
-
.then((res) => {
|
|
33
|
-
return new WithExecutionResultCaching(res, this.createNew, this.ctx);
|
|
34
|
-
})
|
|
35
|
-
.catch((e) => {
|
|
36
|
-
cache.delete(cacheKey);
|
|
37
|
-
throw e;
|
|
38
|
-
});
|
|
39
|
-
cacheEntry = { result };
|
|
40
|
-
cache.set(cacheKey, cacheEntry);
|
|
41
|
-
}
|
|
42
|
-
return new DefinitionSanitizingExecutionResult(await cacheEntry.result, this.createNew, this.definition);
|
|
43
|
-
};
|
|
44
|
-
this.createNew = (decorated) => {
|
|
45
|
-
return new WithExecutionCaching(decorated, this.ctx);
|
|
46
|
-
};
|
|
47
26
|
}
|
|
27
|
+
execute = async () => {
|
|
28
|
+
const cacheKey = this.fingerprint();
|
|
29
|
+
const cache = this.ctx.caches.execution;
|
|
30
|
+
let cacheEntry = cache.get(cacheKey);
|
|
31
|
+
if (!cacheEntry) {
|
|
32
|
+
const result = super
|
|
33
|
+
.execute()
|
|
34
|
+
.then((res) => {
|
|
35
|
+
return new WithExecutionResultCaching(res, this.createNew, this.ctx);
|
|
36
|
+
})
|
|
37
|
+
.catch((e) => {
|
|
38
|
+
cache.delete(cacheKey);
|
|
39
|
+
throw e;
|
|
40
|
+
});
|
|
41
|
+
cacheEntry = { result };
|
|
42
|
+
cache.set(cacheKey, cacheEntry);
|
|
43
|
+
}
|
|
44
|
+
return new DefinitionSanitizingExecutionResult(await cacheEntry.result, this.createNew, this.definition);
|
|
45
|
+
};
|
|
46
|
+
createNew = (decorated) => {
|
|
47
|
+
return new WithExecutionCaching(decorated, this.ctx);
|
|
48
|
+
};
|
|
48
49
|
}
|
|
49
50
|
/**
|
|
50
51
|
* This DataView decorator makes sure that definition used in it is the same as the definition in the result.
|
|
@@ -69,55 +70,58 @@ class DefinitionSanitizingDataView extends DecoratedDataView {
|
|
|
69
70
|
class DefinitionSanitizingExecutionResult extends DecoratedExecutionResult {
|
|
70
71
|
constructor(decorated, wrapper, definitionOverride) {
|
|
71
72
|
super(decorated, wrapper);
|
|
72
|
-
this.readAll = async () => {
|
|
73
|
-
return this.withSanitizedDefinition(await super.readAll());
|
|
74
|
-
};
|
|
75
|
-
this.readWindow = async (offset, size) => {
|
|
76
|
-
return this.withSanitizedDefinition(await super.readWindow(offset, size));
|
|
77
|
-
};
|
|
78
|
-
this.withSanitizedDefinition = (original) => {
|
|
79
|
-
return new DefinitionSanitizingDataView(original, this);
|
|
80
|
-
};
|
|
81
73
|
this.definition = definitionOverride;
|
|
82
74
|
}
|
|
75
|
+
readAll = async () => {
|
|
76
|
+
return this.withSanitizedDefinition(await super.readAll());
|
|
77
|
+
};
|
|
78
|
+
readWindow = async (offset, size) => {
|
|
79
|
+
return this.withSanitizedDefinition(await super.readWindow(offset, size));
|
|
80
|
+
};
|
|
81
|
+
withSanitizedDefinition = (original) => {
|
|
82
|
+
return new DefinitionSanitizingDataView(original, this);
|
|
83
|
+
};
|
|
83
84
|
}
|
|
84
85
|
function windowKey(offset, size) {
|
|
85
86
|
return `o(${offset.join(",")})_s(${size.join(",")})`;
|
|
86
87
|
}
|
|
87
88
|
class WithExecutionResultCaching extends DecoratedExecutionResult {
|
|
89
|
+
ctx;
|
|
90
|
+
allData;
|
|
91
|
+
windows;
|
|
88
92
|
constructor(decorated, wrapper, ctx) {
|
|
89
93
|
super(decorated, wrapper);
|
|
90
94
|
this.ctx = ctx;
|
|
91
|
-
this.readAll = () => {
|
|
92
|
-
if (!this.allData) {
|
|
93
|
-
this.allData = super.readAll().catch((e) => {
|
|
94
|
-
this.allData = undefined;
|
|
95
|
-
throw e;
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return this.allData;
|
|
99
|
-
};
|
|
100
|
-
this.readWindow = (offset, size) => {
|
|
101
|
-
if (!this.windows) {
|
|
102
|
-
return super.readWindow(offset, size);
|
|
103
|
-
}
|
|
104
|
-
const cacheKey = windowKey(offset, size);
|
|
105
|
-
let window = this.windows.get(cacheKey);
|
|
106
|
-
if (!window) {
|
|
107
|
-
window = super.readWindow(offset, size).catch((e) => {
|
|
108
|
-
if (this.windows) {
|
|
109
|
-
this.windows.delete(cacheKey);
|
|
110
|
-
}
|
|
111
|
-
throw e;
|
|
112
|
-
});
|
|
113
|
-
this.windows.set(cacheKey, window);
|
|
114
|
-
}
|
|
115
|
-
return window;
|
|
116
|
-
};
|
|
117
95
|
if (cachingEnabled(this.ctx.config.maxResultWindows)) {
|
|
118
96
|
this.windows = new LRUCache({ max: this.ctx.config.maxResultWindows });
|
|
119
97
|
}
|
|
120
98
|
}
|
|
99
|
+
readAll = () => {
|
|
100
|
+
if (!this.allData) {
|
|
101
|
+
this.allData = super.readAll().catch((e) => {
|
|
102
|
+
this.allData = undefined;
|
|
103
|
+
throw e;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return this.allData;
|
|
107
|
+
};
|
|
108
|
+
readWindow = (offset, size) => {
|
|
109
|
+
if (!this.windows) {
|
|
110
|
+
return super.readWindow(offset, size);
|
|
111
|
+
}
|
|
112
|
+
const cacheKey = windowKey(offset, size);
|
|
113
|
+
let window = this.windows.get(cacheKey);
|
|
114
|
+
if (!window) {
|
|
115
|
+
window = super.readWindow(offset, size).catch((e) => {
|
|
116
|
+
if (this.windows) {
|
|
117
|
+
this.windows.delete(cacheKey);
|
|
118
|
+
}
|
|
119
|
+
throw e;
|
|
120
|
+
});
|
|
121
|
+
this.windows.set(cacheKey, window);
|
|
122
|
+
}
|
|
123
|
+
return window;
|
|
124
|
+
};
|
|
121
125
|
}
|
|
122
126
|
//
|
|
123
127
|
// Catalog caching
|
|
@@ -126,39 +130,40 @@ function optionsKey(options) {
|
|
|
126
130
|
return stringify(options);
|
|
127
131
|
}
|
|
128
132
|
class WithCatalogCaching extends DecoratedWorkspaceCatalogFactory {
|
|
133
|
+
ctx;
|
|
129
134
|
constructor(decorated, ctx) {
|
|
130
135
|
super(decorated);
|
|
131
136
|
this.ctx = ctx;
|
|
132
|
-
this.load = () => {
|
|
133
|
-
const cache = this.getOrCreateWorkspaceEntry(this.workspace).catalogForOptions;
|
|
134
|
-
const cacheKey = optionsKey(this.options);
|
|
135
|
-
let catalog = cache.get(cacheKey);
|
|
136
|
-
if (!catalog) {
|
|
137
|
-
catalog = super.load().catch((e) => {
|
|
138
|
-
cache.delete(cacheKey);
|
|
139
|
-
throw e;
|
|
140
|
-
});
|
|
141
|
-
cache.set(cacheKey, catalog);
|
|
142
|
-
}
|
|
143
|
-
return catalog;
|
|
144
|
-
};
|
|
145
|
-
this.createNew = (decorated) => {
|
|
146
|
-
return new WithCatalogCaching(decorated, this.ctx);
|
|
147
|
-
};
|
|
148
|
-
this.getOrCreateWorkspaceEntry = (workspace) => {
|
|
149
|
-
const cache = this.ctx.caches.workspaceCatalogs;
|
|
150
|
-
let cacheEntry = cache.get(workspace);
|
|
151
|
-
if (!cacheEntry) {
|
|
152
|
-
cacheEntry = {
|
|
153
|
-
catalogForOptions: new LRUCache({
|
|
154
|
-
max: this.ctx.config.maxCatalogOptions,
|
|
155
|
-
}),
|
|
156
|
-
};
|
|
157
|
-
cache.set(workspace, cacheEntry);
|
|
158
|
-
}
|
|
159
|
-
return cacheEntry;
|
|
160
|
-
};
|
|
161
137
|
}
|
|
138
|
+
load = () => {
|
|
139
|
+
const cache = this.getOrCreateWorkspaceEntry(this.workspace).catalogForOptions;
|
|
140
|
+
const cacheKey = optionsKey(this.options);
|
|
141
|
+
let catalog = cache.get(cacheKey);
|
|
142
|
+
if (!catalog) {
|
|
143
|
+
catalog = super.load().catch((e) => {
|
|
144
|
+
cache.delete(cacheKey);
|
|
145
|
+
throw e;
|
|
146
|
+
});
|
|
147
|
+
cache.set(cacheKey, catalog);
|
|
148
|
+
}
|
|
149
|
+
return catalog;
|
|
150
|
+
};
|
|
151
|
+
createNew = (decorated) => {
|
|
152
|
+
return new WithCatalogCaching(decorated, this.ctx);
|
|
153
|
+
};
|
|
154
|
+
getOrCreateWorkspaceEntry = (workspace) => {
|
|
155
|
+
const cache = this.ctx.caches.workspaceCatalogs;
|
|
156
|
+
let cacheEntry = cache.get(workspace);
|
|
157
|
+
if (!cacheEntry) {
|
|
158
|
+
cacheEntry = {
|
|
159
|
+
catalogForOptions: new LRUCache({
|
|
160
|
+
max: this.ctx.config.maxCatalogOptions,
|
|
161
|
+
}),
|
|
162
|
+
};
|
|
163
|
+
cache.set(workspace, cacheEntry);
|
|
164
|
+
}
|
|
165
|
+
return cacheEntry;
|
|
166
|
+
};
|
|
162
167
|
}
|
|
163
168
|
//
|
|
164
169
|
// Organization security settings caching
|
|
@@ -167,86 +172,73 @@ function validUrlInContextKey(url, context) {
|
|
|
167
172
|
return `${context}_${stringify(url)}`;
|
|
168
173
|
}
|
|
169
174
|
class WithSecuritySettingsCaching extends DecoratedSecuritySettingsService {
|
|
175
|
+
ctx;
|
|
170
176
|
constructor(decorated, ctx) {
|
|
171
177
|
super(decorated);
|
|
172
178
|
this.ctx = ctx;
|
|
173
|
-
this.isUrlValid = (url, context) => {
|
|
174
|
-
const cache = this.getOrCreateSecuritySettingsEntry(this.scope).valid;
|
|
175
|
-
const cacheKey = validUrlInContextKey(url, context);
|
|
176
|
-
let result = cache.get(cacheKey);
|
|
177
|
-
if (!result) {
|
|
178
|
-
result = super.isUrlValid(url, context).catch((e) => {
|
|
179
|
-
cache.delete(cacheKey);
|
|
180
|
-
throw e;
|
|
181
|
-
});
|
|
182
|
-
cache.set(cacheKey, result);
|
|
183
|
-
}
|
|
184
|
-
return result;
|
|
185
|
-
};
|
|
186
|
-
this.isDashboardPluginUrlValid = (url, workspace) => {
|
|
187
|
-
const scope = `plugins_${workspace}`;
|
|
188
|
-
const cache = this.getOrCreateSecuritySettingsEntry(scope).valid;
|
|
189
|
-
let result = cache.get(url);
|
|
190
|
-
if (!result) {
|
|
191
|
-
result = super.isDashboardPluginUrlValid(url, workspace).catch((e) => {
|
|
192
|
-
cache.delete(url);
|
|
193
|
-
throw e;
|
|
194
|
-
});
|
|
195
|
-
cache.set(url, result);
|
|
196
|
-
}
|
|
197
|
-
return result;
|
|
198
|
-
};
|
|
199
|
-
this.getOrCreateSecuritySettingsEntry = (scope) => {
|
|
200
|
-
const cache = this.ctx.caches.securitySettings;
|
|
201
|
-
let cacheEntry = cache.get(scope);
|
|
202
|
-
if (!cacheEntry) {
|
|
203
|
-
cacheEntry = {
|
|
204
|
-
valid: new LRUCache({
|
|
205
|
-
max: this.ctx.config.maxSecuritySettingsOrgUrls,
|
|
206
|
-
ttl: this.ctx.config.maxSecuritySettingsOrgUrlsAge,
|
|
207
|
-
}),
|
|
208
|
-
};
|
|
209
|
-
cache.set(scope, cacheEntry);
|
|
210
|
-
}
|
|
211
|
-
return cacheEntry;
|
|
212
|
-
};
|
|
213
179
|
}
|
|
180
|
+
isUrlValid = (url, context) => {
|
|
181
|
+
const cache = this.getOrCreateSecuritySettingsEntry(this.scope).valid;
|
|
182
|
+
const cacheKey = validUrlInContextKey(url, context);
|
|
183
|
+
let result = cache.get(cacheKey);
|
|
184
|
+
if (!result) {
|
|
185
|
+
result = super.isUrlValid(url, context).catch((e) => {
|
|
186
|
+
cache.delete(cacheKey);
|
|
187
|
+
throw e;
|
|
188
|
+
});
|
|
189
|
+
cache.set(cacheKey, result);
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
};
|
|
193
|
+
isDashboardPluginUrlValid = (url, workspace) => {
|
|
194
|
+
const scope = `plugins_${workspace}`;
|
|
195
|
+
const cache = this.getOrCreateSecuritySettingsEntry(scope).valid;
|
|
196
|
+
let result = cache.get(url);
|
|
197
|
+
if (!result) {
|
|
198
|
+
result = super.isDashboardPluginUrlValid(url, workspace).catch((e) => {
|
|
199
|
+
cache.delete(url);
|
|
200
|
+
throw e;
|
|
201
|
+
});
|
|
202
|
+
cache.set(url, result);
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
};
|
|
206
|
+
getOrCreateSecuritySettingsEntry = (scope) => {
|
|
207
|
+
const cache = this.ctx.caches.securitySettings;
|
|
208
|
+
let cacheEntry = cache.get(scope);
|
|
209
|
+
if (!cacheEntry) {
|
|
210
|
+
cacheEntry = {
|
|
211
|
+
valid: new LRUCache({
|
|
212
|
+
max: this.ctx.config.maxSecuritySettingsOrgUrls,
|
|
213
|
+
ttl: this.ctx.config.maxSecuritySettingsOrgUrlsAge,
|
|
214
|
+
}),
|
|
215
|
+
};
|
|
216
|
+
cache.set(scope, cacheEntry);
|
|
217
|
+
}
|
|
218
|
+
return cacheEntry;
|
|
219
|
+
};
|
|
214
220
|
}
|
|
215
221
|
class WithWorkspaceSettingsCaching extends DecoratedWorkspaceSettingsService {
|
|
222
|
+
ctx;
|
|
223
|
+
workspace;
|
|
216
224
|
constructor(decorated, ctx, workspace) {
|
|
217
225
|
super(decorated);
|
|
218
226
|
this.ctx = ctx;
|
|
219
227
|
this.workspace = workspace;
|
|
220
|
-
this.getSettings = () => {
|
|
221
|
-
const cache = this.getOrCreateWorkspaceEntry(this.workspace).workspaceSettings;
|
|
222
|
-
const cacheKey = this.workspace;
|
|
223
|
-
let workspaceSettings = cache.get(cacheKey);
|
|
224
|
-
if (!workspaceSettings) {
|
|
225
|
-
workspaceSettings = super.getSettings().catch((e) => {
|
|
226
|
-
cache.delete(cacheKey);
|
|
227
|
-
throw e;
|
|
228
|
-
});
|
|
229
|
-
cache.set(cacheKey, workspaceSettings);
|
|
230
|
-
}
|
|
231
|
-
return workspaceSettings;
|
|
232
|
-
};
|
|
233
|
-
this.getOrCreateWorkspaceEntry = (workspace) => {
|
|
234
|
-
const cache = this.ctx.caches.workspaceSettings;
|
|
235
|
-
let cacheEntry = cache.get(workspace);
|
|
236
|
-
if (!cacheEntry) {
|
|
237
|
-
cacheEntry = {
|
|
238
|
-
userWorkspaceSettings: new LRUCache({
|
|
239
|
-
max: this.ctx.config.maxWorkspaceSettings,
|
|
240
|
-
}),
|
|
241
|
-
workspaceSettings: new LRUCache({
|
|
242
|
-
max: this.ctx.config.maxWorkspaceSettings,
|
|
243
|
-
}),
|
|
244
|
-
};
|
|
245
|
-
cache.set(workspace, cacheEntry);
|
|
246
|
-
}
|
|
247
|
-
return cacheEntry;
|
|
248
|
-
};
|
|
249
228
|
}
|
|
229
|
+
getSettings = () => {
|
|
230
|
+
const cache = this.getOrCreateWorkspaceEntry(this.workspace).workspaceSettings;
|
|
231
|
+
const cacheKey = this.workspace;
|
|
232
|
+
let workspaceSettings = cache.get(cacheKey);
|
|
233
|
+
if (!workspaceSettings) {
|
|
234
|
+
workspaceSettings = super.getSettings().catch((e) => {
|
|
235
|
+
cache.delete(cacheKey);
|
|
236
|
+
throw e;
|
|
237
|
+
});
|
|
238
|
+
cache.set(cacheKey, workspaceSettings);
|
|
239
|
+
}
|
|
240
|
+
return workspaceSettings;
|
|
241
|
+
};
|
|
250
242
|
getSettingsForCurrentUser() {
|
|
251
243
|
const cache = this.getOrCreateWorkspaceEntry(this.workspace).userWorkspaceSettings;
|
|
252
244
|
const cacheKey = this.workspace; // we assume that the current user does not change over the life span of the backend instance
|
|
@@ -269,6 +261,22 @@ class WithWorkspaceSettingsCaching extends DecoratedWorkspaceSettingsService {
|
|
|
269
261
|
async setTheme(themeId) {
|
|
270
262
|
return super.setTheme(themeId);
|
|
271
263
|
}
|
|
264
|
+
getOrCreateWorkspaceEntry = (workspace) => {
|
|
265
|
+
const cache = this.ctx.caches.workspaceSettings;
|
|
266
|
+
let cacheEntry = cache.get(workspace);
|
|
267
|
+
if (!cacheEntry) {
|
|
268
|
+
cacheEntry = {
|
|
269
|
+
userWorkspaceSettings: new LRUCache({
|
|
270
|
+
max: this.ctx.config.maxWorkspaceSettings,
|
|
271
|
+
}),
|
|
272
|
+
workspaceSettings: new LRUCache({
|
|
273
|
+
max: this.ctx.config.maxWorkspaceSettings,
|
|
274
|
+
}),
|
|
275
|
+
};
|
|
276
|
+
cache.set(workspace, cacheEntry);
|
|
277
|
+
}
|
|
278
|
+
return cacheEntry;
|
|
279
|
+
};
|
|
272
280
|
}
|
|
273
281
|
//
|
|
274
282
|
// Attributes caching
|
|
@@ -304,36 +312,40 @@ function getOrCreateAttributeCache(ctx, workspace) {
|
|
|
304
312
|
return cacheEntry;
|
|
305
313
|
}
|
|
306
314
|
class CachedElementsQuery extends DecoratedElementsQuery {
|
|
315
|
+
ctx;
|
|
316
|
+
workspace;
|
|
317
|
+
ref;
|
|
307
318
|
constructor(decorated, ctx, workspace, ref, settings = {}) {
|
|
308
319
|
super(decorated, settings);
|
|
309
320
|
this.ctx = ctx;
|
|
310
321
|
this.workspace = workspace;
|
|
311
322
|
this.ref = ref;
|
|
312
|
-
this.query = async () => {
|
|
313
|
-
var _a;
|
|
314
|
-
const canCache = !((_a = this.settings.options) === null || _a === void 0 ? void 0 : _a.filter);
|
|
315
|
-
if (!canCache) {
|
|
316
|
-
return super.query();
|
|
317
|
-
}
|
|
318
|
-
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).attributeElementResults;
|
|
319
|
-
invariant(cache, "inconsistent attribute element cache config");
|
|
320
|
-
const cacheKey = elementsCacheKey(this.ref, this.settings);
|
|
321
|
-
let result = cache.get(cacheKey);
|
|
322
|
-
if (!result) {
|
|
323
|
-
result = super.query().catch((e) => {
|
|
324
|
-
cache.delete(cacheKey);
|
|
325
|
-
throw e;
|
|
326
|
-
});
|
|
327
|
-
cache.set(cacheKey, result);
|
|
328
|
-
}
|
|
329
|
-
return result;
|
|
330
|
-
};
|
|
331
323
|
}
|
|
324
|
+
query = async () => {
|
|
325
|
+
const canCache = !this.settings.options?.filter;
|
|
326
|
+
if (!canCache) {
|
|
327
|
+
return super.query();
|
|
328
|
+
}
|
|
329
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).attributeElementResults;
|
|
330
|
+
invariant(cache, "inconsistent attribute element cache config");
|
|
331
|
+
const cacheKey = elementsCacheKey(this.ref, this.settings);
|
|
332
|
+
let result = cache.get(cacheKey);
|
|
333
|
+
if (!result) {
|
|
334
|
+
result = super.query().catch((e) => {
|
|
335
|
+
cache.delete(cacheKey);
|
|
336
|
+
throw e;
|
|
337
|
+
});
|
|
338
|
+
cache.set(cacheKey, result);
|
|
339
|
+
}
|
|
340
|
+
return result;
|
|
341
|
+
};
|
|
332
342
|
createNew(decorated, settings) {
|
|
333
343
|
return new CachedElementsQuery(decorated, this.ctx, this.workspace, this.ref, settings);
|
|
334
344
|
}
|
|
335
345
|
}
|
|
336
346
|
class CachedElementsQueryFactory extends DecoratedElementsQueryFactory {
|
|
347
|
+
ctx;
|
|
348
|
+
workspace;
|
|
337
349
|
constructor(decorated, ctx, workspace) {
|
|
338
350
|
super(decorated);
|
|
339
351
|
this.ctx = ctx;
|
|
@@ -345,98 +357,100 @@ class CachedElementsQueryFactory extends DecoratedElementsQueryFactory {
|
|
|
345
357
|
}
|
|
346
358
|
}
|
|
347
359
|
class WithAttributesCaching extends DecoratedWorkspaceAttributesService {
|
|
360
|
+
ctx;
|
|
361
|
+
workspace;
|
|
348
362
|
constructor(decorated, ctx, workspace) {
|
|
349
363
|
super(decorated);
|
|
350
364
|
this.ctx = ctx;
|
|
351
365
|
this.workspace = workspace;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
cache.delete(idCacheKey);
|
|
361
|
-
}
|
|
362
|
-
if (uriCacheKey) {
|
|
363
|
-
cache.delete(uriCacheKey);
|
|
364
|
-
}
|
|
365
|
-
throw e;
|
|
366
|
-
});
|
|
366
|
+
}
|
|
367
|
+
getAttributeDisplayForm = (ref) => {
|
|
368
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).displayForms;
|
|
369
|
+
const idCacheKey = isIdentifierRef(ref) ? ref.identifier : undefined;
|
|
370
|
+
const uriCacheKey = isUriRef(ref) ? ref.uri : undefined;
|
|
371
|
+
let cacheItem = firstDefined([idCacheKey, uriCacheKey].map((key) => key && cache.get(key)));
|
|
372
|
+
if (!cacheItem) {
|
|
373
|
+
cacheItem = super.getAttributeDisplayForm(ref).catch((e) => {
|
|
367
374
|
if (idCacheKey) {
|
|
368
|
-
cache.
|
|
375
|
+
cache.delete(idCacheKey);
|
|
369
376
|
}
|
|
370
377
|
if (uriCacheKey) {
|
|
371
|
-
cache.
|
|
378
|
+
cache.delete(uriCacheKey);
|
|
372
379
|
}
|
|
373
|
-
|
|
374
|
-
return cacheItem;
|
|
375
|
-
};
|
|
376
|
-
this.getAttributeDisplayForms = async (refs) => {
|
|
377
|
-
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).displayForms;
|
|
378
|
-
// grab a reference to the cache results as soon as possible in case they would get evicted while loading the ones with missing data in cache
|
|
379
|
-
// then would might not be able to call cache.get again and be guaranteed to get the data
|
|
380
|
-
const refsWithCacheResults = refs.map((ref) => {
|
|
381
|
-
const idCacheKey = isIdentifierRef(ref) ? ref.identifier : undefined;
|
|
382
|
-
const uriCacheKey = isUriRef(ref) ? ref.uri : undefined;
|
|
383
|
-
const cacheHit = firstDefined([idCacheKey, uriCacheKey].map((key) => key && cache.get(key)));
|
|
384
|
-
return { ref, cacheHit };
|
|
385
|
-
});
|
|
386
|
-
const [withCacheHits, withoutCacheHits] = partition(refsWithCacheResults, ({ cacheHit }) => !!cacheHit);
|
|
387
|
-
const refsToLoad = withoutCacheHits.map((item) => item.ref);
|
|
388
|
-
const [alreadyInCache, loadedFromServer] = await Promise.all([
|
|
389
|
-
// await the stuff from cache, we need the data available (we cannot just return the promises)
|
|
390
|
-
Promise.all(withCacheHits.map((item) => item.cacheHit)),
|
|
391
|
-
// load items not in cache using the bulk operation
|
|
392
|
-
this.decorated.getAttributeDisplayForms(refsToLoad),
|
|
393
|
-
]);
|
|
394
|
-
// save newly loaded to cache for future reference
|
|
395
|
-
loadedFromServer.forEach((loaded) => {
|
|
396
|
-
const promisifiedResult = Promise.resolve(loaded);
|
|
397
|
-
// save the cache item for both types of refs
|
|
398
|
-
cache.set(loaded.id, promisifiedResult);
|
|
399
|
-
cache.set(loaded.uri, promisifiedResult);
|
|
400
|
-
});
|
|
401
|
-
const loadedRefs = loadedFromServer.map((item) => item.ref);
|
|
402
|
-
const outputRefs = this.ctx.capabilities.allowsInconsistentRelations
|
|
403
|
-
? skipMissingReferences(refs, refsToLoad, loadedRefs)
|
|
404
|
-
: refs;
|
|
405
|
-
// reconstruct the original ordering
|
|
406
|
-
const candidates = [...loadedFromServer, ...alreadyInCache];
|
|
407
|
-
return outputRefs.map((ref) => {
|
|
408
|
-
const match = candidates.find((item) => refMatchesMdObject(ref, item, "displayForm"));
|
|
409
|
-
// if this bombs, some data got lost in the process
|
|
410
|
-
invariant(match);
|
|
411
|
-
return match;
|
|
380
|
+
throw e;
|
|
412
381
|
});
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
382
|
+
if (idCacheKey) {
|
|
383
|
+
cache.set(idCacheKey, cacheItem);
|
|
384
|
+
}
|
|
385
|
+
if (uriCacheKey) {
|
|
386
|
+
cache.set(uriCacheKey, cacheItem);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return cacheItem;
|
|
390
|
+
};
|
|
391
|
+
getAttributeDisplayForms = async (refs) => {
|
|
392
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).displayForms;
|
|
393
|
+
// grab a reference to the cache results as soon as possible in case they would get evicted while loading the ones with missing data in cache
|
|
394
|
+
// then would might not be able to call cache.get again and be guaranteed to get the data
|
|
395
|
+
const refsWithCacheResults = refs.map((ref) => {
|
|
416
396
|
const idCacheKey = isIdentifierRef(ref) ? ref.identifier : undefined;
|
|
417
397
|
const uriCacheKey = isUriRef(ref) ? ref.uri : undefined;
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
398
|
+
const cacheHit = firstDefined([idCacheKey, uriCacheKey].map((key) => key && cache.get(key)));
|
|
399
|
+
return { ref, cacheHit };
|
|
400
|
+
});
|
|
401
|
+
const [withCacheHits, withoutCacheHits] = partition(refsWithCacheResults, ({ cacheHit }) => !!cacheHit);
|
|
402
|
+
const refsToLoad = withoutCacheHits.map((item) => item.ref);
|
|
403
|
+
const [alreadyInCache, loadedFromServer] = await Promise.all([
|
|
404
|
+
// await the stuff from cache, we need the data available (we cannot just return the promises)
|
|
405
|
+
Promise.all(withCacheHits.map((item) => item.cacheHit)),
|
|
406
|
+
// load items not in cache using the bulk operation
|
|
407
|
+
this.decorated.getAttributeDisplayForms(refsToLoad),
|
|
408
|
+
]);
|
|
409
|
+
// save newly loaded to cache for future reference
|
|
410
|
+
loadedFromServer.forEach((loaded) => {
|
|
411
|
+
const promisifiedResult = Promise.resolve(loaded);
|
|
412
|
+
// save the cache item for both types of refs
|
|
413
|
+
cache.set(loaded.id, promisifiedResult);
|
|
414
|
+
cache.set(loaded.uri, promisifiedResult);
|
|
415
|
+
});
|
|
416
|
+
const loadedRefs = loadedFromServer.map((item) => item.ref);
|
|
417
|
+
const outputRefs = this.ctx.capabilities.allowsInconsistentRelations
|
|
418
|
+
? skipMissingReferences(refs, refsToLoad, loadedRefs)
|
|
419
|
+
: refs;
|
|
420
|
+
// reconstruct the original ordering
|
|
421
|
+
const candidates = [...loadedFromServer, ...alreadyInCache];
|
|
422
|
+
return outputRefs.map((ref) => {
|
|
423
|
+
const match = candidates.find((item) => refMatchesMdObject(ref, item, "displayForm"));
|
|
424
|
+
// if this bombs, some data got lost in the process
|
|
425
|
+
invariant(match);
|
|
426
|
+
return match;
|
|
427
|
+
});
|
|
428
|
+
};
|
|
429
|
+
getAttributeByDisplayForm = async (ref) => {
|
|
430
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).attributesByDisplayForms;
|
|
431
|
+
const idCacheKey = isIdentifierRef(ref) ? ref.identifier : undefined;
|
|
432
|
+
const uriCacheKey = isUriRef(ref) ? ref.uri : undefined;
|
|
433
|
+
let cacheItem = firstDefined([idCacheKey, uriCacheKey].map((key) => key && cache.get(key)));
|
|
434
|
+
if (!cacheItem) {
|
|
435
|
+
// eslint-disable-next-line sonarjs/no-identical-functions
|
|
436
|
+
cacheItem = super.getAttributeByDisplayForm(ref).catch((e) => {
|
|
430
437
|
if (idCacheKey) {
|
|
431
|
-
cache.
|
|
438
|
+
cache.delete(idCacheKey);
|
|
432
439
|
}
|
|
433
440
|
if (uriCacheKey) {
|
|
434
|
-
cache.
|
|
441
|
+
cache.delete(uriCacheKey);
|
|
435
442
|
}
|
|
443
|
+
throw e;
|
|
444
|
+
});
|
|
445
|
+
if (idCacheKey) {
|
|
446
|
+
cache.set(idCacheKey, cacheItem);
|
|
436
447
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
448
|
+
if (uriCacheKey) {
|
|
449
|
+
cache.set(uriCacheKey, cacheItem);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return cacheItem;
|
|
453
|
+
};
|
|
440
454
|
elements() {
|
|
441
455
|
const decorated = this.decorated.elements();
|
|
442
456
|
return cachingEnabled(this.ctx.config.maxAttributeElementResultsPerWorkspace)
|
|
@@ -468,24 +482,19 @@ function cachingEnabled(desiredSize) {
|
|
|
468
482
|
function cacheControl(ctx) {
|
|
469
483
|
const control = {
|
|
470
484
|
resetExecutions: () => {
|
|
471
|
-
|
|
472
|
-
(_a = ctx.caches.execution) === null || _a === void 0 ? void 0 : _a.clear();
|
|
485
|
+
ctx.caches.execution?.clear();
|
|
473
486
|
},
|
|
474
487
|
resetCatalogs: () => {
|
|
475
|
-
|
|
476
|
-
(_a = ctx.caches.workspaceCatalogs) === null || _a === void 0 ? void 0 : _a.clear();
|
|
488
|
+
ctx.caches.workspaceCatalogs?.clear();
|
|
477
489
|
},
|
|
478
490
|
resetSecuritySettings: () => {
|
|
479
|
-
|
|
480
|
-
(_a = ctx.caches.securitySettings) === null || _a === void 0 ? void 0 : _a.clear();
|
|
491
|
+
ctx.caches.securitySettings?.clear();
|
|
481
492
|
},
|
|
482
493
|
resetAttributes: () => {
|
|
483
|
-
|
|
484
|
-
(_a = ctx.caches.workspaceAttributes) === null || _a === void 0 ? void 0 : _a.clear();
|
|
494
|
+
ctx.caches.workspaceAttributes?.clear();
|
|
485
495
|
},
|
|
486
496
|
resetWorkspaceSettings: () => {
|
|
487
|
-
|
|
488
|
-
(_a = ctx.caches.workspaceSettings) === null || _a === void 0 ? void 0 : _a.clear();
|
|
497
|
+
ctx.caches.workspaceSettings?.clear();
|
|
489
498
|
},
|
|
490
499
|
resetAll: () => {
|
|
491
500
|
control.resetExecutions();
|