@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,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runChartHandler = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@lightdash/common");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const yaml = tslib_1.__importStar(require("js-yaml"));
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
10
|
+
const styles = tslib_1.__importStar(require("../styles"));
|
|
11
|
+
const asyncQuery_1 = require("./asyncQuery");
|
|
12
|
+
const apiClient_1 = require("./dbt/apiClient");
|
|
13
|
+
const DEFAULT_PAGE_SIZE = 500;
|
|
14
|
+
const runChartHandler = async (options) => {
|
|
15
|
+
globalState_1.default.setVerbose(options.verbose ?? false);
|
|
16
|
+
// Read and parse YAML
|
|
17
|
+
let fileContent;
|
|
18
|
+
try {
|
|
19
|
+
fileContent = await fs_1.promises.readFile(options.path, 'utf-8');
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new Error(`Cannot read file: ${options.path}`);
|
|
23
|
+
}
|
|
24
|
+
let chart;
|
|
25
|
+
try {
|
|
26
|
+
chart = yaml.load(fileContent);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
throw new Error(`Invalid YAML in ${options.path}`);
|
|
30
|
+
}
|
|
31
|
+
// Validate it's a metric query chart (not SQL)
|
|
32
|
+
const typedChart = chart;
|
|
33
|
+
if ('sql' in typedChart && !('tableName' in typedChart)) {
|
|
34
|
+
throw new Error('SQL charts are not supported. Only metric query charts (with tableName + metricQuery) can be run.');
|
|
35
|
+
}
|
|
36
|
+
if (!typedChart.tableName || !typedChart.metricQuery) {
|
|
37
|
+
throw new Error(`File is not a valid metric query chart. Expected 'tableName' and 'metricQuery' fields.`);
|
|
38
|
+
}
|
|
39
|
+
const chartAsCode = chart;
|
|
40
|
+
// Get project UUID
|
|
41
|
+
const config = await (0, config_1.getConfig)();
|
|
42
|
+
const projectUuid = config.context?.project;
|
|
43
|
+
if (!projectUuid) {
|
|
44
|
+
throw new Error(`No project selected. Run 'clary config set-project' first.`);
|
|
45
|
+
}
|
|
46
|
+
const chartName = chartAsCode.name ?? chartAsCode.slug ?? options.path;
|
|
47
|
+
globalState_1.default.debug(`> Running chart: ${chartName}`);
|
|
48
|
+
globalState_1.default.debug(`> Table: ${chartAsCode.tableName}`);
|
|
49
|
+
globalState_1.default.debug(`> Project: ${projectUuid}`);
|
|
50
|
+
const spinner = globalState_1.default.startSpinner(`Executing query for '${chartName}'...`);
|
|
51
|
+
const { metricQuery } = chartAsCode;
|
|
52
|
+
// Build request body: convert MetricQuery to MetricQueryRequest shape
|
|
53
|
+
const queryBody = {
|
|
54
|
+
exploreName: chartAsCode.tableName,
|
|
55
|
+
dimensions: metricQuery.dimensions,
|
|
56
|
+
metrics: metricQuery.metrics,
|
|
57
|
+
filters: metricQuery.filters,
|
|
58
|
+
sorts: metricQuery.sorts,
|
|
59
|
+
limit: options.limit ?? metricQuery.limit,
|
|
60
|
+
tableCalculations: metricQuery.tableCalculations,
|
|
61
|
+
additionalMetrics: metricQuery.additionalMetrics,
|
|
62
|
+
customDimensions: metricQuery.customDimensions,
|
|
63
|
+
};
|
|
64
|
+
// Submit metric query
|
|
65
|
+
const submitResult = await (0, apiClient_1.lightdashApi)({
|
|
66
|
+
method: 'POST',
|
|
67
|
+
url: `/api/v2/projects/${projectUuid}/query/metric-query`,
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
query: queryBody,
|
|
70
|
+
context: 'cli',
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
globalState_1.default.debug(`> Query UUID: ${submitResult.queryUuid}`);
|
|
74
|
+
spinner.text = 'Waiting for query results...';
|
|
75
|
+
// Poll for completion
|
|
76
|
+
const result = await (0, asyncQuery_1.pollForResults)(projectUuid, submitResult.queryUuid, {
|
|
77
|
+
pageSize: options.output
|
|
78
|
+
? (options.pageSize ?? DEFAULT_PAGE_SIZE)
|
|
79
|
+
: undefined,
|
|
80
|
+
});
|
|
81
|
+
if (result.status === common_1.QueryHistoryStatus.ERROR) {
|
|
82
|
+
spinner.fail(`Query failed for '${chartName}'\n Make sure all semantic layer fields referenced in the metric query (dimensions, metrics, custom dimensions, etc.) are deployed to the Clary project.`);
|
|
83
|
+
throw new Error(result.error ?? 'Query execution failed');
|
|
84
|
+
}
|
|
85
|
+
if (result.status === common_1.QueryHistoryStatus.CANCELLED) {
|
|
86
|
+
spinner.fail(`Query cancelled for '${chartName}'`);
|
|
87
|
+
throw new Error('Query was cancelled');
|
|
88
|
+
}
|
|
89
|
+
if (result.status !== common_1.QueryHistoryStatus.READY) {
|
|
90
|
+
spinner.fail('Unexpected query status');
|
|
91
|
+
throw new Error(`Unexpected query status: ${result.status}`);
|
|
92
|
+
}
|
|
93
|
+
const durationMs = result.initialQueryExecutionMs;
|
|
94
|
+
const durationStr = durationMs ? ` (${durationMs}ms)` : '';
|
|
95
|
+
if (options.output) {
|
|
96
|
+
const columns = Object.keys(result.columns);
|
|
97
|
+
const csv = (0, asyncQuery_1.resultsToCsv)(columns, result.rows);
|
|
98
|
+
await fs_1.promises.writeFile(options.output, csv, 'utf8');
|
|
99
|
+
spinner.succeed(`${styles.success('Success!')} Wrote ${result.rows.length} rows to ${options.output}${durationStr}`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
spinner.succeed(`${styles.success('Success!')} '${chartName}' query succeeded${durationStr}`);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
exports.runChartHandler = runChartHandler;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Config } from '../config';
|
|
2
|
+
export type ProjectSelection = {
|
|
3
|
+
projectUuid: string;
|
|
4
|
+
isPreview: boolean;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Resolves which project to use, prompting the user if there's an active preview.
|
|
8
|
+
*
|
|
9
|
+
* Priority:
|
|
10
|
+
* 1. If `explicitProject` is provided (via --project flag), use it
|
|
11
|
+
* 2. If there's an active preview and we're in interactive mode, ask the user
|
|
12
|
+
* 3. In non-interactive mode with active preview, use preview project
|
|
13
|
+
* 4. Fall back to the main project
|
|
14
|
+
*/
|
|
15
|
+
export declare const selectProject: (config: Config, explicitProject?: string) => Promise<ProjectSelection | undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* Logs which project is being used
|
|
18
|
+
*/
|
|
19
|
+
export declare const logSelectedProject: (selection: ProjectSelection, config: Config, action: string) => void;
|
|
20
|
+
//# sourceMappingURL=selectProject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selectProject.d.ts","sourceRoot":"","sources":["../../src/handlers/selectProject.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAInC,MAAM,MAAM,gBAAgB,GAAG;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GACtB,QAAQ,MAAM,EACd,kBAAkB,MAAM,KACzB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAsEtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC3B,WAAW,gBAAgB,EAC3B,QAAQ,MAAM,EACd,QAAQ,MAAM,KACf,IAcF,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logSelectedProject = exports.selectProject = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
6
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
7
|
+
const styles = tslib_1.__importStar(require("../styles"));
|
|
8
|
+
/**
|
|
9
|
+
* Resolves which project to use, prompting the user if there's an active preview.
|
|
10
|
+
*
|
|
11
|
+
* Priority:
|
|
12
|
+
* 1. If `explicitProject` is provided (via --project flag), use it
|
|
13
|
+
* 2. If there's an active preview and we're in interactive mode, ask the user
|
|
14
|
+
* 3. In non-interactive mode with active preview, use preview project
|
|
15
|
+
* 4. Fall back to the main project
|
|
16
|
+
*/
|
|
17
|
+
const selectProject = async (config, explicitProject) => {
|
|
18
|
+
// If explicit project provided via --project flag, use it
|
|
19
|
+
if (explicitProject) {
|
|
20
|
+
return { projectUuid: explicitProject, isPreview: false };
|
|
21
|
+
}
|
|
22
|
+
const mainProject = config.context?.project;
|
|
23
|
+
const previewProject = config.context?.previewProject;
|
|
24
|
+
const previewName = config.context?.previewName;
|
|
25
|
+
const mainProjectName = config.context?.projectName;
|
|
26
|
+
// No projects configured at all
|
|
27
|
+
if (!mainProject && !previewProject) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
// Only preview project available (edge case, but handle it)
|
|
31
|
+
if (!mainProject && previewProject) {
|
|
32
|
+
return { projectUuid: previewProject, isPreview: true };
|
|
33
|
+
}
|
|
34
|
+
// Only main project available (no active preview)
|
|
35
|
+
if (mainProject && !previewProject) {
|
|
36
|
+
return { projectUuid: mainProject, isPreview: false };
|
|
37
|
+
}
|
|
38
|
+
// Both are available - need to choose
|
|
39
|
+
if (mainProject && previewProject) {
|
|
40
|
+
// In non-interactive mode, default to preview project
|
|
41
|
+
if (globalState_1.default.isNonInteractive()) {
|
|
42
|
+
globalState_1.default.debug('> Non-interactive mode with active preview, using preview project');
|
|
43
|
+
return { projectUuid: previewProject, isPreview: true };
|
|
44
|
+
}
|
|
45
|
+
// Interactive mode - ask the user
|
|
46
|
+
const spinner = globalState_1.default.getActiveSpinner();
|
|
47
|
+
spinner?.stop();
|
|
48
|
+
const previewLabel = previewName
|
|
49
|
+
? `Preview: "${previewName}"`
|
|
50
|
+
: `Preview: ${previewProject}`;
|
|
51
|
+
const mainLabel = mainProjectName
|
|
52
|
+
? `Production: "${mainProjectName}"`
|
|
53
|
+
: `Production: ${mainProject}`;
|
|
54
|
+
const { selectedProject } = await inquirer_1.default.prompt([
|
|
55
|
+
{
|
|
56
|
+
type: 'list',
|
|
57
|
+
name: 'selectedProject',
|
|
58
|
+
message: 'You have an active preview. Which project do you want to use?',
|
|
59
|
+
choices: [
|
|
60
|
+
{ name: previewLabel, value: 'preview' },
|
|
61
|
+
{ name: mainLabel, value: 'production' },
|
|
62
|
+
],
|
|
63
|
+
default: 'preview',
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
spinner?.start();
|
|
67
|
+
if (selectedProject === 'preview') {
|
|
68
|
+
return { projectUuid: previewProject, isPreview: true };
|
|
69
|
+
}
|
|
70
|
+
return { projectUuid: mainProject, isPreview: false };
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
};
|
|
74
|
+
exports.selectProject = selectProject;
|
|
75
|
+
/**
|
|
76
|
+
* Logs which project is being used
|
|
77
|
+
*/
|
|
78
|
+
const logSelectedProject = (selection, config, action) => {
|
|
79
|
+
const { projectUuid, isPreview } = selection;
|
|
80
|
+
const previewName = config.context?.previewName;
|
|
81
|
+
const mainProjectName = config.context?.projectName;
|
|
82
|
+
if (isPreview) {
|
|
83
|
+
const name = previewName ? `"${previewName}"` : projectUuid;
|
|
84
|
+
globalState_1.default.log(`\n${styles.success(`${action} preview project:`)} ${name}\n`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const name = mainProjectName ? `"${mainProjectName}"` : projectUuid;
|
|
88
|
+
globalState_1.default.log(`\n${styles.success(`${action} project:`)} ${name}\n`);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
exports.logSelectedProject = logSelectedProject;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type SetProjectOptions = {
|
|
2
|
+
verbose: boolean;
|
|
3
|
+
name: string;
|
|
4
|
+
uuid: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const setProjectCommand: (name?: string, uuid?: string) => Promise<"selected" | "skipped" | "empty">;
|
|
7
|
+
export declare const setFirstProject: () => Promise<void>;
|
|
8
|
+
export declare const setProjectHandler: (options: SetProjectOptions) => Promise<void>;
|
|
9
|
+
export declare const unsetProjectCommand: () => Promise<void>;
|
|
10
|
+
export declare const unsetProjectHandler: (options: {
|
|
11
|
+
verbose: boolean;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=setProject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setProject.d.ts","sourceRoot":"","sources":["../../src/handlers/setProject.ts"],"names":[],"mappings":"AAQA,KAAK,iBAAiB,GAAG;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC1B,OAAO,MAAM,EACb,OAAO,MAAM,KACd,OAAO,CAAC,UAAU,GAAG,SAAS,GAAG,OAAO,CAmE1C,CAAC;AAEF,eAAO,MAAM,eAAe,qBAmB3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,SAAS,iBAAiB,kBAsBjE,CAAC;AAEF,eAAO,MAAM,mBAAmB,qBAG/B,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAU,SAAS;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,kBAmBtE,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unsetProjectHandler = exports.unsetProjectCommand = exports.setProjectHandler = exports.setFirstProject = exports.setProjectCommand = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
6
|
+
const url_1 = require("url");
|
|
7
|
+
const analytics_1 = require("../analytics/analytics");
|
|
8
|
+
const config_1 = require("../config");
|
|
9
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
10
|
+
const apiClient_1 = require("./dbt/apiClient");
|
|
11
|
+
const setProjectCommand = async (name, uuid) => {
|
|
12
|
+
const projects = await (0, apiClient_1.lightdashApi)({
|
|
13
|
+
method: 'GET',
|
|
14
|
+
url: `/api/v1/org/projects`,
|
|
15
|
+
body: undefined,
|
|
16
|
+
});
|
|
17
|
+
globalState_1.default.debug(`> Set project returned response: ${JSON.stringify(projects)}`);
|
|
18
|
+
if (projects.length === 0)
|
|
19
|
+
return 'empty';
|
|
20
|
+
let selectedProject;
|
|
21
|
+
// --uuid or --name options
|
|
22
|
+
if (uuid !== undefined || name !== undefined) {
|
|
23
|
+
selectedProject = projects.find((project) => project.name === name || project.projectUuid === uuid);
|
|
24
|
+
}
|
|
25
|
+
else if (globalState_1.default.isNonInteractive()) {
|
|
26
|
+
globalState_1.default.debug('> Non-interactive mode: selecting first project');
|
|
27
|
+
[selectedProject] = projects;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const SKIP_VALUE = '__skip__';
|
|
31
|
+
const answers = await inquirer_1.default.prompt([
|
|
32
|
+
{
|
|
33
|
+
type: 'list',
|
|
34
|
+
name: 'project',
|
|
35
|
+
choices: [
|
|
36
|
+
{
|
|
37
|
+
name: "Don't select a project",
|
|
38
|
+
value: SKIP_VALUE,
|
|
39
|
+
},
|
|
40
|
+
...projects.map((project) => ({
|
|
41
|
+
name: project.name,
|
|
42
|
+
value: project.projectUuid,
|
|
43
|
+
})),
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
]);
|
|
47
|
+
if (answers.project === SKIP_VALUE) {
|
|
48
|
+
await (0, config_1.unsetProject)();
|
|
49
|
+
return 'skipped';
|
|
50
|
+
}
|
|
51
|
+
selectedProject = projects.find((project) => project.projectUuid === answers.project);
|
|
52
|
+
}
|
|
53
|
+
if (selectedProject !== undefined) {
|
|
54
|
+
await (0, config_1.setProject)(selectedProject.projectUuid, selectedProject.name);
|
|
55
|
+
const config = await (0, config_1.getConfig)();
|
|
56
|
+
const projectUrl = config.context?.serverUrl &&
|
|
57
|
+
new url_1.URL(`/projects/${selectedProject.projectUuid}/home`, config.context.serverUrl);
|
|
58
|
+
console.error(`\n ✅️ Connected to Clary project: ${projectUrl || ''}\n`);
|
|
59
|
+
return 'selected';
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Project not found.`);
|
|
62
|
+
};
|
|
63
|
+
exports.setProjectCommand = setProjectCommand;
|
|
64
|
+
const setFirstProject = async () => {
|
|
65
|
+
const projects = await (0, apiClient_1.lightdashApi)({
|
|
66
|
+
method: 'GET',
|
|
67
|
+
url: `/api/v1/org/projects`,
|
|
68
|
+
body: undefined,
|
|
69
|
+
});
|
|
70
|
+
const firstProject = projects[0];
|
|
71
|
+
await (0, config_1.setProject)(firstProject.projectUuid, firstProject.name);
|
|
72
|
+
const config = await (0, config_1.getConfig)();
|
|
73
|
+
const projectUrl = config.context?.serverUrl &&
|
|
74
|
+
new url_1.URL(`/projects/${firstProject.name}/home`, config.context.serverUrl);
|
|
75
|
+
console.error(`\n ✅️ Connected to Clary project: ${projectUrl || ''}\n`);
|
|
76
|
+
};
|
|
77
|
+
exports.setFirstProject = setFirstProject;
|
|
78
|
+
const setProjectHandler = async (options) => {
|
|
79
|
+
const startTime = Date.now();
|
|
80
|
+
let success = true;
|
|
81
|
+
globalState_1.default.setVerbose(options.verbose);
|
|
82
|
+
try {
|
|
83
|
+
const result = await (0, exports.setProjectCommand)(options.name, options.uuid);
|
|
84
|
+
if (result === 'skipped') {
|
|
85
|
+
console.error(`\n Project unset.\n`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
success = false;
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await analytics_1.LightdashAnalytics.track({
|
|
94
|
+
event: 'command.executed',
|
|
95
|
+
properties: {
|
|
96
|
+
command: 'set-project',
|
|
97
|
+
durationMs: Date.now() - startTime,
|
|
98
|
+
success,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
exports.setProjectHandler = setProjectHandler;
|
|
104
|
+
const unsetProjectCommand = async () => {
|
|
105
|
+
await (0, config_1.unsetProject)();
|
|
106
|
+
console.error(`\n Project unset.\n`);
|
|
107
|
+
};
|
|
108
|
+
exports.unsetProjectCommand = unsetProjectCommand;
|
|
109
|
+
const unsetProjectHandler = async (options) => {
|
|
110
|
+
const startTime = Date.now();
|
|
111
|
+
let success = true;
|
|
112
|
+
globalState_1.default.setVerbose(options.verbose);
|
|
113
|
+
try {
|
|
114
|
+
await (0, exports.unsetProjectCommand)();
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
success = false;
|
|
118
|
+
throw e;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
await analytics_1.LightdashAnalytics.track({
|
|
122
|
+
event: 'command.executed',
|
|
123
|
+
properties: {
|
|
124
|
+
command: 'unset-project',
|
|
125
|
+
durationMs: Date.now() - startTime,
|
|
126
|
+
success,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
exports.unsetProjectHandler = unsetProjectHandler;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type SetWarehouseHandlerOptions = {
|
|
2
|
+
projectDir: string;
|
|
3
|
+
profilesDir: string;
|
|
4
|
+
target?: string;
|
|
5
|
+
profile?: string;
|
|
6
|
+
targetPath?: string;
|
|
7
|
+
project?: string;
|
|
8
|
+
startOfWeek?: number;
|
|
9
|
+
assumeYes: boolean;
|
|
10
|
+
verbose: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare const setWarehouseHandler: (options: SetWarehouseHandlerOptions) => Promise<void>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=setWarehouse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setWarehouse.d.ts","sourceRoot":"","sources":["../../src/handlers/setWarehouse.ts"],"names":[],"mappings":"AAaA,KAAK,0BAA0B,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AAeF,eAAO,MAAM,mBAAmB,GAC5B,SAAS,0BAA0B,kBAyFtC,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setWarehouseHandler = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@lightdash/common");
|
|
6
|
+
const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
|
|
7
|
+
const config_1 = require("../config");
|
|
8
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
9
|
+
const styles = tslib_1.__importStar(require("../styles"));
|
|
10
|
+
const createProject_1 = require("./createProject");
|
|
11
|
+
const apiClient_1 = require("./dbt/apiClient");
|
|
12
|
+
const refresh_1 = require("./dbt/refresh");
|
|
13
|
+
const resolveProjectUuid = async (projectOption) => {
|
|
14
|
+
if (projectOption) {
|
|
15
|
+
return projectOption;
|
|
16
|
+
}
|
|
17
|
+
const config = await (0, config_1.getConfig)();
|
|
18
|
+
if (!config.context?.project) {
|
|
19
|
+
throw new common_1.AuthorizationError(`No project selected. Run 'clary config set-project' first or pass '--project <uuid>'.`);
|
|
20
|
+
}
|
|
21
|
+
return config.context.project;
|
|
22
|
+
};
|
|
23
|
+
const setWarehouseHandler = async (options) => {
|
|
24
|
+
globalState_1.default.setVerbose(options.verbose);
|
|
25
|
+
await (0, apiClient_1.checkLightdashVersion)();
|
|
26
|
+
const projectUuid = await resolveProjectUuid(options.project);
|
|
27
|
+
// Load credentials from profiles.yml
|
|
28
|
+
const loaded = await (0, createProject_1.loadWarehouseCredentialsFromProfiles)({
|
|
29
|
+
projectDir: options.projectDir,
|
|
30
|
+
profilesDir: options.profilesDir,
|
|
31
|
+
target: options.target,
|
|
32
|
+
profile: options.profile,
|
|
33
|
+
startOfWeek: options.startOfWeek,
|
|
34
|
+
assumeYes: options.assumeYes,
|
|
35
|
+
targetPath: options.targetPath,
|
|
36
|
+
});
|
|
37
|
+
if (!loaded) {
|
|
38
|
+
console.error(styles.warning('User declined to store warehouse credentials. Use --assume-yes to bypass.'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const { credentials } = loaded;
|
|
42
|
+
// Fetch existing project to preserve its settings
|
|
43
|
+
const existingProject = await (0, refresh_1.getProject)(projectUuid);
|
|
44
|
+
// Confirmation prompt
|
|
45
|
+
if (!options.assumeYes && !globalState_1.default.isNonInteractive()) {
|
|
46
|
+
const spinner = globalState_1.default.getActiveSpinner();
|
|
47
|
+
spinner?.stop();
|
|
48
|
+
const answers = await inquirer_1.default.prompt([
|
|
49
|
+
{
|
|
50
|
+
type: 'confirm',
|
|
51
|
+
name: 'isConfirm',
|
|
52
|
+
message: `This will update the warehouse connection on project '${existingProject.name}' to ${credentials.type} and trigger a recompile. Continue?`,
|
|
53
|
+
default: false,
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
if (!answers.isConfirm) {
|
|
57
|
+
console.error(styles.warning('Aborted.'));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
spinner?.start();
|
|
61
|
+
}
|
|
62
|
+
const spinner = globalState_1.default.startSpinner(' Updating warehouse connection...');
|
|
63
|
+
try {
|
|
64
|
+
// Build UpdateProject body — preserve existing fields, override warehouseConnection.
|
|
65
|
+
// Note: dbtConnection from GET response may have stripped secrets, but the backend's
|
|
66
|
+
// mergeMissingProjectConfigSecrets fills them back in from the saved project before persisting.
|
|
67
|
+
const updateBody = {
|
|
68
|
+
name: existingProject.name,
|
|
69
|
+
dbtConnection: existingProject.dbtConnection,
|
|
70
|
+
dbtVersion: existingProject.dbtVersion,
|
|
71
|
+
warehouseConnection: credentials,
|
|
72
|
+
};
|
|
73
|
+
// PATCH project — triggers adaptor test + recompile
|
|
74
|
+
const result = await (0, apiClient_1.lightdashApi)({
|
|
75
|
+
method: 'PATCH',
|
|
76
|
+
url: `/api/v1/projects/${projectUuid}`,
|
|
77
|
+
body: JSON.stringify(updateBody),
|
|
78
|
+
});
|
|
79
|
+
// Poll until job completes (custom spinner prefix)
|
|
80
|
+
await (0, refresh_1.getFinalJobState)(result.jobUuid, 'Updating warehouse connection');
|
|
81
|
+
spinner.stop();
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
spinner.fail();
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
const config = await (0, config_1.getConfig)();
|
|
88
|
+
const displayUrl = `${config.context?.serverUrl}/projects/${projectUuid}/home`;
|
|
89
|
+
console.error(`${styles.bold('Successfully updated warehouse connection:')}`);
|
|
90
|
+
console.error('');
|
|
91
|
+
console.error(` ${styles.bold(`⚡️ ${displayUrl}`)}`);
|
|
92
|
+
console.error('');
|
|
93
|
+
};
|
|
94
|
+
exports.setWarehouseHandler = setWarehouseHandler;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/handlers/sql.ts"],"names":[],"mappings":"AAcA,KAAK,iBAAiB,GAAG;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAKF,eAAO,MAAM,UAAU,GACnB,KAAK,MAAM,EACX,SAAS,iBAAiB,KAC3B,OAAO,CAAC,IAAI,CAqGd,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sqlHandler = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const common_1 = require("@lightdash/common");
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
const analytics_1 = require("../analytics/analytics");
|
|
9
|
+
const config_1 = require("../config");
|
|
10
|
+
const globalState_1 = tslib_1.__importDefault(require("../globalState"));
|
|
11
|
+
const styles = tslib_1.__importStar(require("../styles"));
|
|
12
|
+
const asyncQuery_1 = require("./asyncQuery");
|
|
13
|
+
const apiClient_1 = require("./dbt/apiClient");
|
|
14
|
+
const DEFAULT_PAGE_SIZE = 500;
|
|
15
|
+
const DEFAULT_LIMIT = 50000;
|
|
16
|
+
const sqlHandler = async (sql, options) => {
|
|
17
|
+
globalState_1.default.setVerbose(options.verbose ?? false);
|
|
18
|
+
const executionId = (0, uuid_1.v4)();
|
|
19
|
+
const startTime = Date.now();
|
|
20
|
+
const config = await (0, config_1.getConfig)();
|
|
21
|
+
const projectUuid = config.context?.project;
|
|
22
|
+
if (!projectUuid) {
|
|
23
|
+
throw new Error(`No project selected. Run 'clary config set-project' first.`);
|
|
24
|
+
}
|
|
25
|
+
globalState_1.default.debug(`> Running SQL query against project: ${projectUuid}`);
|
|
26
|
+
globalState_1.default.debug(`> SQL: ${sql}`);
|
|
27
|
+
const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;
|
|
28
|
+
try {
|
|
29
|
+
await analytics_1.LightdashAnalytics.track({
|
|
30
|
+
event: 'sql.started',
|
|
31
|
+
properties: {
|
|
32
|
+
executionId,
|
|
33
|
+
projectId: projectUuid,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const spinner = globalState_1.default.startSpinner('Submitting SQL query...');
|
|
37
|
+
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
38
|
+
const submitResult = await (0, apiClient_1.lightdashApi)({
|
|
39
|
+
method: 'POST',
|
|
40
|
+
url: `/api/v2/projects/${projectUuid}/query/sql`,
|
|
41
|
+
body: JSON.stringify({
|
|
42
|
+
sql,
|
|
43
|
+
limit,
|
|
44
|
+
context: 'cli',
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
globalState_1.default.debug(`> Query UUID: ${submitResult.queryUuid}`);
|
|
48
|
+
spinner.text = 'Waiting for query results...';
|
|
49
|
+
const result = await (0, asyncQuery_1.pollForResults)(projectUuid, submitResult.queryUuid, {
|
|
50
|
+
pageSize,
|
|
51
|
+
});
|
|
52
|
+
if (result.status === common_1.QueryHistoryStatus.ERROR) {
|
|
53
|
+
spinner.fail('Query failed');
|
|
54
|
+
throw new Error(result.error ?? 'Query execution failed');
|
|
55
|
+
}
|
|
56
|
+
if (result.status !== common_1.QueryHistoryStatus.READY) {
|
|
57
|
+
spinner.fail('Unexpected query status');
|
|
58
|
+
throw new Error(`Unexpected query status: ${result.status}`);
|
|
59
|
+
}
|
|
60
|
+
const columns = Object.keys(result.columns);
|
|
61
|
+
const rowCount = result.rows.length;
|
|
62
|
+
spinner.text = `Writing ${rowCount} rows to ${options.output}...`;
|
|
63
|
+
const csv = (0, asyncQuery_1.resultsToCsv)(columns, result.rows);
|
|
64
|
+
await fs_1.promises.writeFile(options.output, csv, 'utf8');
|
|
65
|
+
spinner.succeed(`${styles.success('Success!')} Wrote ${rowCount} rows to ${options.output}`);
|
|
66
|
+
await analytics_1.LightdashAnalytics.track({
|
|
67
|
+
event: 'sql.completed',
|
|
68
|
+
properties: {
|
|
69
|
+
executionId,
|
|
70
|
+
projectId: projectUuid,
|
|
71
|
+
rowCount,
|
|
72
|
+
columnCount: columns.length,
|
|
73
|
+
durationMs: Date.now() - startTime,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
await analytics_1.LightdashAnalytics.track({
|
|
79
|
+
event: 'sql.error',
|
|
80
|
+
properties: {
|
|
81
|
+
executionId,
|
|
82
|
+
error: (0, common_1.getErrorMessage)(e),
|
|
83
|
+
errorCategory: (0, analytics_1.categorizeError)(e),
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
exports.sqlHandler = sqlHandler;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LightdashRequestMethodHeader, RequestMethod } from '@lightdash/common';
|
|
2
|
+
type RequestHeader = {
|
|
3
|
+
'Content-Type': 'application/json';
|
|
4
|
+
'Content-Encoding'?: string;
|
|
5
|
+
Authorization: string;
|
|
6
|
+
'Proxy-Authorization'?: string;
|
|
7
|
+
[LightdashRequestMethodHeader]: RequestMethod;
|
|
8
|
+
};
|
|
9
|
+
export declare function buildRequestHeaders(token: string): RequestHeader;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/handlers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,4BAA4B,EAC5B,aAAa,EAChB,MAAM,mBAAmB,CAAC;AAO3B,KAAK,aAAa,GAAG;IACjB,cAAc,EAAE,kBAAkB,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,CAAC,4BAA4B,CAAC,EAAE,aAAa,CAAC;CACjD,CAAC;AAgBF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,iBAgBhD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildRequestHeaders = buildRequestHeaders;
|
|
4
|
+
const common_1 = require("@lightdash/common");
|
|
5
|
+
var TokenType;
|
|
6
|
+
(function (TokenType) {
|
|
7
|
+
TokenType["ApiKey"] = "ApiKey";
|
|
8
|
+
TokenType["Bearer"] = "Bearer";
|
|
9
|
+
})(TokenType || (TokenType = {}));
|
|
10
|
+
/**
|
|
11
|
+
* We initially used personal access tokens (PATs) for CLI authentication without any prefix.
|
|
12
|
+
* Service account tokens are launching with a prefix, so we'll check them first.
|
|
13
|
+
* We assume a missing prefix is a personal access token, although new PATs will be created with a prefix.
|
|
14
|
+
*
|
|
15
|
+
* See {@link AuthTokenPrefix} for the available token prefixes
|
|
16
|
+
*/
|
|
17
|
+
function getAuthHeader(token) {
|
|
18
|
+
const authType = token?.startsWith(common_1.AuthTokenPrefix.SERVICE_ACCOUNT)
|
|
19
|
+
? TokenType.Bearer
|
|
20
|
+
: TokenType.ApiKey;
|
|
21
|
+
return `${authType} ${token}`;
|
|
22
|
+
}
|
|
23
|
+
function buildRequestHeaders(token) {
|
|
24
|
+
const headers = {
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
Authorization: getAuthHeader(token),
|
|
27
|
+
[common_1.LightdashRequestMethodHeader]: process.env.CI === 'true'
|
|
28
|
+
? common_1.RequestMethod.CLI_CI
|
|
29
|
+
: common_1.RequestMethod.CLI,
|
|
30
|
+
};
|
|
31
|
+
if (process.env.CLARY_PROXY_AUTHORIZATION) {
|
|
32
|
+
headers['Proxy-Authorization'] =
|
|
33
|
+
process.env.CLARY_PROXY_AUTHORIZATION;
|
|
34
|
+
}
|
|
35
|
+
return headers;
|
|
36
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Explore, ExploreError, SchedulerJobStatus, ValidationTarget } from '@lightdash/common';
|
|
2
|
+
import { CompileHandlerOptions } from './compile';
|
|
3
|
+
export declare const requestValidation: (projectUuid: string, explores: (Explore | ExploreError)[], validationTargets: ValidationTarget[]) => Promise<{
|
|
4
|
+
jobId: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare const getJobState: (jobUuid: string) => Promise<{
|
|
7
|
+
status: SchedulerJobStatus;
|
|
8
|
+
details: Record<string, import("@lightdash/common").AnyType> | null;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const getValidation: (projectUuid: string, jobId: string) => Promise<import("@lightdash/common").ValidationResponse[]>;
|
|
11
|
+
export declare function delay(ms: number): Promise<unknown>;
|
|
12
|
+
type ValidateHandlerOptions = CompileHandlerOptions & {
|
|
13
|
+
project?: string;
|
|
14
|
+
verbose: boolean;
|
|
15
|
+
preview: boolean;
|
|
16
|
+
only: ValidationTarget[];
|
|
17
|
+
showChartConfigurationWarnings: boolean;
|
|
18
|
+
};
|
|
19
|
+
export declare const waitUntilFinished: (jobUuid: string) => Promise<string>;
|
|
20
|
+
export declare const validateHandler: (options: ValidateHandlerOptions) => Promise<void>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=validate.d.ts.map
|