1 |
|
2 | import get from "lodash/get";
|
3 | import find from "lodash/find";
|
4 | import omit from "lodash/omit";
|
5 | import cloneDeep from "lodash/cloneDeep";
|
6 | import { XhrModule } from "./xhr";
|
7 | import { ExecutionModule } from "./execution";
|
8 | import { IAdHocItemDescription, IStoredItemDescription, ItemDescription } from "./interfaces";
|
9 |
|
10 | const REQUEST_DEFAULTS = {
|
11 | types: ["attribute", "metric", "fact"],
|
12 | paging: {
|
13 | offset: 0,
|
14 | },
|
15 | };
|
16 |
|
17 | const LOAD_DATE_DATASET_DEFAULTS = {
|
18 | includeUnavailableDateDataSetsCount: true,
|
19 | includeAvailableDateAttributes: true,
|
20 | };
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | const getRequiredDataSets = (options: any) => {
|
36 | if (get(options, "returnAllRelatedDateDataSets")) {
|
37 | return {};
|
38 | }
|
39 |
|
40 | if (get(options, "returnAllDateDataSets")) {
|
41 | return { requiredDataSets: { type: "ALL" } };
|
42 | }
|
43 |
|
44 | if (get(options, "dataSetIdentifier")) {
|
45 | return {
|
46 | requiredDataSets: {
|
47 | type: "CUSTOM",
|
48 | customIdentifiers: [get(options, "dataSetIdentifier")],
|
49 | },
|
50 | };
|
51 | }
|
52 |
|
53 | return { requiredDataSets: { type: "PRODUCTION" } };
|
54 | };
|
55 |
|
56 | interface IColumnsAndDefinitions {
|
57 | columns: string[];
|
58 | definitions: any[];
|
59 | }
|
60 |
|
61 | const buildItemDescriptionObjects = ({ columns, definitions }: IColumnsAndDefinitions): ItemDescription[] => {
|
62 | if (!columns) {
|
63 | return [];
|
64 | }
|
65 |
|
66 | return columns.map((column: string) => {
|
67 | const definition = find(
|
68 | definitions,
|
69 | ({ metricDefinition }) => metricDefinition.identifier === column,
|
70 | );
|
71 | const maql = get(definition, "metricDefinition.expression");
|
72 | if (maql) {
|
73 | return { expression: maql };
|
74 | }
|
75 | return { uri: column };
|
76 | });
|
77 | };
|
78 |
|
79 | const isStoredItemDescription = (
|
80 | itemDescription: ItemDescription,
|
81 | ): itemDescription is IStoredItemDescription => {
|
82 | return !!(itemDescription as IStoredItemDescription).uri;
|
83 | };
|
84 |
|
85 | const isAdHocItemDescription = (
|
86 | itemDescription: ItemDescription,
|
87 | ): itemDescription is IAdHocItemDescription => {
|
88 | return !!(itemDescription as IAdHocItemDescription).expression;
|
89 | };
|
90 |
|
91 | const unwrapItemDescriptionObject = (itemDescription: ItemDescription): string => {
|
92 | if (isStoredItemDescription(itemDescription)) {
|
93 | return itemDescription.uri;
|
94 | }
|
95 | if (isAdHocItemDescription(itemDescription)) {
|
96 | return itemDescription.expression;
|
97 | }
|
98 | throw new Error("Item description can only have expression or uri");
|
99 | };
|
100 |
|
101 | export class CatalogueModule {
|
102 | constructor(private xhr: XhrModule, private execution: ExecutionModule) {}
|
103 |
|
104 | public loadItems(projectId: string, options = {}) {
|
105 | const request = omit(
|
106 | {
|
107 | ...REQUEST_DEFAULTS,
|
108 | ...options,
|
109 | ...getRequiredDataSets(options),
|
110 | },
|
111 | ["dataSetIdentifier", "returnAllDateDataSets", "attributesMap"],
|
112 | );
|
113 |
|
114 | const mdObj = get(cloneDeep(options), "bucketItems");
|
115 | const attributesMap = get(options, "attributesMap");
|
116 | const hasBuckets = get(mdObj, "buckets") !== undefined;
|
117 | if (hasBuckets) {
|
118 | return this.loadItemDescriptions(projectId, mdObj, attributesMap).then((bucketItems: any) =>
|
119 | this.loadCatalog(projectId, { ...request, bucketItems }),
|
120 | );
|
121 | }
|
122 |
|
123 | return this.loadCatalog(projectId, request);
|
124 | }
|
125 |
|
126 | public async loadDateDataSets(projectId: string, options: any) {
|
127 | const mdObj = cloneDeep(options).bucketItems;
|
128 | const bucketItems = mdObj
|
129 | ? await this.loadItemDescriptions(projectId, mdObj, get(options, "attributesMap"), true)
|
130 | : undefined;
|
131 |
|
132 | const omittedOptions = [
|
133 | "filter",
|
134 | "types",
|
135 | "paging",
|
136 | "dataSetIdentifier",
|
137 | "returnAllDateDataSets",
|
138 | "returnAllRelatedDateDataSets",
|
139 | "attributesMap",
|
140 | ];
|
141 |
|
142 |
|
143 | if (options.includeObjectsWithTags) {
|
144 | omittedOptions.push("excludeObjectsWithTags");
|
145 | }
|
146 |
|
147 | const request = omit(
|
148 | {
|
149 | ...LOAD_DATE_DATASET_DEFAULTS,
|
150 | ...REQUEST_DEFAULTS,
|
151 | ...options,
|
152 | ...getRequiredDataSets(options),
|
153 | bucketItems,
|
154 | },
|
155 | omittedOptions,
|
156 | );
|
157 |
|
158 | return this.requestDateDataSets(projectId, request);
|
159 | }
|
160 |
|
161 | |
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | public async loadItemDescriptionObjects(
|
174 | projectId: string,
|
175 | mdObj: any,
|
176 | attributesMap: any,
|
177 | removeDateItems = false,
|
178 | ): Promise<ItemDescription[]> {
|
179 | const definitionsAndColumns = await this.execution.mdToExecutionDefinitionsAndColumns(
|
180 | projectId,
|
181 | mdObj,
|
182 | { attributesMap, removeDateItems },
|
183 | );
|
184 |
|
185 | return buildItemDescriptionObjects(definitionsAndColumns);
|
186 | }
|
187 |
|
188 | |
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | public async loadItemDescriptions(
|
199 | projectId: string,
|
200 | mdObj: any,
|
201 | attributesMap: any,
|
202 | removeDateItems = false,
|
203 | ): Promise<string[]> {
|
204 | const itemDescriptions = await this.loadItemDescriptionObjects(
|
205 | projectId,
|
206 | mdObj,
|
207 | attributesMap,
|
208 | removeDateItems,
|
209 | );
|
210 |
|
211 | return itemDescriptions.map(unwrapItemDescriptionObject);
|
212 | }
|
213 |
|
214 | private requestDateDataSets(projectId: string, dateDataSetsRequest: any) {
|
215 | const uri = `/gdc/internal/projects/${projectId}/loadDateDataSets`;
|
216 |
|
217 | return this.xhr
|
218 | .post(uri, { data: { dateDataSetsRequest } })
|
219 | .then(r => r.getData())
|
220 | .then(data => data.dateDataSetsResponse);
|
221 | }
|
222 |
|
223 | private loadCatalog(projectId: string, catalogRequest: any) {
|
224 | const uri = `/gdc/internal/projects/${projectId}/loadCatalog`;
|
225 |
|
226 | return this.xhr
|
227 | .post(uri, { data: { catalogRequest } })
|
228 | .then(r => r.getData())
|
229 | .then(data => data.catalogResponse);
|
230 | }
|
231 | }
|