@claryai/cli 0.1.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/LICENSE +25 -0
- package/README.md +197 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/ajv.d.ts +3 -0
- package/dist/ajv.d.ts.map +1 -0
- package/dist/ajv.js +13 -0
- package/dist/analytics/analytics.d.ts +370 -0
- package/dist/analytics/analytics.d.ts.map +1 -0
- package/dist/analytics/analytics.js +143 -0
- package/dist/config.d.ts +34 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +134 -0
- package/dist/dbt/context.d.ts +14 -0
- package/dist/dbt/context.d.ts.map +1 -0
- package/dist/dbt/context.js +76 -0
- package/dist/dbt/context.test.d.ts +2 -0
- package/dist/dbt/context.test.d.ts.map +1 -0
- package/dist/dbt/context.test.js +152 -0
- package/dist/dbt/manifest.d.ts +7 -0
- package/dist/dbt/manifest.d.ts.map +1 -0
- package/dist/dbt/manifest.js +23 -0
- package/dist/dbt/models.d.ts +43 -0
- package/dist/dbt/models.d.ts.map +1 -0
- package/dist/dbt/models.js +256 -0
- package/dist/dbt/models.test.d.ts +2 -0
- package/dist/dbt/models.test.d.ts.map +1 -0
- package/dist/dbt/models.test.js +19 -0
- package/dist/dbt/profile.d.ts +9 -0
- package/dist/dbt/profile.d.ts.map +1 -0
- package/dist/dbt/profile.js +86 -0
- package/dist/dbt/profiles.test.d.ts +2 -0
- package/dist/dbt/profiles.test.d.ts.map +1 -0
- package/dist/dbt/profiles.test.js +50 -0
- package/dist/dbt/schema.d.ts +31 -0
- package/dist/dbt/schema.d.ts.map +1 -0
- package/dist/dbt/schema.js +49 -0
- package/dist/dbt/targets/Bigquery/index.d.ts +18 -0
- package/dist/dbt/targets/Bigquery/index.d.ts.map +1 -0
- package/dist/dbt/targets/Bigquery/index.js +105 -0
- package/dist/dbt/targets/Bigquery/oauth.d.ts +2 -0
- package/dist/dbt/targets/Bigquery/oauth.d.ts.map +1 -0
- package/dist/dbt/targets/Bigquery/oauth.js +43 -0
- package/dist/dbt/targets/Bigquery/serviceAccount.d.ts +35 -0
- package/dist/dbt/targets/Bigquery/serviceAccount.d.ts.map +1 -0
- package/dist/dbt/targets/Bigquery/serviceAccount.js +149 -0
- package/dist/dbt/targets/Databricks/oauth.d.ts +21 -0
- package/dist/dbt/targets/Databricks/oauth.d.ts.map +1 -0
- package/dist/dbt/targets/Databricks/oauth.js +184 -0
- package/dist/dbt/targets/athena.d.ts +21 -0
- package/dist/dbt/targets/athena.d.ts.map +1 -0
- package/dist/dbt/targets/athena.js +91 -0
- package/dist/dbt/targets/athena.test.d.ts +2 -0
- package/dist/dbt/targets/athena.test.d.ts.map +1 -0
- package/dist/dbt/targets/athena.test.js +60 -0
- package/dist/dbt/targets/clickhouse.d.ts +24 -0
- package/dist/dbt/targets/clickhouse.d.ts.map +1 -0
- package/dist/dbt/targets/clickhouse.js +90 -0
- package/dist/dbt/targets/databricks.d.ts +27 -0
- package/dist/dbt/targets/databricks.d.ts.map +1 -0
- package/dist/dbt/targets/databricks.js +138 -0
- package/dist/dbt/targets/duckdb.d.ts +16 -0
- package/dist/dbt/targets/duckdb.d.ts.map +1 -0
- package/dist/dbt/targets/duckdb.js +63 -0
- package/dist/dbt/targets/duckdb.test.d.ts +2 -0
- package/dist/dbt/targets/duckdb.test.d.ts.map +1 -0
- package/dist/dbt/targets/duckdb.test.js +37 -0
- package/dist/dbt/targets/postgres.d.ts +26 -0
- package/dist/dbt/targets/postgres.d.ts.map +1 -0
- package/dist/dbt/targets/postgres.js +142 -0
- package/dist/dbt/targets/redshift.d.ts +23 -0
- package/dist/dbt/targets/redshift.d.ts.map +1 -0
- package/dist/dbt/targets/redshift.js +96 -0
- package/dist/dbt/targets/snowflake.d.ts +4 -0
- package/dist/dbt/targets/snowflake.d.ts.map +1 -0
- package/dist/dbt/targets/snowflake.js +134 -0
- package/dist/dbt/targets/trino.d.ts +16 -0
- package/dist/dbt/targets/trino.d.ts.map +1 -0
- package/dist/dbt/targets/trino.js +65 -0
- package/dist/dbt/templating.d.ts +15 -0
- package/dist/dbt/templating.d.ts.map +1 -0
- package/dist/dbt/templating.js +50 -0
- package/dist/dbt/templating.test.d.ts +2 -0
- package/dist/dbt/templating.test.d.ts.map +1 -0
- package/dist/dbt/templating.test.js +51 -0
- package/dist/dbt/types.d.ts +17 -0
- package/dist/dbt/types.d.ts.map +1 -0
- package/dist/dbt/types.js +2 -0
- package/dist/dbt/validation.d.ts +9 -0
- package/dist/dbt/validation.d.ts.map +1 -0
- package/dist/dbt/validation.js +54 -0
- package/dist/env.d.ts +12 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +40 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +12 -0
- package/dist/globalState.d.ts +29 -0
- package/dist/globalState.d.ts.map +1 -0
- package/dist/globalState.js +67 -0
- package/dist/handlers/asyncQuery.d.ts +7 -0
- package/dist/handlers/asyncQuery.d.ts.map +1 -0
- package/dist/handlers/asyncQuery.js +50 -0
- package/dist/handlers/compile.d.ts +16 -0
- package/dist/handlers/compile.d.ts.map +1 -0
- package/dist/handlers/compile.js +277 -0
- package/dist/handlers/compile.test.d.ts +2 -0
- package/dist/handlers/compile.test.d.ts.map +1 -0
- package/dist/handlers/compile.test.js +201 -0
- package/dist/handlers/createProject.d.ts +37 -0
- package/dist/handlers/createProject.d.ts.map +1 -0
- package/dist/handlers/createProject.js +272 -0
- package/dist/handlers/dbt/apiClient.d.ts +14 -0
- package/dist/handlers/dbt/apiClient.d.ts.map +1 -0
- package/dist/handlers/dbt/apiClient.js +167 -0
- package/dist/handlers/dbt/compile.d.ts +35 -0
- package/dist/handlers/dbt/compile.d.ts.map +1 -0
- package/dist/handlers/dbt/compile.js +220 -0
- package/dist/handlers/dbt/getDbtProfileTargetName.d.ts +9 -0
- package/dist/handlers/dbt/getDbtProfileTargetName.d.ts.map +1 -0
- package/dist/handlers/dbt/getDbtProfileTargetName.js +44 -0
- package/dist/handlers/dbt/getDbtVersion.d.ts +16 -0
- package/dist/handlers/dbt/getDbtVersion.d.ts.map +1 -0
- package/dist/handlers/dbt/getDbtVersion.js +141 -0
- package/dist/handlers/dbt/getDbtVersion.mocks.d.ts +11 -0
- package/dist/handlers/dbt/getDbtVersion.mocks.d.ts.map +1 -0
- package/dist/handlers/dbt/getDbtVersion.mocks.js +70 -0
- package/dist/handlers/dbt/getDbtVersion.test.d.ts +2 -0
- package/dist/handlers/dbt/getDbtVersion.test.d.ts.map +1 -0
- package/dist/handlers/dbt/getDbtVersion.test.js +97 -0
- package/dist/handlers/dbt/getWarehouseClient.d.ts +24 -0
- package/dist/handlers/dbt/getWarehouseClient.d.ts.map +1 -0
- package/dist/handlers/dbt/getWarehouseClient.js +312 -0
- package/dist/handlers/dbt/refresh.d.ts +11 -0
- package/dist/handlers/dbt/refresh.d.ts.map +1 -0
- package/dist/handlers/dbt/refresh.js +114 -0
- package/dist/handlers/dbt/run.d.ts +14 -0
- package/dist/handlers/dbt/run.d.ts.map +1 -0
- package/dist/handlers/dbt/run.js +67 -0
- package/dist/handlers/deploy.d.ts +26 -0
- package/dist/handlers/deploy.d.ts.map +1 -0
- package/dist/handlers/deploy.js +377 -0
- package/dist/handlers/diagnostics.d.ts +11 -0
- package/dist/handlers/diagnostics.d.ts.map +1 -0
- package/dist/handlers/diagnostics.js +194 -0
- package/dist/handlers/download.d.ts +29 -0
- package/dist/handlers/download.d.ts.map +1 -0
- package/dist/handlers/download.js +955 -0
- package/dist/handlers/exportChartImage.d.ts +7 -0
- package/dist/handlers/exportChartImage.d.ts.map +1 -0
- package/dist/handlers/exportChartImage.js +33 -0
- package/dist/handlers/generate.d.ts +13 -0
- package/dist/handlers/generate.d.ts.map +1 -0
- package/dist/handlers/generate.js +159 -0
- package/dist/handlers/generateExposures.d.ts +8 -0
- package/dist/handlers/generateExposures.d.ts.map +1 -0
- package/dist/handlers/generateExposures.js +100 -0
- package/dist/handlers/getProject.d.ts +6 -0
- package/dist/handlers/getProject.d.ts.map +1 -0
- package/dist/handlers/getProject.js +43 -0
- package/dist/handlers/installSkills.d.ts +12 -0
- package/dist/handlers/installSkills.d.ts.map +1 -0
- package/dist/handlers/installSkills.js +321 -0
- package/dist/handlers/lint/ajvToSarif.d.ts +66 -0
- package/dist/handlers/lint/ajvToSarif.d.ts.map +1 -0
- package/dist/handlers/lint/ajvToSarif.js +222 -0
- package/dist/handlers/lint/sarifFormatter.d.ts +14 -0
- package/dist/handlers/lint/sarifFormatter.d.ts.map +1 -0
- package/dist/handlers/lint/sarifFormatter.js +111 -0
- package/dist/handlers/lint.d.ts +8 -0
- package/dist/handlers/lint.d.ts.map +1 -0
- package/dist/handlers/lint.js +308 -0
- package/dist/handlers/listProjects.d.ts +6 -0
- package/dist/handlers/listProjects.d.ts.map +1 -0
- package/dist/handlers/listProjects.js +53 -0
- package/dist/handlers/login/oauth.d.ts +2 -0
- package/dist/handlers/login/oauth.d.ts.map +1 -0
- package/dist/handlers/login/oauth.js +27 -0
- package/dist/handlers/login/pat.d.ts +2 -0
- package/dist/handlers/login/pat.d.ts.map +1 -0
- package/dist/handlers/login/pat.js +31 -0
- package/dist/handlers/login.d.ts +15 -0
- package/dist/handlers/login.d.ts.map +1 -0
- package/dist/handlers/login.js +239 -0
- package/dist/handlers/metadataFile.d.ts +9 -0
- package/dist/handlers/metadataFile.d.ts.map +1 -0
- package/dist/handlers/metadataFile.js +34 -0
- package/dist/handlers/oauthLogin.d.ts +6 -0
- package/dist/handlers/oauthLogin.d.ts.map +1 -0
- package/dist/handlers/oauthLogin.js +191 -0
- package/dist/handlers/preview.d.ts +29 -0
- package/dist/handlers/preview.d.ts.map +1 -0
- package/dist/handlers/preview.js +415 -0
- package/dist/handlers/renameHandler.d.ts +16 -0
- package/dist/handlers/renameHandler.d.ts.map +1 -0
- package/dist/handlers/renameHandler.js +160 -0
- package/dist/handlers/runChart.d.ts +10 -0
- package/dist/handlers/runChart.d.ts.map +1 -0
- package/dist/handlers/runChart.js +105 -0
- package/dist/handlers/selectProject.d.ts +20 -0
- package/dist/handlers/selectProject.d.ts.map +1 -0
- package/dist/handlers/selectProject.js +91 -0
- package/dist/handlers/setProject.d.ts +14 -0
- package/dist/handlers/setProject.d.ts.map +1 -0
- package/dist/handlers/setProject.js +131 -0
- package/dist/handlers/setWarehouse.d.ts +14 -0
- package/dist/handlers/setWarehouse.d.ts.map +1 -0
- package/dist/handlers/setWarehouse.js +94 -0
- package/dist/handlers/sql.d.ts +9 -0
- package/dist/handlers/sql.d.ts.map +1 -0
- package/dist/handlers/sql.js +89 -0
- package/dist/handlers/utils.d.ts +11 -0
- package/dist/handlers/utils.d.ts.map +1 -0
- package/dist/handlers/utils.js +36 -0
- package/dist/handlers/validate.d.ts +22 -0
- package/dist/handlers/validate.d.ts.map +1 -0
- package/dist/handlers/validate.js +201 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +581 -0
- package/dist/lightdash/loader.d.ts +21 -0
- package/dist/lightdash/loader.d.ts.map +1 -0
- package/dist/lightdash/loader.js +122 -0
- package/dist/lightdash/projectType.d.ts +84 -0
- package/dist/lightdash/projectType.d.ts.map +1 -0
- package/dist/lightdash/projectType.js +75 -0
- package/dist/lightdash-config/index.d.ts +2 -0
- package/dist/lightdash-config/index.d.ts.map +1 -0
- package/dist/lightdash-config/index.js +41 -0
- package/dist/lightdash-config/lightdash-config.test.d.ts +2 -0
- package/dist/lightdash-config/lightdash-config.test.d.ts.map +1 -0
- package/dist/lightdash-config/lightdash-config.test.js +70 -0
- package/dist/styles.d.ts +10 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +14 -0
- package/entitlements.plist +33 -0
- package/package.json +71 -0
- package/track.sh +116 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globalState.d.ts","sourceRoot":"","sources":["../src/globalState.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,KAAK,YAAY,GAAG;IAChB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAEF,cAAM,WAAW;IACb,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,cAAc,CAAkB;IAExC,OAAO,CAAC,aAAa,CAAsB;IAE3C,OAAO,CAAC,kBAAkB,CAAe;IAEzC,OAAO,CAAC,SAAS,CAAuB;;IAMxC,YAAY,IAAI,MAAM;IAOtB,iBAAiB,CAAC,KAAK,EAAE,OAAO;IAIhC,gBAAgB,IAAI,OAAO;IAI3B,gBAAgB;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG;IAMrD,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE;IAUlD,UAAU,CAAC,OAAO,EAAE,OAAO;IAI3B,oBAAoB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC7C,MAAM,EAAE,CAAC,GACV,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAI9B,gBAAgB,CAAC,CAAC,SAAS,MAAM,YAAY,EACzC,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAK1B,iBAAiB;IAIjB,KAAK,CAAC,OAAO,EAAE,MAAM;IAMrB,cAAc,CAAC,MAAM,EAAE,MAAM;CAKhC;;AAED,wBAAiC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const ora_1 = tslib_1.__importDefault(require("ora"));
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
const styles = tslib_1.__importStar(require("./styles"));
|
|
7
|
+
class GlobalState {
|
|
8
|
+
verbose = false;
|
|
9
|
+
nonInteractive = false;
|
|
10
|
+
activeSpinner;
|
|
11
|
+
savedPromptAnswers;
|
|
12
|
+
sessionId = null;
|
|
13
|
+
constructor() {
|
|
14
|
+
this.savedPromptAnswers = {};
|
|
15
|
+
}
|
|
16
|
+
getSessionId() {
|
|
17
|
+
if (!this.sessionId) {
|
|
18
|
+
this.sessionId = (0, uuid_1.v4)();
|
|
19
|
+
}
|
|
20
|
+
return this.sessionId;
|
|
21
|
+
}
|
|
22
|
+
setNonInteractive(value) {
|
|
23
|
+
this.nonInteractive = value;
|
|
24
|
+
}
|
|
25
|
+
isNonInteractive() {
|
|
26
|
+
return this.nonInteractive || process.env.CI === 'true';
|
|
27
|
+
}
|
|
28
|
+
getActiveSpinner() {
|
|
29
|
+
return this.activeSpinner;
|
|
30
|
+
}
|
|
31
|
+
startSpinner(options) {
|
|
32
|
+
this.activeSpinner = (0, ora_1.default)(options);
|
|
33
|
+
this.activeSpinner.start();
|
|
34
|
+
return this.activeSpinner;
|
|
35
|
+
}
|
|
36
|
+
log(message, ...optionalParams) {
|
|
37
|
+
const spinner = this.getActiveSpinner();
|
|
38
|
+
const shouldRestartSpinner = spinner?.isSpinning;
|
|
39
|
+
spinner?.stop();
|
|
40
|
+
console.error(message, ...optionalParams);
|
|
41
|
+
if (shouldRestartSpinner) {
|
|
42
|
+
spinner?.start();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
setVerbose(verbose) {
|
|
46
|
+
this.verbose = verbose;
|
|
47
|
+
}
|
|
48
|
+
getSavedPromptAnswer(prompt) {
|
|
49
|
+
return this.savedPromptAnswers[prompt];
|
|
50
|
+
}
|
|
51
|
+
savePromptAnswer(prompt, value) {
|
|
52
|
+
this.savedPromptAnswers[prompt] = value;
|
|
53
|
+
}
|
|
54
|
+
clearPromptAnswer() {
|
|
55
|
+
this.savedPromptAnswers = {};
|
|
56
|
+
}
|
|
57
|
+
debug(message) {
|
|
58
|
+
if (this.verbose) {
|
|
59
|
+
this.log(styles.debug(message));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
logProjectInfo(config) {
|
|
63
|
+
const projectUuid = config.context?.project;
|
|
64
|
+
this.log(`\n${styles.success('Using project:')} ${projectUuid}\n`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.default = new GlobalState();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ApiGetAsyncQueryResults, ResultRow } from '@lightdash/common';
|
|
2
|
+
export declare function pollForResults(projectUuid: string, queryUuid: string, options?: {
|
|
3
|
+
pageSize?: number;
|
|
4
|
+
backoffMs?: number;
|
|
5
|
+
}): Promise<ApiGetAsyncQueryResults>;
|
|
6
|
+
export declare function resultsToCsv(columns: string[], rows: ResultRow[]): string;
|
|
7
|
+
//# sourceMappingURL=asyncQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncQuery.d.ts","sourceRoot":"","sources":["../../src/handlers/asyncQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EAEvB,SAAS,EACZ,MAAM,mBAAmB,CAAC;AAa3B,wBAAsB,cAAc,CAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACxD,OAAO,CAAC,uBAAuB,CAAC,CAwBlC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,CAkBzE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pollForResults = pollForResults;
|
|
4
|
+
exports.resultsToCsv = resultsToCsv;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const common_1 = require("@lightdash/common");
|
|
7
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
8
|
+
const apiClient_1 = require("./dbt/apiClient");
|
|
9
|
+
const INITIAL_BACKOFF_MS = 250;
|
|
10
|
+
const MAX_BACKOFF_MS = 1000;
|
|
11
|
+
function sleep(ms) {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
setTimeout(resolve, ms);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async function pollForResults(projectUuid, queryUuid, options = {}) {
|
|
17
|
+
const { pageSize, backoffMs = INITIAL_BACKOFF_MS } = options;
|
|
18
|
+
const pageSizeParam = pageSize ? `?pageSize=${pageSize}` : '';
|
|
19
|
+
const result = await (0, apiClient_1.lightdashApi)({
|
|
20
|
+
method: 'GET',
|
|
21
|
+
url: `/api/v2/projects/${projectUuid}/query/${queryUuid}${pageSizeParam}`,
|
|
22
|
+
body: undefined,
|
|
23
|
+
});
|
|
24
|
+
globalState_1.default.debug(`> Query status: ${result.status}`);
|
|
25
|
+
if (result.status === common_1.QueryHistoryStatus.PENDING ||
|
|
26
|
+
result.status === common_1.QueryHistoryStatus.QUEUED ||
|
|
27
|
+
result.status === common_1.QueryHistoryStatus.EXECUTING) {
|
|
28
|
+
await sleep(backoffMs);
|
|
29
|
+
return pollForResults(projectUuid, queryUuid, {
|
|
30
|
+
pageSize,
|
|
31
|
+
backoffMs: Math.min(backoffMs * 2, MAX_BACKOFF_MS),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
function resultsToCsv(columns, rows) {
|
|
37
|
+
const escapeValue = (value) => {
|
|
38
|
+
if (value === null || value === undefined) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
const str = String(value);
|
|
42
|
+
if (str.includes(',') || str.includes('"') || str.includes('\n')) {
|
|
43
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
44
|
+
}
|
|
45
|
+
return str;
|
|
46
|
+
};
|
|
47
|
+
const header = columns.map(escapeValue).join(',');
|
|
48
|
+
const dataRows = rows.map((row) => columns.map((col) => escapeValue(row[col]?.value?.raw)).join(','));
|
|
49
|
+
return [header, ...dataRows].join('\n');
|
|
50
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Explore, ExploreError } from '@lightdash/common';
|
|
2
|
+
import { DbtCompileOptions } from './dbt/compile';
|
|
3
|
+
export type CompileHandlerOptions = DbtCompileOptions & {
|
|
4
|
+
projectDir: string;
|
|
5
|
+
profilesDir: string;
|
|
6
|
+
target: string | undefined;
|
|
7
|
+
profile: string | undefined;
|
|
8
|
+
vars: string | undefined;
|
|
9
|
+
verbose: boolean;
|
|
10
|
+
startOfWeek?: number;
|
|
11
|
+
warehouseCredentials?: boolean;
|
|
12
|
+
disableTimestampConversion?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export declare const compile: (options: CompileHandlerOptions) => Promise<(Explore | ExploreError)[]>;
|
|
15
|
+
export declare const compileHandler: (originalOptions: CompileHandlerOptions) => Promise<void>;
|
|
16
|
+
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/handlers/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,OAAO,EACP,YAAY,EAYf,MAAM,mBAAmB,CAAC;AAa3B,OAAO,EAAE,iBAAiB,EAA8B,MAAM,eAAe,CAAC;AAI9E,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAwHF,eAAO,MAAM,OAAO,GAAU,SAAS,qBAAqB,wCAmP3D,CAAC;AAEF,eAAO,MAAM,cAAc,GACvB,iBAAiB,qBAAqB,kBAmCzC,CAAC"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileHandler = exports.compile = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@lightdash/common");
|
|
6
|
+
const warehouses_1 = require("@lightdash/warehouses");
|
|
7
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
8
|
+
const uuid_1 = require("uuid");
|
|
9
|
+
const analytics_1 = require("../analytics/analytics");
|
|
10
|
+
const context_1 = require("../dbt/context");
|
|
11
|
+
const manifest_1 = require("../dbt/manifest");
|
|
12
|
+
const validation_1 = require("../dbt/validation");
|
|
13
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
14
|
+
const lightdash_config_1 = require("../lightdash-config");
|
|
15
|
+
const loader_1 = require("../lightdash/loader");
|
|
16
|
+
const projectType_1 = require("../lightdash/projectType");
|
|
17
|
+
const styles = tslib_1.__importStar(require("../styles"));
|
|
18
|
+
const compile_1 = require("./dbt/compile");
|
|
19
|
+
const getDbtVersion_1 = require("./dbt/getDbtVersion");
|
|
20
|
+
const getWarehouseClient_1 = tslib_1.__importDefault(require("./dbt/getWarehouseClient"));
|
|
21
|
+
const getExploresFromLightdashYmlProject = async (projectDir, lightdashProjectConfig, startOfWeek, disableTimestampConversion) => {
|
|
22
|
+
// Try to load Lightdash YAML models
|
|
23
|
+
const lightdashModels = await (0, loader_1.loadLightdashModels)(projectDir);
|
|
24
|
+
if (lightdashModels.length === 0) {
|
|
25
|
+
return null; // No Lightdash models, use dbt path
|
|
26
|
+
}
|
|
27
|
+
globalState_1.default.debug(`> Found ${lightdashModels.length} Lightdash YAML models`);
|
|
28
|
+
if (!lightdashProjectConfig.warehouse?.type) {
|
|
29
|
+
throw new common_1.ParseError('Lightdash models found but no warehouse type specified in lightdash.config.yml.\n' +
|
|
30
|
+
'Add a warehouse section:\n' +
|
|
31
|
+
'warehouse:\n' +
|
|
32
|
+
' type: postgres # or bigquery, snowflake, redshift, databricks, trino, clickhouse');
|
|
33
|
+
}
|
|
34
|
+
const adapterType = lightdashProjectConfig.warehouse.type;
|
|
35
|
+
globalState_1.default.debug(`> Using adapter type from lightdash.config.yml: ${adapterType}`);
|
|
36
|
+
// Convert Lightdash models to DbtModelNode format
|
|
37
|
+
const validModels = (0, common_1.convertLightdashModelsToDbtModels)(lightdashModels);
|
|
38
|
+
if (validModels.length === 0) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
globalState_1.default.debug('> Skipping warehouse catalog (types in YAML)');
|
|
42
|
+
const warehouseSqlBuilder = (0, warehouses_1.warehouseSqlBuilderFromType)(adapterType, startOfWeek);
|
|
43
|
+
const validExplores = await (0, common_1.convertExplores)(validModels, false, warehouseSqlBuilder.getAdapterType(), [], warehouseSqlBuilder, lightdashProjectConfig, {
|
|
44
|
+
disableTimestampConversion,
|
|
45
|
+
allowPartialCompilation: process.env.PARTIAL_COMPILATION_ENABLED !== 'false',
|
|
46
|
+
postProcessors: [common_1.preAggregatePostProcessor],
|
|
47
|
+
});
|
|
48
|
+
return validExplores;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* When using --defer, non-selected models pulled in via joins
|
|
52
|
+
* have incorrect schema/relation_name (they point to the dev target
|
|
53
|
+
* instead of production). Return new models with production values
|
|
54
|
+
* from the state manifest.
|
|
55
|
+
*/
|
|
56
|
+
async function patchDeferredModels(compiledModels, originallySelectedModelIds, state) {
|
|
57
|
+
const statePath = path_1.default.resolve(state);
|
|
58
|
+
globalState_1.default.debug(`> Loading state manifest for defer from ${statePath}`);
|
|
59
|
+
try {
|
|
60
|
+
const stateManifest = await (0, manifest_1.loadManifest)({
|
|
61
|
+
targetDir: statePath,
|
|
62
|
+
});
|
|
63
|
+
const stateModels = (0, common_1.getModelsFromManifest)(stateManifest);
|
|
64
|
+
const stateModelMap = new Map(stateModels.map((m) => [m.unique_id, m]));
|
|
65
|
+
const patchedModels = compiledModels.map((model) => {
|
|
66
|
+
if (originallySelectedModelIds.includes(model.unique_id)) {
|
|
67
|
+
return model;
|
|
68
|
+
}
|
|
69
|
+
const stateModel = stateModelMap.get(model.unique_id);
|
|
70
|
+
if (!stateModel) {
|
|
71
|
+
return model;
|
|
72
|
+
}
|
|
73
|
+
globalState_1.default.debug(`> Deferred model ${model.name}: using production schema ${stateModel.schema}`);
|
|
74
|
+
return {
|
|
75
|
+
...model,
|
|
76
|
+
relation_name: stateModel.relation_name,
|
|
77
|
+
schema: stateModel.schema,
|
|
78
|
+
database: stateModel.database,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
const patchedCount = patchedModels.filter((m, i) => m !== compiledModels[i]).length;
|
|
82
|
+
if (patchedCount > 0) {
|
|
83
|
+
globalState_1.default.debug(`> Patched ${patchedCount} deferred model(s) with production schema`);
|
|
84
|
+
}
|
|
85
|
+
return patchedModels;
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
globalState_1.default.debug(`> Warning: Could not load state manifest for defer patching: ${(0, common_1.getErrorMessage)(e)}`);
|
|
89
|
+
return compiledModels;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const compile = async (options) => {
|
|
93
|
+
const dbtVersionResult = await (0, getDbtVersion_1.tryGetDbtVersion)();
|
|
94
|
+
const executionId = (0, uuid_1.v4)();
|
|
95
|
+
const startTime = Date.now();
|
|
96
|
+
await analytics_1.LightdashAnalytics.track({
|
|
97
|
+
event: 'compile.started',
|
|
98
|
+
properties: {
|
|
99
|
+
executionId,
|
|
100
|
+
dbtVersion: dbtVersionResult.success
|
|
101
|
+
? dbtVersionResult.version.verboseVersion
|
|
102
|
+
: undefined,
|
|
103
|
+
useDbtList: !!options.useDbtList,
|
|
104
|
+
skipWarehouseCatalog: !!options.skipWarehouseCatalog,
|
|
105
|
+
skipDbtCompile: !!options.skipDbtCompile,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
const absoluteProjectPath = path_1.default.resolve(options.projectDir);
|
|
109
|
+
globalState_1.default.debug(`> Compiling with project dir ${absoluteProjectPath}`);
|
|
110
|
+
const lightdashProjectConfig = await (0, lightdash_config_1.readAndLoadLightdashProjectConfig)(absoluteProjectPath);
|
|
111
|
+
globalState_1.default.debug(`> Loaded Clary project config`);
|
|
112
|
+
// Try Clary project compile
|
|
113
|
+
let explores = null;
|
|
114
|
+
let dbtMetrics = null;
|
|
115
|
+
explores = await getExploresFromLightdashYmlProject(absoluteProjectPath, lightdashProjectConfig, options.startOfWeek, options.disableTimestampConversion);
|
|
116
|
+
// Load dbt Project
|
|
117
|
+
if (explores === null) {
|
|
118
|
+
if (!dbtVersionResult.success) {
|
|
119
|
+
await analytics_1.LightdashAnalytics.track({
|
|
120
|
+
event: 'compile.error',
|
|
121
|
+
properties: {
|
|
122
|
+
executionId,
|
|
123
|
+
error: 'dbt not found',
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
throw dbtVersionResult.error;
|
|
127
|
+
}
|
|
128
|
+
const context = await (0, context_1.getDbtContext)({
|
|
129
|
+
projectDir: absoluteProjectPath,
|
|
130
|
+
targetPath: options.targetPath,
|
|
131
|
+
});
|
|
132
|
+
const { compiledModelIds, originallySelectedModelIds } = await (0, compile_1.maybeCompileModelsAndJoins)({ targetDir: context.targetDir }, options);
|
|
133
|
+
const manifest = await (0, manifest_1.loadManifest)({ targetDir: context.targetDir });
|
|
134
|
+
const manifestVersion = (0, common_1.getDbtManifestVersion)(manifest);
|
|
135
|
+
const manifestModels = (0, common_1.getModelsFromManifest)(manifest);
|
|
136
|
+
const compiledModels = (0, common_1.getCompiledModels)(manifestModels, compiledModelIds);
|
|
137
|
+
// When using --defer, non-selected models pulled in via joins
|
|
138
|
+
// have incorrect schema/relation_name (they point to the dev target
|
|
139
|
+
// instead of production). Patch them from the state manifest.
|
|
140
|
+
const modelsForValidation = options.defer && options.state && originallySelectedModelIds
|
|
141
|
+
? await patchDeferredModels(compiledModels, originallySelectedModelIds, options.state)
|
|
142
|
+
: compiledModels;
|
|
143
|
+
const adapterType = manifest.metadata.adapter_type;
|
|
144
|
+
const { valid: validModels, invalid: failedExplores } = await (0, validation_1.validateDbtModel)(adapterType, manifestVersion, modelsForValidation);
|
|
145
|
+
if (failedExplores.length > 0) {
|
|
146
|
+
const errors = failedExplores.map((failedExplore) => failedExplore.errors.map((error) => `- ${failedExplore.name}: ${error.message}\n`));
|
|
147
|
+
console.error(styles.warning(`Found ${failedExplores.length} errors when validating dbt models:
|
|
148
|
+
${errors.join('')}`));
|
|
149
|
+
}
|
|
150
|
+
// Skipping assumes yml has the field types.
|
|
151
|
+
let catalog = {};
|
|
152
|
+
if (!options.skipWarehouseCatalog) {
|
|
153
|
+
const { warehouseClient } = await (0, getWarehouseClient_1.default)({
|
|
154
|
+
isDbtCloudCLI: dbtVersionResult.success
|
|
155
|
+
? dbtVersionResult.version.isDbtCloudCLI
|
|
156
|
+
: false,
|
|
157
|
+
profilesDir: options.profilesDir,
|
|
158
|
+
profile: options.profile || context.profileName,
|
|
159
|
+
target: options.target,
|
|
160
|
+
startOfWeek: options.startOfWeek,
|
|
161
|
+
});
|
|
162
|
+
globalState_1.default.debug('> Fetching warehouse catalog');
|
|
163
|
+
catalog = await warehouseClient.getCatalog((0, common_1.getSchemaStructureFromDbtModels)(validModels));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
globalState_1.default.debug('> Skipping warehouse catalog');
|
|
167
|
+
}
|
|
168
|
+
const validModelsWithTypes = (0, common_1.attachTypesToModels)(validModels, catalog, false);
|
|
169
|
+
if (!(0, common_1.isSupportedDbtAdapter)(manifest.metadata)) {
|
|
170
|
+
await analytics_1.LightdashAnalytics.track({
|
|
171
|
+
event: 'compile.error',
|
|
172
|
+
properties: {
|
|
173
|
+
executionId,
|
|
174
|
+
dbtVersion: dbtVersionResult.success
|
|
175
|
+
? dbtVersionResult.version.verboseVersion
|
|
176
|
+
: undefined,
|
|
177
|
+
error: `Dbt adapter ${manifest.metadata.adapter_type} is not supported`,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
throw new common_1.ParseError(`Dbt adapter ${manifest.metadata.adapter_type} is not supported`);
|
|
181
|
+
}
|
|
182
|
+
globalState_1.default.debug(`> Converting explores with adapter: ${manifest.metadata.adapter_type}`);
|
|
183
|
+
globalState_1.default.debug(`> Loading Clary project config from ${absoluteProjectPath}`);
|
|
184
|
+
const warehouseSqlBuilder = (0, warehouses_1.warehouseSqlBuilderFromType)(adapterType, options.startOfWeek);
|
|
185
|
+
const validExplores = await (0, common_1.convertExplores)(validModelsWithTypes, false, manifest.metadata.adapter_type, [
|
|
186
|
+
common_1.DbtManifestVersion.V10,
|
|
187
|
+
common_1.DbtManifestVersion.V11,
|
|
188
|
+
common_1.DbtManifestVersion.V12,
|
|
189
|
+
].includes(manifestVersion)
|
|
190
|
+
? []
|
|
191
|
+
: Object.values(manifest.metrics || {}), warehouseSqlBuilder, lightdashProjectConfig, {
|
|
192
|
+
disableTimestampConversion: options.disableTimestampConversion,
|
|
193
|
+
allowPartialCompilation: process.env.PARTIAL_COMPILATION_ENABLED !== 'false',
|
|
194
|
+
postProcessors: [common_1.preAggregatePostProcessor],
|
|
195
|
+
});
|
|
196
|
+
console.error('');
|
|
197
|
+
explores = [...validExplores, ...failedExplores];
|
|
198
|
+
dbtMetrics = manifest.metrics;
|
|
199
|
+
}
|
|
200
|
+
let errors = 0;
|
|
201
|
+
let partialSuccess = 0;
|
|
202
|
+
let success = 0;
|
|
203
|
+
explores.forEach((e) => {
|
|
204
|
+
let status;
|
|
205
|
+
let messages = '';
|
|
206
|
+
if ((0, common_1.isExploreError)(e)) {
|
|
207
|
+
status = styles.error('ERROR');
|
|
208
|
+
messages = `: ${styles.error(e.errors.map((err) => err.message).join(', '))}`;
|
|
209
|
+
errors += 1;
|
|
210
|
+
}
|
|
211
|
+
else if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
|
|
212
|
+
'warnings' in e &&
|
|
213
|
+
e.warnings &&
|
|
214
|
+
e.warnings.length > 0) {
|
|
215
|
+
status = styles.warning('PARTIAL_SUCCESS');
|
|
216
|
+
messages = `: ${styles.warning(e.warnings.map((warning) => warning.message).join(', '))}`;
|
|
217
|
+
partialSuccess += 1;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
status = styles.success('SUCCESS');
|
|
221
|
+
success += 1;
|
|
222
|
+
}
|
|
223
|
+
console.error(`- ${status}> ${e.name} ${messages}`);
|
|
224
|
+
});
|
|
225
|
+
console.error('');
|
|
226
|
+
if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
|
|
227
|
+
partialSuccess > 0) {
|
|
228
|
+
console.error(`Compiled ${explores.length} explores, SUCCESS=${success} PARTIAL_SUCCESS=${partialSuccess} ERRORS=${errors}`);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
console.error(`Compiled ${explores.length} explores, SUCCESS=${success} ERRORS=${errors}`);
|
|
232
|
+
}
|
|
233
|
+
const metricsCount = dbtMetrics === null ? 0 : Object.values(dbtMetrics).length;
|
|
234
|
+
await analytics_1.LightdashAnalytics.track({
|
|
235
|
+
event: 'compile.completed',
|
|
236
|
+
properties: {
|
|
237
|
+
executionId,
|
|
238
|
+
explores: explores.length,
|
|
239
|
+
errors,
|
|
240
|
+
dbtMetrics: metricsCount,
|
|
241
|
+
dbtVersion: dbtVersionResult.success
|
|
242
|
+
? dbtVersionResult.version.verboseVersion
|
|
243
|
+
: undefined,
|
|
244
|
+
durationMs: Date.now() - startTime,
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
return explores;
|
|
248
|
+
};
|
|
249
|
+
exports.compile = compile;
|
|
250
|
+
const compileHandler = async (originalOptions) => {
|
|
251
|
+
const options = { ...originalOptions };
|
|
252
|
+
// Detect project type and configure options accordingly
|
|
253
|
+
const projectTypeConfig = await (0, projectType_1.detectProjectType)({
|
|
254
|
+
projectDir: options.projectDir,
|
|
255
|
+
userOptions: {
|
|
256
|
+
warehouseCredentials: options.warehouseCredentials,
|
|
257
|
+
skipDbtCompile: options.skipDbtCompile,
|
|
258
|
+
skipWarehouseCatalog: options.skipWarehouseCatalog,
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
// Apply project type configuration to options
|
|
262
|
+
options.warehouseCredentials = projectTypeConfig.warehouseCredentials;
|
|
263
|
+
options.skipDbtCompile = projectTypeConfig.skipDbtCompile;
|
|
264
|
+
options.skipWarehouseCatalog = projectTypeConfig.skipWarehouseCatalog;
|
|
265
|
+
globalState_1.default.setVerbose(options.verbose);
|
|
266
|
+
const explores = await (0, exports.compile)(options);
|
|
267
|
+
const errorsCount = explores.filter((e) => (0, common_1.isExploreError)(e)).length;
|
|
268
|
+
console.error('');
|
|
269
|
+
if (errorsCount > 0) {
|
|
270
|
+
console.error(styles.error(`Failed to compile project. Found ${errorsCount} error${errorsCount > 1 ? 's' : ''}`));
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
console.error(styles.success('Successfully compiled project'));
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
exports.compileHandler = compileHandler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.test.d.ts","sourceRoot":"","sources":["../../src/handlers/compile.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
|
|
5
|
+
const os = tslib_1.__importStar(require("os"));
|
|
6
|
+
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
const styles = tslib_1.__importStar(require("../styles"));
|
|
8
|
+
const compile_1 = require("./compile");
|
|
9
|
+
jest.mock('execa');
|
|
10
|
+
jest.mock('../analytics/analytics');
|
|
11
|
+
jest.mock('../config', () => ({
|
|
12
|
+
getConfig: jest.fn().mockResolvedValue({ user: null, context: null }),
|
|
13
|
+
}));
|
|
14
|
+
describe('compile', () => {
|
|
15
|
+
let tempDir;
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
jest.clearAllMocks();
|
|
18
|
+
tempDir = await promises_1.default.mkdtemp(path.join(os.tmpdir(), 'lightdash-compile-test-'));
|
|
19
|
+
// Create minimal lightdash.config.yml
|
|
20
|
+
await promises_1.default.writeFile(path.join(tempDir, 'lightdash.config.yml'), `
|
|
21
|
+
warehouse:
|
|
22
|
+
type: postgres
|
|
23
|
+
`);
|
|
24
|
+
// Create lightdash/models directory and a test model
|
|
25
|
+
const modelsDir = path.join(tempDir, 'lightdash', 'models');
|
|
26
|
+
await promises_1.default.mkdir(modelsDir, { recursive: true });
|
|
27
|
+
await promises_1.default.writeFile(path.join(modelsDir, 'test_model.yml'), `
|
|
28
|
+
version: 1
|
|
29
|
+
type: model
|
|
30
|
+
name: test_model
|
|
31
|
+
description: Test model
|
|
32
|
+
sql_from: "SELECT * FROM test_table"
|
|
33
|
+
dimensions:
|
|
34
|
+
- name: id
|
|
35
|
+
description: ID column
|
|
36
|
+
type: number
|
|
37
|
+
sql: id
|
|
38
|
+
`);
|
|
39
|
+
});
|
|
40
|
+
afterEach(async () => {
|
|
41
|
+
await promises_1.default.rm(tempDir, { recursive: true, force: true });
|
|
42
|
+
});
|
|
43
|
+
test('should compile Lightdash YAML project without dbt installed', async () => {
|
|
44
|
+
// Mock analytics to prevent actual tracking
|
|
45
|
+
const { LightdashAnalytics } = await Promise.resolve().then(() => tslib_1.__importStar(require('../analytics/analytics')));
|
|
46
|
+
LightdashAnalytics.track.mockResolvedValue(undefined);
|
|
47
|
+
const result = await (0, compile_1.compile)({
|
|
48
|
+
projectDir: tempDir,
|
|
49
|
+
profilesDir: '',
|
|
50
|
+
target: undefined,
|
|
51
|
+
profile: undefined,
|
|
52
|
+
vars: undefined,
|
|
53
|
+
verbose: false,
|
|
54
|
+
startOfWeek: 0,
|
|
55
|
+
skipWarehouseCatalog: true,
|
|
56
|
+
skipDbtCompile: true,
|
|
57
|
+
useDbtList: false,
|
|
58
|
+
select: undefined,
|
|
59
|
+
models: undefined,
|
|
60
|
+
threads: undefined,
|
|
61
|
+
noVersionCheck: false,
|
|
62
|
+
exclude: undefined,
|
|
63
|
+
selector: undefined,
|
|
64
|
+
state: undefined,
|
|
65
|
+
fullRefresh: false,
|
|
66
|
+
defer: false,
|
|
67
|
+
targetPath: undefined,
|
|
68
|
+
favorState: false,
|
|
69
|
+
warehouseCredentials: false,
|
|
70
|
+
disableTimestampConversion: false,
|
|
71
|
+
});
|
|
72
|
+
// Should succeed even though dbt is not installed
|
|
73
|
+
expect(result).toBeDefined();
|
|
74
|
+
expect(result.length).toBeGreaterThan(0);
|
|
75
|
+
// Analytics should be called even though dbt is not found
|
|
76
|
+
const trackCalls = LightdashAnalytics.track.mock.calls;
|
|
77
|
+
expect(LightdashAnalytics.track).toHaveBeenCalledWith(expect.objectContaining({
|
|
78
|
+
event: 'compile.started',
|
|
79
|
+
properties: expect.objectContaining({
|
|
80
|
+
dbtVersion: undefined,
|
|
81
|
+
}),
|
|
82
|
+
}));
|
|
83
|
+
expect(LightdashAnalytics.track).toHaveBeenCalledWith(expect.objectContaining({
|
|
84
|
+
event: 'compile.completed',
|
|
85
|
+
}));
|
|
86
|
+
// Verify compile.started was called with undefined dbtVersion
|
|
87
|
+
const startedCall = trackCalls.find((call) => call[0].event === 'compile.started');
|
|
88
|
+
expect(startedCall).toBeDefined();
|
|
89
|
+
expect(startedCall[0].properties.dbtVersion).toBeUndefined();
|
|
90
|
+
});
|
|
91
|
+
test('should display PARTIAL_SUCCESS with warning messages', () => {
|
|
92
|
+
// Mock console.error to capture output
|
|
93
|
+
const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
94
|
+
// Partial compilation is now enabled by default
|
|
95
|
+
const originalEnv = process.env.PARTIAL_COMPILATION_ENABLED;
|
|
96
|
+
// No need to set to 'true' as it's enabled by default
|
|
97
|
+
try {
|
|
98
|
+
// Create mock explores array with different statuses
|
|
99
|
+
const mockExplores = [
|
|
100
|
+
{
|
|
101
|
+
name: 'successful_explore',
|
|
102
|
+
label: 'Successful Explore',
|
|
103
|
+
tags: [],
|
|
104
|
+
baseTable: 'table1',
|
|
105
|
+
// No warnings or errors - should be SUCCESS
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'explore_with_warnings',
|
|
109
|
+
label: 'Explore with Warnings',
|
|
110
|
+
tags: [],
|
|
111
|
+
baseTable: 'table2',
|
|
112
|
+
warnings: [
|
|
113
|
+
{
|
|
114
|
+
type: 'MISSING_TABLE',
|
|
115
|
+
message: 'Join to table "missing_table" was skipped',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
type: 'FIELD_ERROR',
|
|
119
|
+
message: 'Field compilation warning',
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'failed_explore',
|
|
125
|
+
label: 'Failed Explore',
|
|
126
|
+
tags: [],
|
|
127
|
+
errors: [
|
|
128
|
+
{
|
|
129
|
+
type: 'NO_DIMENSIONS_FOUND',
|
|
130
|
+
message: 'No dimensions found in model',
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
// Simulate the explore display logic from compile.ts
|
|
136
|
+
let errors = 0;
|
|
137
|
+
let partialSuccess = 0;
|
|
138
|
+
let success = 0;
|
|
139
|
+
mockExplores.forEach((e) => {
|
|
140
|
+
let status;
|
|
141
|
+
let messages = '';
|
|
142
|
+
if ('errors' in e && e.errors) {
|
|
143
|
+
status = styles.error('ERROR');
|
|
144
|
+
messages = `: ${styles.error(e.errors.map((err) => err.message).join(', '))}`;
|
|
145
|
+
errors += 1;
|
|
146
|
+
}
|
|
147
|
+
else if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
|
|
148
|
+
'warnings' in e &&
|
|
149
|
+
e.warnings &&
|
|
150
|
+
e.warnings.length > 0) {
|
|
151
|
+
status = styles.warning('PARTIAL_SUCCESS');
|
|
152
|
+
messages = `: ${styles.warning(e.warnings
|
|
153
|
+
.map((warning) => warning.message)
|
|
154
|
+
.join(', '))}`;
|
|
155
|
+
partialSuccess += 1;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
status = styles.success('SUCCESS');
|
|
159
|
+
success += 1;
|
|
160
|
+
}
|
|
161
|
+
console.error(`- ${status}> ${e.name} ${messages}`);
|
|
162
|
+
});
|
|
163
|
+
console.error('');
|
|
164
|
+
// Display summary
|
|
165
|
+
if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
|
|
166
|
+
partialSuccess > 0) {
|
|
167
|
+
console.error(`Compiled ${mockExplores.length} explores, SUCCESS=${success} PARTIAL_SUCCESS=${partialSuccess} ERRORS=${errors}`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
console.error(`Compiled ${mockExplores.length} explores, SUCCESS=${success} ERRORS=${errors}`);
|
|
171
|
+
}
|
|
172
|
+
// Verify the output
|
|
173
|
+
const calls = consoleSpy.mock.calls.map((call) => call[0]);
|
|
174
|
+
// Check that PARTIAL_SUCCESS status is displayed
|
|
175
|
+
const partialSuccessCall = calls.find((call) => typeof call === 'string' &&
|
|
176
|
+
call.includes('PARTIAL_SUCCESS> explore_with_warnings'));
|
|
177
|
+
expect(partialSuccessCall).toBeDefined();
|
|
178
|
+
expect(partialSuccessCall).toContain('Join to table "missing_table" was skipped');
|
|
179
|
+
expect(partialSuccessCall).toContain('Field compilation warning');
|
|
180
|
+
// Check that SUCCESS status is displayed
|
|
181
|
+
const successCall = calls.find((call) => typeof call === 'string' &&
|
|
182
|
+
call.includes('SUCCESS> successful_explore'));
|
|
183
|
+
expect(successCall).toBeDefined();
|
|
184
|
+
// Check that ERROR status is displayed
|
|
185
|
+
const errorCall = calls.find((call) => typeof call === 'string' &&
|
|
186
|
+
call.includes('ERROR> failed_explore'));
|
|
187
|
+
expect(errorCall).toBeDefined();
|
|
188
|
+
// Check the summary includes PARTIAL_SUCCESS count
|
|
189
|
+
const summaryCall = calls.find((call) => typeof call === 'string' &&
|
|
190
|
+
call.includes('Compiled') &&
|
|
191
|
+
call.includes('PARTIAL_SUCCESS='));
|
|
192
|
+
expect(summaryCall).toBeDefined();
|
|
193
|
+
expect(summaryCall).toContain('SUCCESS=1 PARTIAL_SUCCESS=1 ERRORS=1');
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
// Clean up
|
|
197
|
+
consoleSpy.mockRestore();
|
|
198
|
+
process.env.PARTIAL_COMPILATION_ENABLED = originalEnv;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|