@gooddata/sdk-backend-base 11.56.0-alpha.7 → 11.56.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.
- package/esm/cachingBackend/index.d.ts +15 -0
- package/esm/cachingBackend/index.d.ts.map +1 -1
- package/esm/cachingBackend/index.js +158 -20
- package/esm/decoratedBackend/attributes.d.ts +2 -2
- package/esm/decoratedBackend/attributes.d.ts.map +1 -1
- package/esm/decoratedBackend/attributes.js +3 -3
- package/esm/decoratedBackend/measures.d.ts +2 -2
- package/esm/decoratedBackend/measures.d.ts.map +1 -1
- package/esm/decoratedBackend/measures.js +2 -2
- package/esm/sdk-backend-base.d.ts +15 -0
- package/package.json +7 -7
|
@@ -408,6 +408,21 @@ export type CachingConfiguration = {
|
|
|
408
408
|
* When non-positive number is specified, then no caching of attribute element results will be done.
|
|
409
409
|
*/
|
|
410
410
|
maxAttributeElementResultsPerWorkspace?: number;
|
|
411
|
+
/**
|
|
412
|
+
* Maximum number of elements in an element list that may be searched locally.
|
|
413
|
+
*
|
|
414
|
+
* A query with a `filter` normally always goes to the backend. When the elements of the same attribute
|
|
415
|
+
* were already loaded in full and there are no more than this many of them, the filter is instead applied
|
|
416
|
+
* to that list in memory, which spares the backend a request per keystroke. Clearing the filter is
|
|
417
|
+
* answered from the same list. Above this many elements the query goes to the backend as before.
|
|
418
|
+
*
|
|
419
|
+
* The number of lists kept is bounded by `maxAttributeElementResultsPerWorkspace`, and local filtering is
|
|
420
|
+
* only done when that cache is enabled too.
|
|
421
|
+
*
|
|
422
|
+
* When no maximum number is specified, or the specified number is non-positive, then no local filtering
|
|
423
|
+
* will be done.
|
|
424
|
+
*/
|
|
425
|
+
maxAttributeElementsForLocalFiltering?: number;
|
|
411
426
|
/**
|
|
412
427
|
* Maximum number of settings for a workspace and for a user to cache per workspace.
|
|
413
428
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cachingBackend/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAGH,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cachingBackend/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAGH,KAAK,kBAAkB,EAmD1B,MAAM,2BAA2B,CAAC;AAwmGnC;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACvB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B;;OAEG;IACH,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAElC;;OAEG;IACH,eAAe,EAAE,MAAM,IAAI,CAAC;IAE5B;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IAEvB;;OAEG;IACH,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B;;OAEG;IACH,sBAAsB,EAAE,MAAM,IAAI,CAAC;IAEnC;;OAEG;IACH,cAAc,EAAE,MAAM,IAAI,CAAC;IAE3B;;OAEG;IACH,oBAAoB,EAAE,MAAM,IAAI,CAAC;IAEjC;;OAEG;IACH,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B;;OAEG;IACH,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B;;OAEG;IACH,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAE7B;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAC/B;;;;;;;;;;;;;;OAcG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;OASG;IACH,8BAA8B,CAAC,EAAE,MAAM,CAAC;IAExC;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,KAAK,IAAI,CAAC;IAEpD;;;;;;;;;;;OAWG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,0BAA0B,CAAC,EAAE,MAAM,CAAC;IAEpC;;;;;;;;;;OAUG;IACH,6BAA6B,CAAC,EAAE,MAAM,CAAC;IAEvC;;;;;;;;;;;;OAYG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;;;;;;;;OAWG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAElC;;;;;;;;;;;;;OAaG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;;;;;;OAYG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;;;;;;;OAWG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;;;;;;;;;;OAYG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;;;;;OAWG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAEjC;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAC;IAEtC;;;;;;;;;;;OAWG;IACH,oCAAoC,CAAC,EAAE,MAAM,CAAC;IAE9C;;;;;;;;;;;OAWG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;;;;;;;;;OAYG;IACH,+BAA+B,CAAC,EAAE,MAAM,CAAC;IAEzC;;;;;;;;;;;;OAYG;IACH,kCAAkC,CAAC,EAAE,MAAM,CAAC;IAE5C;;;;;;;;;;;;;OAaG;IACH,sCAAsC,CAAC,EAAE,MAAM,CAAC;IAEhD;;;;;;;;;;;;;OAaG;IACH,qCAAqC,CAAC,EAAE,MAAM,CAAC;IAE/C;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AASF;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,EAAE,oBA4B7C,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACvB,WAAW,EAAE,kBAAkB,EAC/B,MAAM,EAAE,oBAAoB,GAC7B,kBAAkB,CAkHpB"}
|
|
@@ -22,6 +22,7 @@ import { DecoratedSecuritySettingsService } from "../decoratedBackend/securitySe
|
|
|
22
22
|
import { DecoratedWorkspaceExportTemplatesService } from "../decoratedBackend/workspaceExportTemplates.js";
|
|
23
23
|
import { DecoratedWorkspaceSettingsService } from "../decoratedBackend/workspaceSettings.js";
|
|
24
24
|
import { mergeBbox } from "../toolkit/geoItems.js";
|
|
25
|
+
import { InMemoryPaging } from "../toolkit/paging.js";
|
|
25
26
|
//
|
|
26
27
|
// Execution caching
|
|
27
28
|
//
|
|
@@ -679,6 +680,48 @@ function elementsCacheKey(ref, settings) {
|
|
|
679
680
|
const fingerprint = stringify(settings) || "undefined";
|
|
680
681
|
return new SparkMD5().append(objRefToString(ref)).append(fingerprint).end();
|
|
681
682
|
}
|
|
683
|
+
/**
|
|
684
|
+
* Cache key of the complete element list a search over the same elements can be answered from. Paging and the
|
|
685
|
+
* options that only narrow an already loaded list are left out, so that a search finds what the unfiltered
|
|
686
|
+
* load stored; everything that decides which elements exist at all stays in.
|
|
687
|
+
*/
|
|
688
|
+
function completeElementsCacheKey(ref, settings) {
|
|
689
|
+
const { limit: _limit, offset: _offset, signal: _signal, options, ...rest } = settings;
|
|
690
|
+
const { filter: _filter, complement: _complement, cacheId: _cacheId, ...restOptions } = options ?? {};
|
|
691
|
+
return elementsCacheKey(ref, { ...rest, options: restOptions });
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Options that make the backend match against something other than the loaded titles, or return more than the
|
|
695
|
+
* elements themselves, cannot be honored locally.
|
|
696
|
+
*/
|
|
697
|
+
function canFilterLocally(options) {
|
|
698
|
+
return !options?.elements && !options?.filterByPrimaryLabel && !options?.includeTotalCountWithoutFilters;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Pages over locally filtered elements. Carries the cacheId of the backend result the elements came from, so
|
|
702
|
+
* that a later backend query can still reuse the same server-side result.
|
|
703
|
+
*/
|
|
704
|
+
class LocallyFilteredElements extends InMemoryPaging {
|
|
705
|
+
cacheId;
|
|
706
|
+
constructor(allItems, limit, offset, cacheId) {
|
|
707
|
+
super(allItems, limit, offset);
|
|
708
|
+
this.cacheId = cacheId;
|
|
709
|
+
}
|
|
710
|
+
async next() {
|
|
711
|
+
if (this.items.length === 0) {
|
|
712
|
+
return this;
|
|
713
|
+
}
|
|
714
|
+
return new LocallyFilteredElements(this.allItems, this.limit, this.offset + this.items.length, this.cacheId);
|
|
715
|
+
}
|
|
716
|
+
async goTo(pageIndex) {
|
|
717
|
+
if (this.items.length === 0) {
|
|
718
|
+
return this;
|
|
719
|
+
}
|
|
720
|
+
// Paged by the requested limit, the way a server-backed result pages, rather than by how full the
|
|
721
|
+
// current page happens to be.
|
|
722
|
+
return new LocallyFilteredElements(this.allItems, this.limit, pageIndex * this.limit, this.cacheId);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
682
725
|
/**
|
|
683
726
|
* Returns the identifier- and uri-based cache keys for the given ref. A ref yields at most one of the two.
|
|
684
727
|
*/
|
|
@@ -728,11 +771,22 @@ function getOrCreateAttributeCache(ctx, workspace) {
|
|
|
728
771
|
computedAttributes: new LRUCache({
|
|
729
772
|
max: ctx.config.maxAttributesPerWorkspace,
|
|
730
773
|
}),
|
|
774
|
+
computedAttributeExpressionTokens: new LRUCache({
|
|
775
|
+
max: ctx.config.maxAttributesPerWorkspace,
|
|
776
|
+
}),
|
|
731
777
|
attributeElementResults: cachingEnabled(ctx.config.maxAttributeElementResultsPerWorkspace)
|
|
732
778
|
? new LRUCache({
|
|
733
779
|
max: ctx.config.maxAttributeElementResultsPerWorkspace,
|
|
734
780
|
})
|
|
735
781
|
: undefined,
|
|
782
|
+
// Bounded by the same limit as the element results it is populated from, and only ever reached
|
|
783
|
+
// through the element result cache, so it is off whenever that one is.
|
|
784
|
+
completeAttributeElements: cachingEnabled(ctx.config.maxAttributeElementsForLocalFiltering) &&
|
|
785
|
+
cachingEnabled(ctx.config.maxAttributeElementResultsPerWorkspace)
|
|
786
|
+
? new LRUCache({
|
|
787
|
+
max: ctx.config.maxAttributeElementResultsPerWorkspace,
|
|
788
|
+
})
|
|
789
|
+
: undefined,
|
|
736
790
|
};
|
|
737
791
|
cache.set(workspace, cacheEntry);
|
|
738
792
|
}
|
|
@@ -749,10 +803,84 @@ class CachedElementsQuery extends DecoratedElementsQuery {
|
|
|
749
803
|
this.ref = ref;
|
|
750
804
|
}
|
|
751
805
|
query = async () => {
|
|
752
|
-
const
|
|
753
|
-
if (
|
|
806
|
+
const local = this.queryLocally();
|
|
807
|
+
if (local) {
|
|
808
|
+
return local;
|
|
809
|
+
}
|
|
810
|
+
if (this.settings.options?.filter) {
|
|
754
811
|
return super.query();
|
|
755
812
|
}
|
|
813
|
+
const result = await this.queryCached();
|
|
814
|
+
this.rememberCompleteElements(result);
|
|
815
|
+
return result;
|
|
816
|
+
};
|
|
817
|
+
/**
|
|
818
|
+
* Answers from an element list already loaded in full, without asking the backend. Covers both a search
|
|
819
|
+
* over that list and the unfiltered query a cleared search makes, which is the same query the list came
|
|
820
|
+
* from. Returns undefined when there is no such list, or when the query asks for something it cannot
|
|
821
|
+
* answer.
|
|
822
|
+
*/
|
|
823
|
+
queryLocally() {
|
|
824
|
+
const { limit, offset = 0, options } = this.settings;
|
|
825
|
+
const filter = options?.filter;
|
|
826
|
+
const maxElements = this.ctx.config.maxAttributeElementsForLocalFiltering;
|
|
827
|
+
// A page the local path cannot represent is left to the backend to accept or reject, so that the
|
|
828
|
+
// decorator never turns a backend's answer into a local failure. Without an explicit limit there is
|
|
829
|
+
// no page size to honor either - the backend's own default is not known here.
|
|
830
|
+
if (limit === undefined || limit <= 0 || offset < 0) {
|
|
831
|
+
return undefined;
|
|
832
|
+
}
|
|
833
|
+
if (!cachingEnabled(maxElements) || !canFilterLocally(options)) {
|
|
834
|
+
return undefined;
|
|
835
|
+
}
|
|
836
|
+
// `%` and `_` are wildcards in the pattern the backend matches with and are deliberately left
|
|
837
|
+
// unescaped there, so a pattern containing either means something a substring match would get wrong.
|
|
838
|
+
if (filter?.includes("%") || filter?.includes("_")) {
|
|
839
|
+
return undefined;
|
|
840
|
+
}
|
|
841
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).completeAttributeElements;
|
|
842
|
+
const complete = cache?.get(completeElementsCacheKey(this.ref, this.settings));
|
|
843
|
+
if (!complete || complete.items.length > maxElements) {
|
|
844
|
+
return undefined;
|
|
845
|
+
}
|
|
846
|
+
// A caller naming a result keeps the elements of that result, not of whichever one happens to be
|
|
847
|
+
// loaded. The list can still answer the query that has yet to be given a result to hold on to.
|
|
848
|
+
if (options?.cacheId !== undefined && options.cacheId !== complete.cacheId) {
|
|
849
|
+
return undefined;
|
|
850
|
+
}
|
|
851
|
+
return new LocallyFilteredElements(this.matching(complete.items), limit, offset, complete.cacheId);
|
|
852
|
+
}
|
|
853
|
+
matching(elements) {
|
|
854
|
+
const { filter, complement = false } = this.settings.options ?? {};
|
|
855
|
+
if (!filter) {
|
|
856
|
+
return elements;
|
|
857
|
+
}
|
|
858
|
+
const needle = filter.toLowerCase();
|
|
859
|
+
// Matching goes against the title even where formattedTitle is what the user reads, because that is
|
|
860
|
+
// what the backend matches. An element without a title matches neither the pattern nor its negation,
|
|
861
|
+
// the same as SQL NULL against (NOT) ILIKE.
|
|
862
|
+
return elements.filter((element) => typeof element.title === "string" &&
|
|
863
|
+
element.title.toLowerCase().includes(needle) !== complement);
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Keeps an element list the backend returned in full, so that a later search over it can be answered
|
|
867
|
+
* locally. A page of a longer list says nothing about the elements it does not contain.
|
|
868
|
+
*/
|
|
869
|
+
rememberCompleteElements(result) {
|
|
870
|
+
const maxElements = this.ctx.config.maxAttributeElementsForLocalFiltering;
|
|
871
|
+
if (!cachingEnabled(maxElements) ||
|
|
872
|
+
result.offset !== 0 ||
|
|
873
|
+
result.items.length !== result.totalCount ||
|
|
874
|
+
result.items.length > maxElements) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).completeAttributeElements;
|
|
878
|
+
cache?.set(completeElementsCacheKey(this.ref, this.settings), {
|
|
879
|
+
items: result.items,
|
|
880
|
+
cacheId: result.cacheId,
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
async queryCached() {
|
|
756
884
|
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).attributeElementResults;
|
|
757
885
|
invariant(cache, "inconsistent attribute element cache config");
|
|
758
886
|
const cacheKey = elementsCacheKey(this.ref, this.settings);
|
|
@@ -782,7 +910,7 @@ class CachedElementsQuery extends DecoratedElementsQuery {
|
|
|
782
910
|
return promise;
|
|
783
911
|
}
|
|
784
912
|
return result;
|
|
785
|
-
}
|
|
913
|
+
}
|
|
786
914
|
createNew(decorated, settings) {
|
|
787
915
|
return new CachedElementsQuery(decorated, this.ctx, this.workspace, this.ref, settings);
|
|
788
916
|
}
|
|
@@ -1081,26 +1209,20 @@ class WithAttributesCaching extends DecoratedWorkspaceAttributesService {
|
|
|
1081
1209
|
}
|
|
1082
1210
|
return result;
|
|
1083
1211
|
};
|
|
1084
|
-
getConnectedAttributesByDisplayForm = (ref) => {
|
|
1212
|
+
getConnectedAttributesByDisplayForm = (ref, options) => {
|
|
1085
1213
|
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).connectedAttributes;
|
|
1086
|
-
|
|
1087
|
-
|
|
1214
|
+
// The ref is serialized rather than reduced to its identifier: a computed attribute's
|
|
1215
|
+
// display form and a label may share an id, and this cache must not conflate them. The
|
|
1216
|
+
// option changes the result set, so it is part of the key too.
|
|
1217
|
+
const optionsSuffix = options?.includeComputedAttributes ? ":withComputedAttributes" : "";
|
|
1218
|
+
const cacheKey = `${serializeObjRef(ref)}${optionsSuffix}`;
|
|
1219
|
+
let cacheItem = cache.get(cacheKey);
|
|
1088
1220
|
if (!cacheItem) {
|
|
1089
|
-
cacheItem = super.getConnectedAttributesByDisplayForm(ref).catch((e) => {
|
|
1090
|
-
|
|
1091
|
-
cache.delete(idCacheKey);
|
|
1092
|
-
}
|
|
1093
|
-
if (uriCacheKey) {
|
|
1094
|
-
cache.delete(uriCacheKey);
|
|
1095
|
-
}
|
|
1221
|
+
cacheItem = super.getConnectedAttributesByDisplayForm(ref, options).catch((e) => {
|
|
1222
|
+
cache.delete(cacheKey);
|
|
1096
1223
|
throw e;
|
|
1097
1224
|
});
|
|
1098
|
-
|
|
1099
|
-
cache.set(idCacheKey, cacheItem);
|
|
1100
|
-
}
|
|
1101
|
-
if (uriCacheKey) {
|
|
1102
|
-
cache.set(uriCacheKey, cacheItem);
|
|
1103
|
-
}
|
|
1225
|
+
cache.set(cacheKey, cacheItem);
|
|
1104
1226
|
}
|
|
1105
1227
|
return cacheItem;
|
|
1106
1228
|
};
|
|
@@ -1993,7 +2115,9 @@ class WithComputedAttributesCaching extends DecoratedWorkspaceComputedAttributes
|
|
|
1993
2115
|
// (loadUserData), and computed-attribute writes are rare management actions, so one refetch
|
|
1994
2116
|
// beats chasing every key shape. Same stance as the automations caching above.
|
|
1995
2117
|
invalidateComputedAttributes = () => {
|
|
1996
|
-
getOrCreateAttributeCache(this.ctx, this.workspace)
|
|
2118
|
+
const cacheEntry = getOrCreateAttributeCache(this.ctx, this.workspace);
|
|
2119
|
+
cacheEntry.computedAttributes.clear();
|
|
2120
|
+
cacheEntry.computedAttributeExpressionTokens.clear();
|
|
1997
2121
|
};
|
|
1998
2122
|
createComputedAttribute = async (computedAttribute) => {
|
|
1999
2123
|
const result = await super.createComputedAttribute(computedAttribute);
|
|
@@ -2030,6 +2154,19 @@ class WithComputedAttributesCaching extends DecoratedWorkspaceComputedAttributes
|
|
|
2030
2154
|
}
|
|
2031
2155
|
return cacheItem;
|
|
2032
2156
|
};
|
|
2157
|
+
getComputedAttributeExpressionTokens = async (ref) => {
|
|
2158
|
+
const cache = getOrCreateAttributeCache(this.ctx, this.workspace).computedAttributeExpressionTokens;
|
|
2159
|
+
const cacheKey = serializeObjRef(ref);
|
|
2160
|
+
let cacheItem = cache.get(cacheKey);
|
|
2161
|
+
if (!cacheItem) {
|
|
2162
|
+
cacheItem = super.getComputedAttributeExpressionTokens(ref).catch((e) => {
|
|
2163
|
+
cache.delete(cacheKey);
|
|
2164
|
+
throw e;
|
|
2165
|
+
});
|
|
2166
|
+
cache.set(cacheKey, cacheItem);
|
|
2167
|
+
}
|
|
2168
|
+
return cacheItem;
|
|
2169
|
+
};
|
|
2033
2170
|
}
|
|
2034
2171
|
function cachedComputedAttributes(ctx) {
|
|
2035
2172
|
return (original, workspace) => new WithComputedAttributesCaching(original, ctx, workspace);
|
|
@@ -2196,6 +2333,7 @@ export const RecommendedCachingConfiguration = {
|
|
|
2196
2333
|
maxCommonAttributesPerWorkspace: 500,
|
|
2197
2334
|
maxConnectedAttributesPerWorkspace: 500,
|
|
2198
2335
|
maxAttributeElementResultsPerWorkspace: 100,
|
|
2336
|
+
maxAttributeElementsForLocalFiltering: 500,
|
|
2199
2337
|
maxWorkspaceSettings: 1,
|
|
2200
2338
|
maxAutomationsWorkspaces: 1,
|
|
2201
2339
|
maxInsightsPerWorkspace: 50,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IAttributeWithReferences, type IAttributesQuery, type IElementsQueryFactory, type IWorkspaceAttributesService } from "@gooddata/sdk-backend-spi";
|
|
1
|
+
import { type IAttributeWithReferences, type IAttributesQuery, type IConnectedAttributesOptions, type IElementsQueryFactory, type IWorkspaceAttributesService } from "@gooddata/sdk-backend-spi";
|
|
2
2
|
import { type IAttributeDisplayFormMetadataObject, type IAttributeMetadataObject, type IMetadataObject, type IMetadataObjectBase, type IMetadataObjectIdentity, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
/**
|
|
4
4
|
* @alpha
|
|
@@ -19,7 +19,7 @@ export declare abstract class DecoratedWorkspaceAttributesService implements IWo
|
|
|
19
19
|
getCommonAttributesBatch(attributesRefsBatch: ObjRef[][]): Promise<ObjRef[][]>;
|
|
20
20
|
getAttributeDatasetMeta(ref: ObjRef): Promise<IMetadataObject>;
|
|
21
21
|
getAttributesWithReferences(refs: ObjRef[]): Promise<IAttributeWithReferences[]>;
|
|
22
|
-
getConnectedAttributesByDisplayForm(ref: ObjRef): Promise<ObjRef[]>;
|
|
22
|
+
getConnectedAttributesByDisplayForm(ref: ObjRef, options?: IConnectedAttributesOptions): Promise<ObjRef[]>;
|
|
23
23
|
getAttributesQuery(): IAttributesQuery;
|
|
24
24
|
}
|
|
25
25
|
//# sourceMappingURL=attributes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../src/decoratedBackend/attributes.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,mCAAmC,EACxC,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,8BAAsB,mCAAoC,YAAW,2BAA2B;IACtE,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,2BAA2B;IAA/E,SAAS,aAAgC,SAAS,EAAE,2BAA2B,EAAI;IAE5E,QAAQ,IAAI,qBAAqB,CAEvC;IAEM,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAExF;IAEM,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,mCAAmC,EAAE,CAAC,CAE9F;IAEM,YAAY,CACf,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAA;KAAO,GACrC,OAAO,CAAC,wBAAwB,CAAC,CAEnC;IAEM,mBAAmB,CACtB,gBAAgB,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,uBAAuB,GACzE,OAAO,CAAC,wBAAwB,CAAC,CAEnC;IAEM,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAE/E;IAEM,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAExE;IAEM,mBAAmB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAErE;IAEM,wBAAwB,CAAC,mBAAmB,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAEpF;IAEM,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEpE;IAEM,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAEtF;IAEM,mCAAmC,
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../src/decoratedBackend/attributes.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,gBAAgB,EACrB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,mCAAmC,EACxC,KAAK,wBAAwB,EAC7B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,8BAAsB,mCAAoC,YAAW,2BAA2B;IACtE,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,2BAA2B;IAA/E,SAAS,aAAgC,SAAS,EAAE,2BAA2B,EAAI;IAE5E,QAAQ,IAAI,qBAAqB,CAEvC;IAEM,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAExF;IAEM,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,mCAAmC,EAAE,CAAC,CAE9F;IAEM,YAAY,CACf,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,CAAA;KAAO,GACrC,OAAO,CAAC,wBAAwB,CAAC,CAEnC;IAEM,mBAAmB,CACtB,gBAAgB,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,uBAAuB,GACzE,OAAO,CAAC,wBAAwB,CAAC,CAEnC;IAEM,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAE/E;IAEM,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAExE;IAEM,mBAAmB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAErE;IAEM,wBAAwB,CAAC,mBAAmB,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAEpF;IAEM,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEpE;IAEM,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAEtF;IAEM,mCAAmC,CACtC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,2BAA2B,GACtC,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;IAEM,kBAAkB,IAAI,gBAAgB,CAE5C;CACJ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// (C) 2021-
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
2
|
/**
|
|
3
3
|
* @alpha
|
|
4
4
|
*/
|
|
@@ -40,8 +40,8 @@ export class DecoratedWorkspaceAttributesService {
|
|
|
40
40
|
getAttributesWithReferences(refs) {
|
|
41
41
|
return this.decorated.getAttributesWithReferences(refs);
|
|
42
42
|
}
|
|
43
|
-
getConnectedAttributesByDisplayForm(ref) {
|
|
44
|
-
return this.decorated.getConnectedAttributesByDisplayForm(ref);
|
|
43
|
+
getConnectedAttributesByDisplayForm(ref, options) {
|
|
44
|
+
return this.decorated.getConnectedAttributesByDisplayForm(ref, options);
|
|
45
45
|
}
|
|
46
46
|
getAttributesQuery() {
|
|
47
47
|
return this.decorated.getAttributesQuery();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IGetMeasureOptions, type IMeasureExpressionToken, type IMeasureKeyDrivers, type IMeasureReferencing, type IMeasuresQuery, type ISaveMeasureOptions, type IUpdateMeasureMetaPayload, type IWorkspaceMeasuresService } from "@gooddata/sdk-backend-spi";
|
|
1
|
+
import { type IConnectedAttributesOptions, type IGetMeasureOptions, type IMeasureExpressionToken, type IMeasureKeyDrivers, type IMeasureReferencing, type IMeasuresQuery, type ISaveMeasureOptions, type IUpdateMeasureMetaPayload, type IWorkspaceMeasuresService } from "@gooddata/sdk-backend-spi";
|
|
2
2
|
import { type IMeasure, type IMeasureMetadataObject, type IMeasureMetadataObjectDefinition, type IObjectCertificationWrite, type ObjRef } from "@gooddata/sdk-model";
|
|
3
3
|
/**
|
|
4
4
|
* @alpha
|
|
@@ -18,6 +18,6 @@ export declare abstract class DecoratedWorkspaceMeasuresService implements IWork
|
|
|
18
18
|
getMeasureReferencingObjects(measureRef: ObjRef): Promise<IMeasureReferencing>;
|
|
19
19
|
getMeasuresQuery(): IMeasuresQuery;
|
|
20
20
|
getMeasure(ref: ObjRef, options?: IGetMeasureOptions): Promise<IMeasureMetadataObject>;
|
|
21
|
-
getConnectedAttributes(definition: IMeasure, auxMeasures?: IMeasure[]): Promise<ObjRef[]>;
|
|
21
|
+
getConnectedAttributes(definition: IMeasure, auxMeasures?: IMeasure[], options?: IConnectedAttributesOptions): Promise<ObjRef[]>;
|
|
22
22
|
}
|
|
23
23
|
//# sourceMappingURL=measures.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measures.d.ts","sourceRoot":"","sources":["../../src/decoratedBackend/measures.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EACjC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,EAC9B,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,8BAAsB,iCAAkC,YAAW,yBAAyB;IAClE,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,yBAAyB;IAA7E,SAAS,aAAgC,SAAS,EAAE,yBAAyB,EAAI;IAEjF,iBAAiB,CACb,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE;QACN,aAAa,EAAE,KAAK,GAAG,MAAM,CAAC;KACjC,GACF,OAAO,CAAC,kBAAkB,CAAC,CAE7B;IAED,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAE1E;IAED,aAAa,CACT,OAAO,EAAE,gCAAgC,EACzC,OAAO,CAAC,EAAE,mBAAmB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAEjC;IAED,aAAa,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAE9E;IAED,iBAAiB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAErF;IAED,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;IAED,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;IAED,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAE7E;IAED,gBAAgB,IAAI,cAAc,CAEjC;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAErF;IAED,sBAAsB,
|
|
1
|
+
{"version":3,"file":"measures.d.ts","sourceRoot":"","sources":["../../src/decoratedBackend/measures.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,EACjC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,sBAAsB,EAC3B,KAAK,gCAAgC,EACrC,KAAK,yBAAyB,EAC9B,KAAK,MAAM,EACd,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,8BAAsB,iCAAkC,YAAW,yBAAyB;IAClE,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,yBAAyB;IAA7E,SAAS,aAAgC,SAAS,EAAE,yBAAyB,EAAI;IAEjF,iBAAiB,CACb,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE;QACN,aAAa,EAAE,KAAK,GAAG,MAAM,CAAC;KACjC,GACF,OAAO,CAAC,kBAAkB,CAAC,CAE7B;IAED,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAE1E;IAED,aAAa,CACT,OAAO,EAAE,gCAAgC,EACzC,OAAO,CAAC,EAAE,mBAAmB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAEjC;IAED,aAAa,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAE9E;IAED,iBAAiB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAErF;IAED,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtF;IAED,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;IAED,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAE7E;IAED,gBAAgB,IAAI,cAAc,CAEjC;IAED,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAErF;IAED,sBAAsB,CAClB,UAAU,EAAE,QAAQ,EACpB,WAAW,CAAC,EAAE,QAAQ,EAAE,EACxB,OAAO,CAAC,EAAE,2BAA2B,GACtC,OAAO,CAAC,MAAM,EAAE,CAAC,CAEnB;CACJ"}
|
|
@@ -37,7 +37,7 @@ export class DecoratedWorkspaceMeasuresService {
|
|
|
37
37
|
getMeasure(ref, options) {
|
|
38
38
|
return this.decorated.getMeasure(ref, options);
|
|
39
39
|
}
|
|
40
|
-
getConnectedAttributes(definition, auxMeasures) {
|
|
41
|
-
return this.decorated.getConnectedAttributes(definition, auxMeasures);
|
|
40
|
+
getConnectedAttributes(definition, auxMeasures, options) {
|
|
41
|
+
return this.decorated.getConnectedAttributes(definition, auxMeasures, options);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -854,6 +854,21 @@ export declare type CachingConfiguration = {
|
|
|
854
854
|
* When non-positive number is specified, then no caching of attribute element results will be done.
|
|
855
855
|
*/
|
|
856
856
|
maxAttributeElementResultsPerWorkspace?: number;
|
|
857
|
+
/**
|
|
858
|
+
* Maximum number of elements in an element list that may be searched locally.
|
|
859
|
+
*
|
|
860
|
+
* A query with a `filter` normally always goes to the backend. When the elements of the same attribute
|
|
861
|
+
* were already loaded in full and there are no more than this many of them, the filter is instead applied
|
|
862
|
+
* to that list in memory, which spares the backend a request per keystroke. Clearing the filter is
|
|
863
|
+
* answered from the same list. Above this many elements the query goes to the backend as before.
|
|
864
|
+
*
|
|
865
|
+
* The number of lists kept is bounded by `maxAttributeElementResultsPerWorkspace`, and local filtering is
|
|
866
|
+
* only done when that cache is enabled too.
|
|
867
|
+
*
|
|
868
|
+
* When no maximum number is specified, or the specified number is non-positive, then no local filtering
|
|
869
|
+
* will be done.
|
|
870
|
+
*/
|
|
871
|
+
maxAttributeElementsForLocalFiltering?: number;
|
|
857
872
|
/**
|
|
858
873
|
* Maximum number of settings for a workspace and for a user to cache per workspace.
|
|
859
874
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-backend-base",
|
|
3
|
-
"version": "11.56.0
|
|
3
|
+
"version": "11.56.0",
|
|
4
4
|
"description": "GoodData.UI SDK - Base for backend implementations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"ts-invariant": "0.10.3",
|
|
30
30
|
"tslib": "2.8.1",
|
|
31
31
|
"uuid": "11.1.1",
|
|
32
|
-
"@gooddata/sdk-backend-spi": "11.56.0
|
|
33
|
-
"@gooddata/
|
|
34
|
-
"@gooddata/
|
|
32
|
+
"@gooddata/sdk-backend-spi": "11.56.0",
|
|
33
|
+
"@gooddata/util": "11.56.0",
|
|
34
|
+
"@gooddata/sdk-model": "11.56.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@microsoft/api-documenter": "7.30.10",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"oxlint-tsgolint": "0.15.0",
|
|
54
54
|
"typescript": "7.0.2",
|
|
55
55
|
"vitest": "4.1.8",
|
|
56
|
-
"@gooddata/oxlint-config": "11.56.0
|
|
57
|
-
"@gooddata/
|
|
58
|
-
"@gooddata/
|
|
56
|
+
"@gooddata/oxlint-config": "11.56.0",
|
|
57
|
+
"@gooddata/reference-workspace": "11.56.0",
|
|
58
|
+
"@gooddata/eslint-config": "11.56.0"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"_phase:build": "npm run build",
|