@sisense/sdk-cli 1.8.0 → 1.9.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.
@@ -1,5 +1,7 @@
1
1
  import { HttpClient } from '@sisense/sdk-rest-client';
2
2
  import { DataModel } from '@sisense/sdk-data';
3
+ import { DataSourceField } from '@sisense/sdk-query-client';
4
+ import { DataSourceSchemaDataset } from '../types.js';
3
5
  declare function getHttpClient(url: string, username?: string, password?: string, token?: string, wat?: string): HttpClient;
4
6
  export declare const handleHttpClientLogin: (httpClient: HttpClient) => Promise<void>;
5
7
  /**
@@ -27,4 +29,8 @@ export declare type SupportedOutputFilePathInfo = FilePathInfo & {
27
29
  extension: SupportedOutputFileExtension;
28
30
  };
29
31
  declare function isSupportedOutputFile(filePathInfo: FilePathInfo): filePathInfo is SupportedOutputFilePathInfo;
32
+ /**
33
+ * Add 'description' property from datasource schema columns to datasource fields
34
+ */
35
+ export declare function addDescriptionToFields(fields: DataSourceField[], datasets: DataSourceSchemaDataset[]): DataSourceField[];
30
36
  export { getHttpClient, createDataModel, rewriteDataModel, writeFile, getFilePathInfo, isSupportedOutputFile, };
@@ -1,5 +1,3 @@
1
- /* eslint-disable max-lines */
2
- /* eslint-disable max-lines-per-function */
3
1
  /* eslint-disable max-params */
4
2
  /* eslint-disable @typescript-eslint/restrict-template-expressions */
5
3
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
@@ -11,7 +9,8 @@ import { HttpClient, getAuthenticator, WatAuthenticator, BearerAuthenticator, }
11
9
  import { MetadataTypes } from '@sisense/sdk-data';
12
10
  import { writeTypescript, writeJavascript } from '@sisense/sdk-modeling';
13
11
  import path from 'path';
14
- import { DimensionalQueryClient } from '@sisense/sdk-query-client';
12
+ import levenshtein from 'js-levenshtein';
13
+ import { DimensionalQueryClient, } from '@sisense/sdk-query-client';
15
14
  import { PKG_VERSION } from '../package-version.js';
16
15
  import { trackCliError } from '@sisense/sdk-tracking';
17
16
  function getHttpClient(url, username, password, token, wat) {
@@ -39,24 +38,74 @@ export const handleHttpClientLogin = async (httpClient) => {
39
38
  }
40
39
  return Promise.resolve();
41
40
  };
41
+ async function retrieveDataSource(queryClient, dataSourceTitle) {
42
+ console.log('Getting data source... ');
43
+ const dataSourceList = await queryClient.getDataSourceList();
44
+ let minDistance = Number.MAX_SAFE_INTEGER;
45
+ let minDistanceDataSource = { title: dataSourceTitle, live: false };
46
+ dataSourceList.forEach((dataSource) => {
47
+ const title = dataSource.title;
48
+ if (title === dataSourceTitle) {
49
+ minDistanceDataSource = dataSource;
50
+ minDistance = 0;
51
+ }
52
+ else {
53
+ // get the most matching data source by comparing levenshtein distance on the title
54
+ const distance = levenshtein(dataSourceTitle, title);
55
+ if (distance < minDistance) {
56
+ minDistance = distance;
57
+ minDistanceDataSource = dataSource;
58
+ }
59
+ }
60
+ });
61
+ if (minDistance === 0) {
62
+ console.log('OK!\r\n');
63
+ return minDistanceDataSource;
64
+ }
65
+ throw new Error(`Data source '${dataSourceTitle}' not found. ${minDistance <= 3 ? `Did you mean '${minDistanceDataSource.title}'?` : ''}`);
66
+ }
67
+ async function retrieveDataFields(queryClient, dataSourceTitle) {
68
+ console.log('Getting fields... ');
69
+ const fields = await queryClient.getDataSourceFields(dataSourceTitle);
70
+ try {
71
+ // get the schema of the data source to add descriptions to the fields
72
+ const dataSourceSchema = await queryClient.getDataSourceSchema(dataSourceTitle);
73
+ return addDescriptionToFields(fields, dataSourceSchema.datasets);
74
+ }
75
+ catch (error) {
76
+ if (error.status === '403') {
77
+ // the caller may not have permission to access this data source
78
+ console.log(`Note: Field descriptions are omitted from the data model due to restricted role of your account`);
79
+ }
80
+ else {
81
+ throw error;
82
+ }
83
+ }
84
+ finally {
85
+ console.log('OK!\r\n');
86
+ }
87
+ return fields;
88
+ }
89
+ function combineDataSourceAndDataFields(dataSource, dataFields) {
90
+ return {
91
+ name: dataSource.title,
92
+ dataSource: {
93
+ title: dataSource.title,
94
+ type: dataSource.live ? 'live' : 'elasticube',
95
+ },
96
+ metadata: dataFields,
97
+ };
98
+ }
42
99
  /**
43
100
  * Create a data model for a Sisense data source
44
101
  */
45
102
  async function createDataModel(httpClient, dataSourceTitle) {
46
103
  const queryClient = new DimensionalQueryClient(httpClient);
47
- console.log('Getting fields... ');
48
104
  try {
49
- const [fields, dataSourceInfo] = await Promise.all([
50
- queryClient.getDataSourceFields(dataSourceTitle),
51
- queryClient.getDataSourceInfo(dataSourceTitle),
52
- ]);
53
- console.log('OK!\r\n');
54
- const dataModel = {
55
- name: dataSourceTitle,
56
- dataSource: dataSourceInfo,
57
- metadata: fields,
58
- };
59
- return rewriteDataModel(dataModel);
105
+ const dataSource = await retrieveDataSource(queryClient, dataSourceTitle);
106
+ const dataFields = await retrieveDataFields(queryClient, dataSourceTitle);
107
+ const rawDataModel = combineDataSourceAndDataFields(dataSource, dataFields);
108
+ return rewriteDataModel(rawDataModel);
60
109
  }
61
110
  catch (err) {
62
111
  trackCliError({
@@ -78,6 +127,7 @@ function rewriteDataModel(dataModel) {
78
127
  expression: item.id,
79
128
  type: MetadataTypes.Dimension,
80
129
  group: undefined,
130
+ description: item.description,
81
131
  };
82
132
  result.group = item.table;
83
133
  switch (item.dimtype) {
@@ -165,4 +215,22 @@ function getFullFilePath(filePathInfo) {
165
215
  function isSupportedOutputFile(filePathInfo) {
166
216
  return ['.ts', '.js'].includes(filePathInfo.extension);
167
217
  }
218
+ /**
219
+ * Add 'description' property from datasource schema columns to datasource fields
220
+ */
221
+ export function addDescriptionToFields(fields, datasets) {
222
+ const schemaDataDescriptionsMap = datasets.reduce((map, dataset) => {
223
+ dataset.schema.tables.forEach((table) => {
224
+ map[table.name] = {};
225
+ table.columns.forEach((column) => {
226
+ map[table.name][column.name] = column.description;
227
+ });
228
+ });
229
+ return map;
230
+ }, {});
231
+ return fields.map((field) => ({
232
+ ...field,
233
+ description: schemaDataDescriptionsMap[field.table]?.[field.column] || '',
234
+ }));
235
+ }
168
236
  export { getHttpClient, createDataModel, rewriteDataModel, writeFile, getFilePathInfo, isSupportedOutputFile, };
@@ -1 +1 @@
1
- export declare const PKG_VERSION = "1.8.0";
1
+ export declare const PKG_VERSION = "1.9.0";
@@ -1 +1 @@
1
- export const PKG_VERSION = "1.8.0";
1
+ export const PKG_VERSION = "1.9.0";
package/dist/types.d.ts CHANGED
@@ -19,4 +19,26 @@ export declare type GetApiTokenOptions = {
19
19
  username: string;
20
20
  password: string | undefined;
21
21
  };
22
+ /**
23
+ * Data source schema table
24
+ *
25
+ * @internal
26
+ */
27
+ export declare type DataSourceSchemaTable = {
28
+ name: string;
29
+ columns: {
30
+ name: string;
31
+ description: string | null;
32
+ }[];
33
+ };
34
+ /**
35
+ * Data source schema table
36
+ *
37
+ * @internal
38
+ */
39
+ export declare type DataSourceSchemaDataset = {
40
+ schema: {
41
+ tables: DataSourceSchemaTable[];
42
+ };
43
+ };
22
44
  export {};
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "Sisense",
12
12
  "Compose SDK"
13
13
  ],
14
- "version": "1.8.0",
14
+ "version": "1.9.0",
15
15
  "type": "module",
16
16
  "exports": "./dist/index.js",
17
17
  "main": "./dist/index.js",
@@ -20,14 +20,15 @@
20
20
  "license": "SEE LICENSE IN LICENSE.md",
21
21
  "bin": "./dist/index.js",
22
22
  "dependencies": {
23
- "@sisense/sdk-common": "^1.8.0",
24
- "@sisense/sdk-data": "^1.8.0",
25
- "@sisense/sdk-modeling": "^1.8.0",
26
- "@sisense/sdk-query-client": "^1.8.0",
27
- "@sisense/sdk-rest-client": "^1.8.0",
28
- "@sisense/sdk-tracking": "^1.8.0",
23
+ "@sisense/sdk-common": "^1.9.0",
24
+ "@sisense/sdk-data": "^1.9.0",
25
+ "@sisense/sdk-modeling": "^1.9.0",
26
+ "@sisense/sdk-query-client": "^1.9.0",
27
+ "@sisense/sdk-rest-client": "^1.9.0",
28
+ "@sisense/sdk-tracking": "^1.9.0",
29
29
  "cross-fetch": "^4.0.0",
30
30
  "inquirer": "^8.1.2",
31
+ "js-levenshtein": "^1.1.6",
31
32
  "node-window-polyfill": "^1.0.2",
32
33
  "yargs": "17.7.1"
33
34
  },
@@ -54,6 +55,7 @@
54
55
  "devDependencies": {
55
56
  "@babel/preset-env": "^7.20.2",
56
57
  "@types/inquirer": "8.2.6",
58
+ "@types/js-levenshtein": "^1.1.3",
57
59
  "@types/yargs": "^17.0.22",
58
60
  "eslint": "^8.40.0",
59
61
  "msw": "2.2.1",