@gooddata/sdk-backend-tiger 11.62.0-alpha.2 → 11.62.0-alpha.3

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 (25) hide show
  1. package/esm/__version.d.ts +1 -1
  2. package/esm/__version.js +1 -1
  3. package/esm/backend/settings/mapping.js +2 -0
  4. package/esm/backend/workspace/attributes/elements/dependentDateFilters.d.ts.map +1 -1
  5. package/esm/backend/workspace/attributes/elements/dependentDateFilters.js +26 -10
  6. package/esm/backend/workspace/dashboards/referenceAvailability.d.ts +13 -10
  7. package/esm/backend/workspace/dashboards/referenceAvailability.d.ts.map +1 -1
  8. package/esm/backend/workspace/dashboards/referenceAvailability.js +28 -13
  9. package/esm/backend/workspace/genAI/index.d.ts.map +1 -1
  10. package/esm/backend/workspace/genAI/index.js +13 -5
  11. package/esm/convertors/fromBackend/AutomationConverter.d.ts.map +1 -1
  12. package/esm/convertors/fromBackend/AutomationConverter.js +4 -2
  13. package/esm/convertors/fromBackend/afm/FilterConverter.d.ts.map +1 -1
  14. package/esm/convertors/fromBackend/afm/FilterConverter.js +42 -0
  15. package/esm/convertors/shared/absoluteGranularityLiterals.d.ts +38 -0
  16. package/esm/convertors/shared/absoluteGranularityLiterals.d.ts.map +1 -0
  17. package/esm/convertors/shared/absoluteGranularityLiterals.js +82 -0
  18. package/esm/convertors/shared/storedFilterConverter.d.ts +12 -2
  19. package/esm/convertors/shared/storedFilterConverter.d.ts.map +1 -1
  20. package/esm/convertors/shared/storedFilterConverter.js +16 -5
  21. package/esm/convertors/toBackend/InsightConverter.d.ts.map +1 -1
  22. package/esm/convertors/toBackend/InsightConverter.js +6 -3
  23. package/esm/convertors/toBackend/afm/FilterConverter.d.ts.map +1 -1
  24. package/esm/convertors/toBackend/afm/FilterConverter.js +23 -2
  25. package/package.json +12 -12
@@ -1,4 +1,4 @@
1
- export declare const LIB_VERSION = "11.62.0-alpha.2";
1
+ export declare const LIB_VERSION = "11.62.0-alpha.3";
2
2
  export declare const LIB_DESCRIPTION = "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN";
3
3
  export declare const LIB_NAME = "@gooddata/sdk-backend-tiger";
4
4
  //# sourceMappingURL=__version.d.ts.map
package/esm/__version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // (C) 2021 GoodData Corporation
2
2
  // DO NOT CHANGE THIS FILE, IT IS RE-GENERATED ON EVERY BUILD
3
- export const LIB_VERSION = "11.62.0-alpha.2";
3
+ export const LIB_VERSION = "11.62.0-alpha.3";
4
4
  export const LIB_DESCRIPTION = "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN";
5
5
  export const LIB_NAME = "@gooddata/sdk-backend-tiger";
@@ -42,6 +42,8 @@ const TYPE_TO_KEY_MAP = {
42
42
  ENABLE_PARTIAL_DATA_RESULTS: "enablePartialDataResults",
43
43
  ENABLE_NULL_JOINS: "enableNullJoins",
44
44
  ENABLE_TIMEZONE_CHANGE: "enableTimezoneChange",
45
+ DEFAULT_METRIC_VISIBILITY: "defaultMetricVisibility",
46
+ DEFAULT_VISUALIZATION_VISIBILITY: "defaultVisualizationVisibility",
45
47
  };
46
48
  export function mapTypeToKey(type, fallback = "") {
47
49
  // For undefined or unmapped type - return fallback
@@ -1 +1 @@
1
- {"version":3,"file":"dependentDateFilters.d.ts","sourceRoot":"","sources":["../../../../../src/backend/workspace/attributes/elements/dependentDateFilters.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAEH,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EAI3B,MAAM,qBAAqB,CAAC;AAI7B,wBAAgB,2CAA2C,CACvD,UAAU,EAAE,mBAAmB,GAAG,mBAAmB,uBAOxD"}
1
+ {"version":3,"file":"dependentDateFilters.d.ts","sourceRoot":"","sources":["../../../../../src/backend/workspace/attributes/elements/dependentDateFilters.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAEH,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EAI3B,MAAM,qBAAqB,CAAC;AAQ7B,wBAAgB,2CAA2C,CACvD,UAAU,EAAE,mBAAmB,GAAG,mBAAmB,uBAOxD"}
@@ -1,7 +1,8 @@
1
- // (C) 2024-2025 GoodData Corporation
1
+ // (C) 2024-2026 GoodData Corporation
2
2
  import { invariant } from "ts-invariant";
3
3
  import { isRelativeBoundedDateFilter, isRelativeDateFilter, isUriRef, } from "@gooddata/sdk-model";
4
4
  import { toTigerGranularity } from "../../../../convertors/fromBackend/dateGranularityConversions.js";
5
+ import { hasPeriodLiteral, toWholePeriodLiterals, } from "../../../../convertors/shared/absoluteGranularityLiterals.js";
5
6
  export function mapDashboardDateFilterToDependentDateFilter(dateFilter) {
6
7
  if (isRelativeDateFilter(dateFilter)) {
7
8
  return newRelativeDependentDateFilter(dateFilter);
@@ -37,19 +38,34 @@ function newRelativeDependentDateFilter(dateFilter) {
37
38
  };
38
39
  }
39
40
  function newAbsoluteDependentDateFilter(dateFilter) {
40
- const localIdentifier = dateFilter.absoluteDateFilter.dataSet;
41
+ const { dataSet: localIdentifier, from, to, granularity } = dateFilter.absoluteDateFilter;
41
42
  invariant(!isUriRef(localIdentifier));
43
+ const dataset = {
44
+ identifier: {
45
+ id: localIdentifier.identifier,
46
+ type: "dataset",
47
+ },
48
+ };
49
+ if (hasPeriodLiteral(granularity)) {
50
+ const literals = toWholePeriodLiterals(granularity, from, to);
51
+ if (literals) {
52
+ return {
53
+ dateFilter: {
54
+ absoluteGranularityDateFilter: {
55
+ dataset,
56
+ granularity: toTigerGranularity(granularity),
57
+ ...literals,
58
+ },
59
+ },
60
+ };
61
+ }
62
+ }
42
63
  return {
43
64
  dateFilter: {
44
65
  absoluteDateFilter: {
45
- dataset: {
46
- identifier: {
47
- id: localIdentifier.identifier,
48
- type: "dataset",
49
- },
50
- },
51
- from: dateFilter.absoluteDateFilter.from,
52
- to: dateFilter.absoluteDateFilter.to,
66
+ dataset,
67
+ from,
68
+ to,
53
69
  },
54
70
  },
55
71
  };
@@ -5,6 +5,7 @@ import { type TigerAuthenticatedCallGuard } from "../../../types/index.js";
5
5
  /** The same for the filter-context GET, which links the objects the filters use. */
6
6
  declare const FILTER_CONTEXT_RELATIONSHIP_KEYS: {
7
7
  readonly displayForm: "labels";
8
+ readonly attribute: "attributes";
8
9
  readonly computedAttribute: "computedAttributes";
9
10
  readonly measure: "metrics";
10
11
  readonly fact: "facts";
@@ -23,19 +24,21 @@ export declare function resolveUnavailableReferences(document: JsonApiAnalytical
23
24
  */
24
25
  export declare function resolveUnavailableDashboardReferences(document: JsonApiAnalyticalDashboardOutDocument, dashboard: IDashboard, types: SupportedDashboardReferenceTypes[]): IUnavailableDashboardReference[];
25
26
  /**
26
- * Resolves which filter display forms, computed attributes, metrics and facts referenced by a filter
27
- * context are unavailable. Each inspected type must have been requested as an include (`labels`,
28
- * `computedAttributes`, `metrics`, `facts`) so the response contains both relationship linkages and
29
- * document-level `meta.restricted` for it.
27
+ * Resolves which filter display forms, attributes, computed attributes, metrics and facts referenced by
28
+ * a filter context are unavailable. Each inspected type must have been requested as an include
29
+ * (`labels`, `attributes`, `computedAttributes`, `metrics`, `facts`) so the response contains both
30
+ * relationship linkages and document-level `meta.restricted` for it.
30
31
  */
31
32
  export declare function resolveUnavailableFilterContextReferences(context: JsonApiFilterContextOut, restricted: RestrictedObject[] | undefined, inspected: FilterContextInspectedType[]): IUnavailableDashboardReference[];
32
33
  /**
33
- * Filter labels, computed attributes, metrics and facts relate to their filter-context entities: the
34
- * dashboard GET side-loads the filter contexts as bare items (no `relationships`), so the existence
35
- * linkage for filter objects is reachable only through a direct filter-context GET with `include=labels`
36
- * (and `computedAttributes`, `metrics`, `facts`), hence this one batched extra request. Types other than
37
- * labels are included only when a filter uses them (metric value filters, filters on computed
38
- * attributes, metrics and facts limiting a filter's values), so other dashboards never request them.
34
+ * Filter labels, attributes, computed attributes, metrics and facts relate to their filter-context
35
+ * entities: the dashboard GET side-loads the filter contexts as bare items (no `relationships`), so the
36
+ * existence linkage for filter objects is reachable only through a direct filter-context GET with
37
+ * `include=labels` (and `attributes`, `computedAttributes`, `metrics`, `facts`), hence this one batched
38
+ * extra request. Types other than labels are included only when a filter uses them (metric value
39
+ * filters and the attributes they are computed for, filters on computed attributes, metrics, facts
40
+ * and "Count of" attributes or computed attributes limiting a filter's values), so other dashboards
41
+ * never request them.
39
42
  * It inspects the contexts of the effective dashboard, so a `filterContextRef` override is covered;
40
43
  * the synthetic export-override context has no entity behind it and is skipped.
41
44
  * It would become redundant if the backend emitted `relationships.labels` on the filter-context items
@@ -1 +1 @@
1
- {"version":3,"file":"referenceAvailability.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/dashboards/referenceAvailability.ts"],"names":[],"mappings":"AAEA,OAAO,EAIH,KAAK,qCAAqC,EAC1C,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EAExB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACR,8BAA8B,EAC9B,gCAAgC,EACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,UAAU,EAQlB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAqD3E,oFAAoF;AACpF,QAAA,MAAM,gCAAgC;0BACrB,QAAQ;gCACF,oBAAoB;sBAC9B,SAAS;mBACZ,OAAO;CACwD,CAAC;AAE1E,KAAK,0BAA0B,GAAG,MAAM,OAAO,gCAAgC,CAAC;AAsEhF;;GAEG;AACH,wBAAgB,4BAA4B,CACxC,QAAQ,EAAE,qCAAqC,EAC/C,KAAK,EAAE,gCAAgC,EAAE,GAC1C,8BAA8B,EAAE,CAKlC;AAED;;;;;;GAMG;AACH,wBAAgB,qCAAqC,CACjD,QAAQ,EAAE,qCAAqC,EAC/C,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,gCAAgC,EAAE,GAC1C,8BAA8B,EAAE,CAWlC;AAED;;;;;GAKG;AACH,wBAAgB,yCAAyC,CACrD,OAAO,EAAE,uBAAuB,EAChC,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC1C,SAAS,EAAE,0BAA0B,EAAE,GACxC,8BAA8B,EAAE,CAMlC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,kCAAkC,CACpD,QAAQ,EAAE,2BAA2B,EACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,gCAAgC,EAAE,GAC1C,OAAO,CAAC,8BAA8B,EAAE,CAAC,CA4B3C;AA6BD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,EAAE,CAQ3E"}
1
+ {"version":3,"file":"referenceAvailability.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/dashboards/referenceAvailability.ts"],"names":[],"mappings":"AAEA,OAAO,EAIH,KAAK,qCAAqC,EAC1C,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EAExB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACR,8BAA8B,EAC9B,gCAAgC,EACnC,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,UAAU,EASlB,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAqD3E,oFAAoF;AACpF,QAAA,MAAM,gCAAgC;0BACrB,QAAQ;wBACV,YAAY;gCACJ,oBAAoB;sBAC9B,SAAS;mBACZ,OAAO;CACwD,CAAC;AAE1E,KAAK,0BAA0B,GAAG,MAAM,OAAO,gCAAgC,CAAC;AAsEhF;;GAEG;AACH,wBAAgB,4BAA4B,CACxC,QAAQ,EAAE,qCAAqC,EAC/C,KAAK,EAAE,gCAAgC,EAAE,GAC1C,8BAA8B,EAAE,CAKlC;AAED;;;;;;GAMG;AACH,wBAAgB,qCAAqC,CACjD,QAAQ,EAAE,qCAAqC,EAC/C,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,gCAAgC,EAAE,GAC1C,8BAA8B,EAAE,CAWlC;AAED;;;;;GAKG;AACH,wBAAgB,yCAAyC,CACrD,OAAO,EAAE,uBAAuB,EAChC,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC1C,SAAS,EAAE,0BAA0B,EAAE,GACxC,8BAA8B,EAAE,CAMlC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kCAAkC,CACpD,QAAQ,EAAE,2BAA2B,EACrC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,UAAU,EACrB,KAAK,EAAE,gCAAgC,EAAE,GAC1C,OAAO,CAAC,8BAA8B,EAAE,CAAC,CA4B3C;AA8CD;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,EAAE,CAQ3E"}
@@ -20,6 +20,7 @@ const DASHBOARD_RELATIONSHIP_KEYS = {
20
20
  /** The same for the filter-context GET, which links the objects the filters use. */
21
21
  const FILTER_CONTEXT_RELATIONSHIP_KEYS = {
22
22
  displayForm: "labels",
23
+ attribute: "attributes",
23
24
  computedAttribute: "computedAttributes",
24
25
  measure: "metrics",
25
26
  fact: "facts",
@@ -88,21 +89,23 @@ export function resolveUnavailableDashboardReferences(document, dashboard, types
88
89
  return unavailable.filter((entry) => entry.type !== "filterContext" || (isIdentifierRef(entry.ref) && inUse.has(entry.ref.identifier)));
89
90
  }
90
91
  /**
91
- * Resolves which filter display forms, computed attributes, metrics and facts referenced by a filter
92
- * context are unavailable. Each inspected type must have been requested as an include (`labels`,
93
- * `computedAttributes`, `metrics`, `facts`) so the response contains both relationship linkages and
94
- * document-level `meta.restricted` for it.
92
+ * Resolves which filter display forms, attributes, computed attributes, metrics and facts referenced by
93
+ * a filter context are unavailable. Each inspected type must have been requested as an include
94
+ * (`labels`, `attributes`, `computedAttributes`, `metrics`, `facts`) so the response contains both
95
+ * relationship linkages and document-level `meta.restricted` for it.
95
96
  */
96
97
  export function resolveUnavailableFilterContextReferences(context, restricted, inspected) {
97
98
  return diffInspectedTypes({ data: context, meta: { restricted } }, FILTER_CONTEXT_RELATIONSHIP_KEYS, inspected);
98
99
  }
99
100
  /**
100
- * Filter labels, computed attributes, metrics and facts relate to their filter-context entities: the
101
- * dashboard GET side-loads the filter contexts as bare items (no `relationships`), so the existence
102
- * linkage for filter objects is reachable only through a direct filter-context GET with `include=labels`
103
- * (and `computedAttributes`, `metrics`, `facts`), hence this one batched extra request. Types other than
104
- * labels are included only when a filter uses them (metric value filters, filters on computed
105
- * attributes, metrics and facts limiting a filter's values), so other dashboards never request them.
101
+ * Filter labels, attributes, computed attributes, metrics and facts relate to their filter-context
102
+ * entities: the dashboard GET side-loads the filter contexts as bare items (no `relationships`), so the
103
+ * existence linkage for filter objects is reachable only through a direct filter-context GET with
104
+ * `include=labels` (and `attributes`, `computedAttributes`, `metrics`, `facts`), hence this one batched
105
+ * extra request. Types other than labels are included only when a filter uses them (metric value
106
+ * filters and the attributes they are computed for, filters on computed attributes, metrics, facts
107
+ * and "Count of" attributes or computed attributes limiting a filter's values), so other dashboards
108
+ * never request them.
106
109
  * It inspects the contexts of the effective dashboard, so a `filterContextRef` override is covered;
107
110
  * the synthetic export-override context has no entity behind it and is skipped.
108
111
  * It would become redundant if the backend emitted `relationships.labels` on the filter-context items
@@ -134,8 +137,9 @@ export async function fetchUnavailableFilterDisplayForms(authCall, workspaceId,
134
137
  }
135
138
  /**
136
139
  * The filter-context object types the dashboard's filters use: labels always; computed attributes of
137
- * attribute filters built on them; metrics of metric value filters; metrics and facts that limit an
138
- * attribute filter's values.
140
+ * attribute filters built on them; metrics of metric value filters and the attributes or computed
141
+ * attributes they are computed for ("For attribute"); metrics, facts and "Count of" attributes or
142
+ * computed attributes that limit an attribute filter's values.
139
143
  */
140
144
  function filterObjectTypes(dashboard) {
141
145
  const used = new Set(["displayForm"]);
@@ -143,6 +147,7 @@ function filterObjectTypes(dashboard) {
143
147
  for (const filter of contexts.flatMap((context) => context?.filters ?? [])) {
144
148
  if (isDashboardMeasureValueFilter(filter)) {
145
149
  used.add("measure");
150
+ dimensionalityObjectTypes(filter).forEach((type) => used.add(type));
146
151
  }
147
152
  if (!isDashboardAttributeFilterItem(filter)) {
148
153
  continue;
@@ -151,13 +156,23 @@ function filterObjectTypes(dashboard) {
151
156
  used.add("computedAttribute");
152
157
  }
153
158
  for (const ref of dashboardAttributeFilterItemValidateElementsBy(filter) ?? []) {
154
- if (isIdentifierRef(ref) && (ref.type === "measure" || ref.type === "fact")) {
159
+ if (isIdentifierRef(ref) &&
160
+ (ref.type === "measure" ||
161
+ ref.type === "fact" ||
162
+ ref.type === "attribute" ||
163
+ ref.type === "computedAttribute")) {
155
164
  used.add(ref.type);
156
165
  }
157
166
  }
158
167
  }
159
168
  return used;
160
169
  }
170
+ /** The attribute and computed-attribute types of the items a metric value filter is computed for. */
171
+ function dimensionalityObjectTypes(filter) {
172
+ return (filter.dashboardMeasureValueFilter.dimensionality ?? []).flatMap((ref) => isIdentifierRef(ref) && (ref.type === "attribute" || ref.type === "computedAttribute")
173
+ ? [ref.type]
174
+ : []);
175
+ }
161
176
  /**
162
177
  * Identifiers of the persisted filter contexts the dashboard actually uses (root and tabs; a
163
178
  * `filterContextRef` override replaces them all). Only a ref typed `filterContext` names an entity
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/genAI/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACR,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,aAAa,EACb,0BAA0B,EAC1B,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,6BAA6B,EAChC,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,yDAAyD,CAAC;AAE9F,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAS3E,qBAAa,YAAa,YAAW,aAAa;IAE1C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAHnC,YACqB,QAAQ,EAAE,2BAA2B,EACrC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,cAAc,EAC/C;IAEJ,oBAAoB,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,kBAAkB,CAE1E;IAED,sBAAsB,IAAI,oBAAoB,CAE7C;IAEK,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzC;IAED,qBAAqB,IAAI,0BAA0B,CAElD;IAED,cAAc,IAAI,mBAAmB,CAEpC;IAED,mBAAmB,IAAI,wBAAwB,CAE9C;IAED,kBAAkB,IAAI,uBAAuB,CAE5C;IAEK,kBAAkB,CACpB,OAAO,EAAE,wBAAwB,EACjC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAkC5B;IAEK,uBAAuB,CACzB,OAAO,EAAE,6BAA6B,EACtC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAyB5B;CACJ"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/workspace/genAI/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACR,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,aAAa,EACb,0BAA0B,EAC1B,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,6BAA6B,EAChC,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,yDAAyD,CAAC;AAE9F,OAAO,EAAE,KAAK,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAS3E,qBAAa,YAAa,YAAW,aAAa;IAE1C,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAHnC,YACqB,QAAQ,EAAE,2BAA2B,EACrC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,cAAc,EAC/C;IAEJ,oBAAoB,CAAC,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,kBAAkB,CAE1E;IAED,sBAAsB,IAAI,oBAAoB,CAE7C;IAEK,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzC;IAED,qBAAqB,IAAI,0BAA0B,CAElD;IAED,cAAc,IAAI,mBAAmB,CAEpC;IAED,mBAAmB,IAAI,wBAAwB,CAE9C;IAED,kBAAkB,IAAI,uBAAuB,CAE5C;IAEK,kBAAkB,CACpB,OAAO,EAAE,wBAAwB,EACjC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAkC5B;IAEK,uBAAuB,CACzB,OAAO,EAAE,6BAA6B,EACtC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACnC,OAAO,CAAC,iBAAiB,CAAC,CA6B5B;CACJ"}
@@ -69,11 +69,13 @@ export class GenAIService {
69
69
  }
70
70
  async summarizeVisualizations(request, options) {
71
71
  const aiSummarizeVisualizationsRequest = {
72
- visualizations: request.visualizations,
73
- // Cast bridges the AFM filter definitions to the generated union type of the AI API.
74
- filterContext: request.filters
75
- .map((filter) => convertFilter(filter))
76
- .filter(Boolean),
72
+ visualizations: request.visualizations.map((visualization) => typeof visualization === "string"
73
+ ? visualization
74
+ : {
75
+ visualizationId: visualization.visualizationId,
76
+ filters: convertSummaryFilters(visualization.filters),
77
+ }),
78
+ filterContext: convertSummaryFilters(request.filters),
77
79
  };
78
80
  if (request.formatHint !== undefined) {
79
81
  aiSummarizeVisualizationsRequest.formatHint = request.formatHint;
@@ -85,6 +87,12 @@ export class GenAIService {
85
87
  return convertSummaryResponse(response.data);
86
88
  }
87
89
  }
90
+ // Cast bridges the AFM filter definitions to the generated union type of the AI API.
91
+ function convertSummaryFilters(filters) {
92
+ return filters
93
+ .map((filter) => convertFilter(filter))
94
+ .filter(Boolean);
95
+ }
88
96
  function convertSummaryResponse(data) {
89
97
  return {
90
98
  summary: data.summary,
@@ -1 +1 @@
1
- {"version":3,"file":"AutomationConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/fromBackend/AutomationConverter.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,eAAe,EAGpB,KAAK,yBAAyB,EAO9B,KAAK,uCAAuC,EAC5C,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAE7B,KAAK,6BAA6B,EAQlC,KAAK,sCAAsC,EAK3C,KAAK,gBAAgB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEH,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EAI9B,KAAK,OAAO,EA0Bf,MAAM,qBAAqB,CAAC;AA6I7B,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,6BAA6B,GAAG,sCAAsC,EAClF,QAAQ,EAAE,4BAA4B,EAAE,EACxC,UAAU,CAAC,EAAE,gBAAgB,EAAE,GAChC,yBAAyB,CA6H3B;AAED,eAAO,MAAM,kCAAkC,mBAC3B,wBAAwB,KACzC,yBAAyB,EAI3B,CAAC;AAcF,eAAO,MAAM,YAAY,UACd,yBAAyB,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,UAC/D,uCAAuC,KAChD,gBAAgB,GAAG,SAoGrB,CAAC;AA0CF;;;;;;;GAOG;AACH,wBAAgB,yCAAyC,CACrD,MAAM,EAAE,OAAO,EACf,uBAAuB,EAAE,MAAM,GAChC,iBAAiB,GAAG,SAAS,CAgG/B"}
1
+ {"version":3,"file":"AutomationConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/fromBackend/AutomationConverter.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,eAAe,EAGpB,KAAK,yBAAyB,EAO9B,KAAK,uCAAuC,EAC5C,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAE7B,KAAK,6BAA6B,EAQlC,KAAK,sCAAsC,EAK3C,KAAK,gBAAgB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEH,KAAK,iBAAiB,EAEtB,KAAK,gBAAgB,EACrB,KAAK,yBAAyB,EAI9B,KAAK,OAAO,EA2Bf,MAAM,qBAAqB,CAAC;AA6I7B,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,6BAA6B,GAAG,sCAAsC,EAClF,QAAQ,EAAE,4BAA4B,EAAE,EACxC,UAAU,CAAC,EAAE,gBAAgB,EAAE,GAChC,yBAAyB,CA6H3B;AAED,eAAO,MAAM,kCAAkC,mBAC3B,wBAAwB,KACzC,yBAAyB,EAI3B,CAAC;AAcF,eAAO,MAAM,YAAY,UACd,yBAAyB,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,UAC/D,uCAAuC,KAChD,gBAAgB,GAAG,SAoGrB,CAAC;AA0CF;;;;;;;GAOG;AACH,wBAAgB,yCAAyC,CACrD,MAAM,EAAE,OAAO,EACf,uBAAuB,EAAE,MAAM,GAChC,iBAAiB,GAAG,SAAS,CAmG/B"}
@@ -1,6 +1,6 @@
1
1
  // (C) 2024-2026 GoodData Corporation
2
2
  import { compact } from "lodash-es";
3
- import { filterAttributeElements, filterLocalIdentifier, filterObjRef, idRef, isAbsoluteDateFilter, isAllTimeDateFilter, isArbitraryAttributeFilter, isAttributeFilterWithSelection, isAutomationUserRecipient, isExportDefinitionVisualizationObjectRequestPayload, isFilter, isFilterContextItem, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isObjRef, isRelativeBoundedDateFilter, isRelativeDateFilter, measureValueFilterConditions, measureValueFilterDimensionality, measureValueFilterMeasure, newAbsoluteDashboardDateFilter, newAllTimeDashboardDateFilter, newRelativeDashboardDateFilter, } from "@gooddata/sdk-model";
3
+ import { filterAttributeElements, filterLocalIdentifier, filterObjRef, idRef, isAbsoluteDateFilter, isAllTimeDateFilter, isArbitraryAttributeFilter, isAttributeFilterWithSelection, isAutomationUserRecipient, isDateFilterGranularity, isExportDefinitionVisualizationObjectRequestPayload, isFilter, isFilterContextItem, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isObjRef, isRelativeBoundedDateFilter, isRelativeDateFilter, measureValueFilterConditions, measureValueFilterDimensionality, measureValueFilterMeasure, newAbsoluteDashboardDateFilter, newAllTimeDashboardDateFilter, newRelativeDashboardDateFilter, } from "@gooddata/sdk-model";
4
4
  import { fixNumber } from "../../utils/fixNumber.js";
5
5
  import { convertFilter } from "./afm/FilterConverter.js";
6
6
  import { convertMeasure } from "./afm/MeasureConverter.js";
@@ -338,7 +338,9 @@ export function convertExecutionFilterToFilterContextItem(filter, fallbackLocalI
338
338
  };
339
339
  }
340
340
  if (isAbsoluteDateFilter(filter)) {
341
- return newAbsoluteDashboardDateFilter(filter.absoluteDateFilter.from, filter.absoluteDateFilter.to, filter.absoluteDateFilter.dataSet, filter.absoluteDateFilter.localIdentifier, filter.absoluteDateFilter.emptyValueHandling);
341
+ return newAbsoluteDashboardDateFilter(filter.absoluteDateFilter.from, filter.absoluteDateFilter.to, filter.absoluteDateFilter.dataSet, filter.absoluteDateFilter.localIdentifier, filter.absoluteDateFilter.emptyValueHandling, isDateFilterGranularity(filter.absoluteDateFilter.granularity)
342
+ ? filter.absoluteDateFilter.granularity
343
+ : "GDC.time.date");
342
344
  }
343
345
  if (isAllTimeDateFilter(filter)) {
344
346
  return newAllTimeDashboardDateFilter(filter.relativeDateFilter.dataSet, filter.relativeDateFilter.localIdentifier, filter.relativeDateFilter.emptyValueHandling);
@@ -1 +1 @@
1
- {"version":3,"file":"FilterConverter.d.ts","sourceRoot":"","sources":["../../../../src/convertors/fromBackend/afm/FilterConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EAMH,KAAK,gBAAgB,EAWxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAGH,KAAK,OAAO,EAQf,MAAM,qBAAqB,CAAC;AAqH7B,eAAO,MAAM,aAAa,WAAY,gBAAgB,KAAG,OA2NxD,CAAC"}
1
+ {"version":3,"file":"FilterConverter.d.ts","sourceRoot":"","sources":["../../../../src/convertors/fromBackend/afm/FilterConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EAOH,KAAK,gBAAgB,EAWxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAGH,KAAK,OAAO,EAQf,MAAM,qBAAqB,CAAC;AA8H7B,eAAO,MAAM,aAAa,WAAY,gBAAgB,KAAG,OAyQxD,CAAC"}
@@ -2,6 +2,7 @@
2
2
  import { isAfmObjectIdentifier, isAfmObjectLocalIdentifier, } from "@gooddata/api-client-tiger";
3
3
  import { NotSupported } from "@gooddata/sdk-backend-spi";
4
4
  import { newArbitraryAttributeFilter, } from "@gooddata/sdk-model";
5
+ import { fromPeriodLiteral, isWireAbsoluteGranularity, toPeriodLiteral, } from "../../shared/absoluteGranularityLiterals.js";
5
6
  import { toSdkGranularity } from "../dateGranularityConversions.js";
6
7
  import { toLocalRef, toObjRef } from "../ObjRefConverter.js";
7
8
  const isPositiveAttributeFilter = (filter) => {
@@ -13,6 +14,9 @@ const isNegativeAttributeFilter = (filter) => {
13
14
  const isAbsoluteDateFilter = (filter) => {
14
15
  return filter.absoluteDateFilter !== undefined;
15
16
  };
17
+ const isAbsoluteGranularityDateFilter = (filter) => {
18
+ return filter.absoluteGranularityDateFilter !== undefined;
19
+ };
16
20
  const isAllTimeDateFilter = (filter) => {
17
21
  return filter.allTimeDateFilter !== undefined;
18
22
  };
@@ -147,6 +151,44 @@ export const convertFilter = (filter) => {
147
151
  },
148
152
  };
149
153
  }
154
+ else if (isAbsoluteGranularityDateFilter(filter)) {
155
+ const { dataset, granularity, from, to, localIdentifier } = filter.absoluteGranularityDateFilter;
156
+ const sdkGranularity = toSdkGranularity(granularity);
157
+ if (from === undefined || from === null || to === undefined || to === null) {
158
+ throw new NotSupported("Open-ended absolute date filters are not supported.");
159
+ }
160
+ if (!isWireAbsoluteGranularity(sdkGranularity)) {
161
+ throw new NotSupported(`Absolute date filters at the ${granularity} granularity are not supported.`);
162
+ }
163
+ const emptyValueHandling = toSdkEmptyValues(filter.absoluteGranularityDateFilter.emptyValueHandling);
164
+ // The range covers whole periods, so it ends on the last day of the period 'to' names,
165
+ // not on its first day.
166
+ let range;
167
+ try {
168
+ range = {
169
+ from: fromPeriodLiteral(sdkGranularity, from).first,
170
+ to: fromPeriodLiteral(sdkGranularity, to).last,
171
+ };
172
+ // Parsing accepts a literal that is not zero-padded or has a short year, so the literal must
173
+ // also come back unchanged when its period is converted to a literal again.
174
+ if (toPeriodLiteral(sdkGranularity, range.from) !== from ||
175
+ toPeriodLiteral(sdkGranularity, range.to) !== to) {
176
+ throw new Error(`Not ${granularity} literals: ${from} - ${to}`);
177
+ }
178
+ }
179
+ catch {
180
+ throw new NotSupported(`The absolute date filter range ${from} - ${to} is not in the format of the ${granularity} granularity.`);
181
+ }
182
+ return {
183
+ absoluteDateFilter: {
184
+ dataSet: toObjRef(dataset),
185
+ localIdentifier,
186
+ ...range,
187
+ ...(sdkGranularity === "GDC.time.date" ? {} : { granularity: sdkGranularity }),
188
+ ...(emptyValueHandling === undefined ? {} : { emptyValueHandling }),
189
+ },
190
+ };
191
+ }
150
192
  else if (isAllTimeDateFilter(filter)) {
151
193
  const emptyValueHandling = toSdkEmptyValues(filter.allTimeDateFilter.emptyValueHandling);
152
194
  return {
@@ -0,0 +1,38 @@
1
+ import { type DateAttributeGranularity } from "@gooddata/sdk-model";
2
+ declare const WIRE_ABSOLUTE_GRANULARITIES: readonly ["GDC.time.date", "GDC.time.month", "GDC.time.quarter", "GDC.time.year"];
3
+ /**
4
+ * Granularities an absolute date filter can express on the wire as a period literal.
5
+ */
6
+ export type WireAbsoluteGranularity = (typeof WIRE_ABSOLUTE_GRANULARITIES)[number];
7
+ /**
8
+ * Granularities whose ranges can be sent as period literals rather than as days.
9
+ */
10
+ export type PeriodLiteralGranularity = Exclude<WireAbsoluteGranularity, "GDC.time.date">;
11
+ export declare function isWireAbsoluteGranularity(granularity: DateAttributeGranularity | undefined): granularity is WireAbsoluteGranularity;
12
+ /**
13
+ * Tells whether an absolute date filter at the granularity can be sent as period literals rather than
14
+ * as its days.
15
+ */
16
+ export declare function hasPeriodLiteral(granularity: DateAttributeGranularity | undefined): granularity is PeriodLiteralGranularity;
17
+ /**
18
+ * Converts a day into the literal of the period of the given granularity that contains it.
19
+ */
20
+ export declare function toPeriodLiteral(granularity: WireAbsoluteGranularity, day: string): string;
21
+ /**
22
+ * Converts a period literal into the first and the last day of that period.
23
+ */
24
+ export declare function fromPeriodLiteral(granularity: WireAbsoluteGranularity, literal: string): {
25
+ first: string;
26
+ last: string;
27
+ };
28
+ /**
29
+ * Converts a range of days into the literals of its first and last period of the given granularity.
30
+ *
31
+ * @returns undefined when a day is not in the YYYY-MM-DD format or the range is not whole periods
32
+ */
33
+ export declare function toWholePeriodLiterals(granularity: PeriodLiteralGranularity, from: string, to: string): {
34
+ from: string;
35
+ to: string;
36
+ } | undefined;
37
+ export {};
38
+ //# sourceMappingURL=absoluteGranularityLiterals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"absoluteGranularityLiterals.d.ts","sourceRoot":"","sources":["../../../src/convertors/shared/absoluteGranularityLiterals.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAMpE,QAAA,MAAM,2BAA2B,mFAKuB,CAAC;AAEzD;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,EAAE,eAAe,CAAC,CAAC;AAEzF,wBAAgB,yBAAyB,CACrC,WAAW,EAAE,wBAAwB,GAAG,SAAS,GAClD,WAAW,IAAI,uBAAuB,CAExC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC5B,WAAW,EAAE,wBAAwB,GAAG,SAAS,GAClD,WAAW,IAAI,wBAAwB,CAEzC;AAkBD;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,uBAAuB,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,WAAW,EAAE,uBAAuB,EACpC,OAAO,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAuBjC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACjC,WAAW,EAAE,wBAAwB,EACrC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAe1C"}
@@ -0,0 +1,82 @@
1
+ // (C) 2026 GoodData Corporation
2
+ import { endOfMonth, endOfQuarter, endOfYear, isValid } from "date-fns";
3
+ import { parseDateValue, serializeDateValue } from "../fromBackend/dateFormatting/dateValueParser.js";
4
+ // TODO: a week has no literal yet, because the backend numbers weeks by ISO-8601 and shifts them by the
5
+ // week start; support will be added later in a different PR.
6
+ const WIRE_ABSOLUTE_GRANULARITIES = [
7
+ "GDC.time.date",
8
+ "GDC.time.month",
9
+ "GDC.time.quarter",
10
+ "GDC.time.year",
11
+ ];
12
+ export function isWireAbsoluteGranularity(granularity) {
13
+ return WIRE_ABSOLUTE_GRANULARITIES.some((wireGranularity) => wireGranularity === granularity);
14
+ }
15
+ /**
16
+ * Tells whether an absolute date filter at the granularity can be sent as period literals rather than
17
+ * as its days.
18
+ */
19
+ export function hasPeriodLiteral(granularity) {
20
+ return isWireAbsoluteGranularity(granularity) && granularity !== "GDC.time.date";
21
+ }
22
+ function isDay(value) {
23
+ return /^\d{4}-\d{2}-\d{2}$/.test(value) && isValid(parseDateValue(value, "GDC.time.date"));
24
+ }
25
+ function parseDay(day) {
26
+ if (!isDay(day)) {
27
+ throw new Error(`Not a day in the YYYY-MM-DD format: ${day}`);
28
+ }
29
+ return parseDateValue(day, "GDC.time.date");
30
+ }
31
+ function serializeDay(date) {
32
+ return serializeDateValue(date, "GDC.time.date");
33
+ }
34
+ /**
35
+ * Converts a day into the literal of the period of the given granularity that contains it.
36
+ */
37
+ export function toPeriodLiteral(granularity, day) {
38
+ return serializeDateValue(parseDay(day), granularity);
39
+ }
40
+ /**
41
+ * Converts a period literal into the first and the last day of that period.
42
+ */
43
+ export function fromPeriodLiteral(granularity, literal) {
44
+ const first = parseDateValue(literal, granularity);
45
+ if (!isValid(first)) {
46
+ throw new Error(`Not a ${granularity} literal: ${literal}`);
47
+ }
48
+ let last = first;
49
+ switch (granularity) {
50
+ case "GDC.time.month":
51
+ last = endOfMonth(first);
52
+ break;
53
+ case "GDC.time.quarter":
54
+ last = endOfQuarter(first);
55
+ break;
56
+ case "GDC.time.year":
57
+ last = endOfYear(first);
58
+ break;
59
+ }
60
+ return {
61
+ first: serializeDay(first),
62
+ last: serializeDay(last),
63
+ };
64
+ }
65
+ /**
66
+ * Converts a range of days into the literals of its first and last period of the given granularity.
67
+ *
68
+ * @returns undefined when a day is not in the YYYY-MM-DD format or the range is not whole periods
69
+ */
70
+ export function toWholePeriodLiterals(granularity, from, to) {
71
+ if (!isDay(from) || !isDay(to)) {
72
+ return undefined;
73
+ }
74
+ const literals = {
75
+ from: toPeriodLiteral(granularity, from),
76
+ to: toPeriodLiteral(granularity, to),
77
+ };
78
+ const isWhole = from <= to &&
79
+ fromPeriodLiteral(granularity, literals.from).first === from &&
80
+ fromPeriodLiteral(granularity, literals.to).last === to;
81
+ return isWhole ? literals : undefined;
82
+ }
@@ -1,5 +1,14 @@
1
1
  import { type ITigerFilter, type ITigerFilterContextItem } from "@gooddata/api-client-tiger";
2
2
  import { type FilterContextItem, type IFilter } from "@gooddata/sdk-model";
3
+ /**
4
+ * Options of the conversion of SDK filters to Tiger stored filters.
5
+ */
6
+ export interface IStoredFilterConversionOptions {
7
+ /**
8
+ * Removes the granularity from absolute date filters. It is kept by default.
9
+ */
10
+ dropAbsoluteDateGranularity?: boolean;
11
+ }
3
12
  /**
4
13
  * Converts SDK filter to Tiger stored filter format.
5
14
  *
@@ -8,10 +17,11 @@ import { type FilterContextItem, type IFilter } from "@gooddata/sdk-model";
8
17
  * For AFM/execution filters, use the AFM filter converter instead.
9
18
  *
10
19
  * @param filter - SDK filter to convert
20
+ * @param options - conversion options
11
21
  * @returns Tiger stored filter with sanitized IDs and converted formats
12
22
  * @public
13
23
  */
14
- export declare function convertSdkFilterToTigerStored(filter: IFilter): ITigerFilter;
24
+ export declare function convertSdkFilterToTigerStored(filter: IFilter, options?: IStoredFilterConversionOptions): ITigerFilter;
15
25
  /**
16
26
  * Converts SDK FilterContextItem to Tiger FilterContextItem.
17
27
  *
@@ -31,7 +41,7 @@ export declare function convertSdkFilterContextItemToTiger(item: FilterContextIt
31
41
  export declare function convertTigerStoredToSdkFilter(filter: ITigerFilter): IFilter;
32
42
  type SdkFiltersToTigerInput = IFilter[] | FilterContextItem[] | undefined;
33
43
  type SdkFiltersToTigerOutput<T extends SdkFiltersToTigerInput> = T extends IFilter[] ? ITigerFilter[] : T extends FilterContextItem[] ? ITigerFilterContextItem[] : undefined;
34
- export declare function convertSdkFiltersToTiger<T extends SdkFiltersToTigerInput>(filters: T): SdkFiltersToTigerOutput<T>;
44
+ export declare function convertSdkFiltersToTiger<T extends SdkFiltersToTigerInput>(filters: T, options?: IStoredFilterConversionOptions): SdkFiltersToTigerOutput<T>;
35
45
  type TigerToSdkFiltersInput = ITigerFilter[] | ITigerFilterContextItem[] | undefined;
36
46
  type TigerToSdkFiltersOutput<T extends TigerToSdkFiltersInput> = T extends ITigerFilter[] ? IFilter[] : T extends ITigerFilterContextItem[] ? FilterContextItem[] : undefined;
37
47
  export declare function convertTigerToSdkFilters<T extends TigerToSdkFiltersInput>(filters: T): TigerToSdkFiltersOutput<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"storedFilterConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/shared/storedFilterConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAG/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACH,KAAK,iBAAiB,EAEtB,KAAK,OAAO,EAKf,MAAM,qBAAqB,CAAC;AAc7B;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,CAG3E;AAED;;;;;;GAMG;AACH,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,iBAAiB,GAAG,uBAAuB,CAgBnG;AA4CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAG3E;AAmBD,KAAK,sBAAsB,GAAG,OAAO,EAAE,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC;AAC1E,KAAK,uBAAuB,CAAC,CAAC,SAAS,sBAAsB,IAAI,CAAC,SAAS,OAAO,EAAE,GAC9E,YAAY,EAAE,GACd,CAAC,SAAS,iBAAiB,EAAE,GAC3B,uBAAuB,EAAE,GACzB,SAAS,CAAC;AAElB,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,sBAAsB,EACrE,OAAO,EAAE,CAAC,GACX,uBAAuB,CAAC,CAAC,CAAC,CAkB5B;AAID,KAAK,sBAAsB,GAAG,YAAY,EAAE,GAAG,uBAAuB,EAAE,GAAG,SAAS,CAAC;AACrF,KAAK,uBAAuB,CAAC,CAAC,SAAS,sBAAsB,IAAI,CAAC,SAAS,YAAY,EAAE,GACnF,OAAO,EAAE,GACT,CAAC,SAAS,uBAAuB,EAAE,GACjC,iBAAiB,EAAE,GACnB,SAAS,CAAC;AAElB,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,sBAAsB,EACrE,OAAO,EAAE,CAAC,GACX,uBAAuB,CAAC,CAAC,CAAC,CAiC5B"}
1
+ {"version":3,"file":"storedFilterConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/shared/storedFilterConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAG/B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACH,KAAK,iBAAiB,EAEtB,KAAK,OAAO,EAMf,MAAM,qBAAqB,CAAC;AAW7B;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C;;OAEG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACzC;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CACzC,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,8BAAmC,GAC7C,YAAY,CAId;AAaD;;;;;;GAMG;AACH,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,iBAAiB,GAAG,uBAAuB,CAgBnG;AA4CD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAG3E;AAmBD,KAAK,sBAAsB,GAAG,OAAO,EAAE,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC;AAC1E,KAAK,uBAAuB,CAAC,CAAC,SAAS,sBAAsB,IAAI,CAAC,SAAS,OAAO,EAAE,GAC9E,YAAY,EAAE,GACd,CAAC,SAAS,iBAAiB,EAAE,GAC3B,uBAAuB,EAAE,GACzB,SAAS,CAAC;AAElB,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,sBAAsB,EACrE,OAAO,EAAE,CAAC,EACV,OAAO,GAAE,8BAAmC,GAC7C,uBAAuB,CAAC,CAAC,CAAC,CAoB5B;AAID,KAAK,sBAAsB,GAAG,YAAY,EAAE,GAAG,uBAAuB,EAAE,GAAG,SAAS,CAAC;AACrF,KAAK,uBAAuB,CAAC,CAAC,SAAS,sBAAsB,IAAI,CAAC,SAAS,YAAY,EAAE,GACnF,OAAO,EAAE,GACT,CAAC,SAAS,uBAAuB,EAAE,GACjC,iBAAiB,EAAE,GACnB,SAAS,CAAC;AAElB,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,sBAAsB,EACrE,OAAO,EAAE,CAAC,GACX,uBAAuB,CAAC,CAAC,CAAC,CAiC5B"}
@@ -1,6 +1,6 @@
1
1
  // (C) 2026 GoodData Corporation
2
2
  import { isTigerFilterContextItems, isTigerFilters, } from "@gooddata/api-client-tiger";
3
- import { isComparisonCondition, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, } from "@gooddata/sdk-model";
3
+ import { isAbsoluteDateFilter, isComparisonCondition, isDashboardMatchAttributeFilter, isDashboardMeasureValueFilter, } from "@gooddata/sdk-model";
4
4
  import { cloneWithSanitizedIdsTyped as cloneWithSanitizedIdsTypedFromBackend } from "../fromBackend/IdSanitization.js";
5
5
  import { cloneWithSanitizedIdsTyped as cloneWithSanitizedIdsTypedToBackend } from "../toBackend/IdSanitization.js";
6
6
  import { convertMeasureValueFilterSdkToTiger, convertMeasureValueFilterTigerToSdk, } from "./measureValueFilterConverter.js";
@@ -15,13 +15,24 @@ import { isFilterContextItems, isFilters } from "./sdkFilterTypeGuards.js";
15
15
  * For AFM/execution filters, use the AFM filter converter instead.
16
16
  *
17
17
  * @param filter - SDK filter to convert
18
+ * @param options - conversion options
18
19
  * @returns Tiger stored filter with sanitized IDs and converted formats
19
20
  * @public
20
21
  */
21
- export function convertSdkFilterToTigerStored(filter) {
22
- const sanitized = cloneWithSanitizedIdsTypedToBackend(filter);
22
+ export function convertSdkFilterToTigerStored(filter, options = {}) {
23
+ const stored = options.dropAbsoluteDateGranularity ? dropAbsoluteDateFilterGranularity(filter) : filter;
24
+ const sanitized = cloneWithSanitizedIdsTypedToBackend(stored);
23
25
  return convertMeasureValueFilterSdkToTiger(sanitized);
24
26
  }
27
+ // Insights store absolute date filters without the granularity. Dropping it cannot change what the
28
+ // filter selects, because from/to already are the first and the last day of the selected periods.
29
+ function dropAbsoluteDateFilterGranularity(filter) {
30
+ if (!isAbsoluteDateFilter(filter) || filter.absoluteDateFilter.granularity === undefined) {
31
+ return filter;
32
+ }
33
+ const { granularity: _granularity, ...absoluteDateFilter } = filter.absoluteDateFilter;
34
+ return { absoluteDateFilter };
35
+ }
25
36
  /**
26
37
  * Converts SDK FilterContextItem to Tiger FilterContextItem.
27
38
  *
@@ -106,7 +117,7 @@ function convertDashboardFilterToSdk(item) {
106
117
  }
107
118
  return cloneWithSanitizedIdsTypedFromBackend(item);
108
119
  }
109
- export function convertSdkFiltersToTiger(filters) {
120
+ export function convertSdkFiltersToTiger(filters, options = {}) {
110
121
  if (!filters) {
111
122
  return undefined;
112
123
  }
@@ -117,7 +128,7 @@ export function convertSdkFiltersToTiger(filters) {
117
128
  return filters.map(convertSdkFilterContextItemToTiger);
118
129
  }
119
130
  if (isFilters(filters)) {
120
- return filters.map(convertSdkFilterToTigerStored);
131
+ return filters.map((filter) => convertSdkFilterToTigerStored(filter, options));
121
132
  }
122
133
  throw new Error("Unsupported filters type");
123
134
  }
@@ -1 +1 @@
1
- {"version":3,"file":"InsightConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/toBackend/InsightConverter.ts"],"names":[],"mappings":"AAIA,OAAO,EAOH,KAAK,0BAA0B,EAClC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAIH,KAAK,kBAAkB,EAO1B,MAAM,qBAAqB,CAAC;AAyB7B;;;;;GAKG;AACH,eAAO,MAAM,cAAc,YACd,kBAAkB,KAC5B,0BAA0B,CAAC,oBAwD7B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC,YAAa,kBAAkB,KAAG,MACxD,CAAC"}
1
+ {"version":3,"file":"InsightConverter.d.ts","sourceRoot":"","sources":["../../../src/convertors/toBackend/InsightConverter.ts"],"names":[],"mappings":"AAIA,OAAO,EAOH,KAAK,0BAA0B,EAClC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAIH,KAAK,kBAAkB,EAO1B,MAAM,qBAAqB,CAAC;AAgC7B;;;;;GAKG;AACH,eAAO,MAAM,cAAc,YACd,kBAAkB,KAC5B,0BAA0B,CAAC,oBA2D7B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC,YAAa,kBAAkB,KAAG,MACxD,CAAC"}
@@ -1,8 +1,11 @@
1
1
  // (C) 2019-2026 GoodData Corporation
2
2
  import { omit } from "lodash-es";
3
3
  import { insightLayers, insightParameters, } from "@gooddata/sdk-model";
4
- import { convertSdkFiltersToTiger } from "../shared/storedFilterConverter.js";
4
+ import { convertSdkFiltersToTiger, } from "../shared/storedFilterConverter.js";
5
5
  import { cloneWithSanitizedIdsTyped } from "./IdSanitization.js";
6
+ // TODO: Analytical Designer does not support the granularity of an absolute date filter yet,
7
+ // so the insight and layer filters store only its days; measure filters in buckets keep it.
8
+ const insightFilterConversionOptions = { dropAbsoluteDateGranularity: true };
6
9
  function removeIdentifiers(insight) {
7
10
  const insightData = omit(insight.insight, ["ref", "uri", "identifier"]);
8
11
  return {
@@ -32,7 +35,7 @@ export const convertInsight = (insight) => {
32
35
  ? {
33
36
  layers: layers.map((layer) => {
34
37
  const tigerLayer = cloneWithSanitizedIdsTyped(layer);
35
- const convertedFilters = convertSdkFiltersToTiger(layer.filters);
38
+ const convertedFilters = convertSdkFiltersToTiger(layer.filters, insightFilterConversionOptions);
36
39
  return {
37
40
  ...tigerLayer,
38
41
  ...(convertedFilters ? { filters: convertedFilters } : {}),
@@ -48,7 +51,7 @@ export const convertInsight = (insight) => {
48
51
  : {};
49
52
  return {
50
53
  buckets: cloneWithSanitizedIdsTyped(sanitizedInsight.insight.buckets),
51
- filters: convertSdkFiltersToTiger(sanitizedInsight.insight.filters),
54
+ filters: convertSdkFiltersToTiger(sanitizedInsight.insight.filters, insightFilterConversionOptions),
52
55
  ...(sanitizedInsight.insight.attributeFilterConfigs
53
56
  ? {
54
57
  attributeFilterConfigs: cloneWithSanitizedIdsTyped(sanitizedInsight.insight.attributeFilterConfigs),
@@ -1 +1 @@
1
- {"version":3,"file":"FilterConverter.d.ts","sourceRoot":"","sources":["../../../../src/convertors/toBackend/afm/FilterConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EAMH,KAAK,gBAAgB,EASxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAMH,KAAK,OAAO,EA2Bf,MAAM,qBAAqB,CAAC;AA6B7B;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,OAAO,GAAG,SAAS,CAAC;CACtC;AAED,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,OAAO,EACf,aAAa,EAAE,OAAO,GAAG,SAAS,GACnC,wBAAwB,CAE1B;AAyWD,wBAAgB,aAAa,CACzB,OAAO,EAAE,OAAO,GAAG,wBAAwB,EAC3C,yBAAyB,GAAE,OAAe,GAC3C,gBAAgB,GAAG,IAAI,CAyBzB"}
1
+ {"version":3,"file":"FilterConverter.d.ts","sourceRoot":"","sources":["../../../../src/convertors/toBackend/afm/FilterConverter.ts"],"names":[],"mappings":"AAEA,OAAO,EAQH,KAAK,gBAAgB,EASxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAMH,KAAK,OAAO,EA2Bf,MAAM,qBAAqB,CAAC;AA+B7B;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,OAAO,GAAG,SAAS,CAAC;CACtC;AAED,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,OAAO,EACf,aAAa,EAAE,OAAO,GAAG,SAAS,GACnC,wBAAwB,CAE1B;AA8XD,wBAAgB,aAAa,CACzB,OAAO,EAAE,OAAO,GAAG,wBAAwB,EAC3C,yBAAyB,GAAE,OAAe,GAC3C,gBAAgB,GAAG,IAAI,CAyBzB"}
@@ -1,6 +1,7 @@
1
1
  // (C) 2007-2026 GoodData Corporation
2
2
  import { filterIsEmpty, isAbsoluteDateFilter, isAllTimeDateFilter, isArbitraryAttributeFilter, isAttributeElementsByValue, isAttributeFilter, isComparisonCondition, isFilter, isLowerBound, isMatchAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isObjRef, isPositiveAttributeFilter, isRangeCondition, isRankingFilter, isRelativeBoundedDateFilterBody, isRelativeDateFilter, isUpperBound, } from "@gooddata/sdk-model";
3
3
  import { toTigerGranularity } from "../../fromBackend/dateGranularityConversions.js";
4
+ import { hasPeriodLiteral, toWholePeriodLiterals } from "../../shared/absoluteGranularityLiterals.js";
4
5
  import { toAfmIdentifier, toDateDataSetQualifier, toLabelQualifier, toLocalIdentifier, } from "../ObjRefConverter.js";
5
6
  function toTigerEmptyValueHandling(emptyValues) {
6
7
  if (emptyValues === "include") {
@@ -132,11 +133,31 @@ function convertAbsoluteDateFilter(filter, applyOnResultProp) {
132
133
  const datasetRef = absoluteDateFilter.dataSet;
133
134
  const localIdentifier = absoluteDateFilter.localIdentifier;
134
135
  const emptyValueHandling = toTigerEmptyValueHandling(absoluteDateFilter.emptyValueHandling);
136
+ const from = String(absoluteDateFilter.from);
137
+ const to = String(absoluteDateFilter.to);
138
+ const granularity = absoluteDateFilter.granularity;
139
+ // A range of whole periods goes as period literals; any other range, which an older or an as-code
140
+ // dashboard can store, goes as its days, as stored.
141
+ if (hasPeriodLiteral(granularity)) {
142
+ const literals = toWholePeriodLiterals(granularity, from, to);
143
+ if (literals) {
144
+ return {
145
+ absoluteGranularityDateFilter: {
146
+ dataset: toDateDataSetQualifier(datasetRef),
147
+ granularity: toTigerGranularity(granularity),
148
+ ...literals,
149
+ localIdentifier,
150
+ ...(emptyValueHandling === undefined ? {} : { emptyValueHandling }),
151
+ ...applyOnResultProp,
152
+ },
153
+ };
154
+ }
155
+ }
135
156
  return {
136
157
  absoluteDateFilter: {
137
158
  dataset: toDateDataSetQualifier(datasetRef),
138
- from: String(absoluteDateFilter.from),
139
- to: String(absoluteDateFilter.to),
159
+ from,
160
+ to,
140
161
  localIdentifier,
141
162
  ...(emptyValueHandling === undefined ? {} : { emptyValueHandling }),
142
163
  ...applyOnResultProp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-backend-tiger",
3
- "version": "11.62.0-alpha.2",
3
+ "version": "11.62.0-alpha.3",
4
4
  "description": "GoodData Backend SPI implementation for GoodData Cloud and GoodData.CN",
5
5
  "license": "MIT",
6
6
  "author": "GoodData",
@@ -34,12 +34,12 @@
34
34
  "ts-invariant": "0.10.3",
35
35
  "tslib": "2.8.1",
36
36
  "uuid": "11.1.1",
37
- "@gooddata/api-client-tiger": "11.62.0-alpha.2",
38
- "@gooddata/sdk-backend-base": "11.62.0-alpha.2",
39
- "@gooddata/sdk-backend-spi": "11.62.0-alpha.2",
40
- "@gooddata/sdk-model": "11.62.0-alpha.2",
41
- "@gooddata/sdk-code-convertors": "11.62.0-alpha.2",
42
- "@gooddata/util": "11.62.0-alpha.2"
37
+ "@gooddata/api-client-tiger": "11.62.0-alpha.3",
38
+ "@gooddata/sdk-backend-base": "11.62.0-alpha.3",
39
+ "@gooddata/sdk-backend-spi": "11.62.0-alpha.3",
40
+ "@gooddata/sdk-code-convertors": "11.62.0-alpha.3",
41
+ "@gooddata/sdk-model": "11.62.0-alpha.3",
42
+ "@gooddata/util": "11.62.0-alpha.3"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@gooddata/fixtures": "3.7.0",
@@ -63,11 +63,11 @@
63
63
  "oxlint-plugin-eslint": "1.82.0",
64
64
  "oxlint-tsgolint": "7.0.2001",
65
65
  "typescript": "7.0.2",
66
- "vitest": "4.1.11",
67
- "@gooddata/catalog-export": "11.62.0-alpha.2",
68
- "@gooddata/reference-workspace": "11.62.0-alpha.2",
69
- "@gooddata/oxlint-config": "11.62.0-alpha.2",
70
- "@gooddata/eslint-config": "11.62.0-alpha.2"
66
+ "vitest": "5.0.4",
67
+ "@gooddata/catalog-export": "11.62.0-alpha.3",
68
+ "@gooddata/eslint-config": "11.62.0-alpha.3",
69
+ "@gooddata/oxlint-config": "11.62.0-alpha.3",
70
+ "@gooddata/reference-workspace": "11.62.0-alpha.3"
71
71
  },
72
72
  "scripts": {
73
73
  "_phase:build": "npm run build",