@get-dx/cli 0.1.3 → 0.1.4
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/dist/cli.js +1 -1
- package/dist/commandHelpers.js +4 -0
- package/dist/commands/init.js +4 -3
- package/dist/commands/studio/query.js +34 -6
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -45,7 +45,7 @@ function createProgram() {
|
|
|
45
45
|
*/
|
|
46
46
|
function applyExitOverride(cmd) {
|
|
47
47
|
cmd.exitOverride();
|
|
48
|
-
cmd.configureOutput({
|
|
48
|
+
cmd.configureOutput({ outputError: () => { } });
|
|
49
49
|
for (const sub of cmd.commands) {
|
|
50
50
|
applyExitOverride(sub);
|
|
51
51
|
}
|
package/dist/commandHelpers.js
CHANGED
|
@@ -58,6 +58,10 @@ export function handleError(error, command, argv) {
|
|
|
58
58
|
if (error instanceof HttpError) {
|
|
59
59
|
process.stderr.write(`The API returned an error with status code ${error.status}:\n\n${JSON.stringify(error.body, null, 2)}\n`);
|
|
60
60
|
}
|
|
61
|
+
else if (error instanceof CommanderError &&
|
|
62
|
+
(error.code === "commander.help" || error.message === "(outputHelp)")) {
|
|
63
|
+
// Commander already printed the relevant help text.
|
|
64
|
+
}
|
|
61
65
|
else {
|
|
62
66
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
63
67
|
}
|
package/dist/commands/init.js
CHANGED
|
@@ -160,7 +160,7 @@ async function optionallySetupSkill(runtime) {
|
|
|
160
160
|
renderRichText([
|
|
161
161
|
ui.p(`The DX skill is not installed. Would you like to install it?`),
|
|
162
162
|
ui.p("This will run the following command:", false),
|
|
163
|
-
ui.codeBlock("npx --yes -- skills@latest add get-dx/
|
|
163
|
+
ui.codeBlock("npx --yes -- skills@latest add get-dx/cli --global"),
|
|
164
164
|
ui.blankLine(),
|
|
165
165
|
]);
|
|
166
166
|
const setupSkill = await confirm({
|
|
@@ -174,17 +174,18 @@ async function optionallySetupSkill(runtime) {
|
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
176
176
|
renderRichText([ui.p(`Setting up the DX skill...`)]);
|
|
177
|
+
// NOTE: if the user chooses "no" for the final confirmation prompt, `skills` still exits with a 0 status.
|
|
178
|
+
// We are also not able to pipe the output without also breaking interactivity.
|
|
177
179
|
const result = await execa({
|
|
178
180
|
stdout: "inherit",
|
|
179
181
|
stderr: "inherit",
|
|
180
182
|
stdin: "inherit",
|
|
181
|
-
}) `npx --yes -- skills@latest add get-dx/
|
|
183
|
+
}) `npx --yes -- skills@latest add get-dx/cli --global`;
|
|
182
184
|
runtime.logger.debug("To update: npx skills update dx-cli --global");
|
|
183
185
|
runtime.logger.debug("To uninstall: npx skills remove dx-cli --global");
|
|
184
186
|
if (result.exitCode !== 0) {
|
|
185
187
|
throw new CliError(`Failed to setup the DX skill: ${result.stderr}`);
|
|
186
188
|
}
|
|
187
|
-
renderRichText([ui.p(`DX skill setup successful.`)]);
|
|
188
189
|
}
|
|
189
190
|
function createEmptyContext() {
|
|
190
191
|
return {
|
|
@@ -21,6 +21,7 @@ export function queryCommand() {
|
|
|
21
21
|
.description("Execute a Data Studio SQL query and wait for the results")
|
|
22
22
|
.argument("<sql>", "SQL query to execute")
|
|
23
23
|
.option("--output <filename>", "Save the full result set as CSV to a file")
|
|
24
|
+
.option("--variable <key=value>", "Set a template variable referenced in the SQL (can be repeated; use comma-separated values for arrays)", (val, prev) => [...prev, val], [])
|
|
24
25
|
.addHelpText("afterAll", createExampleText([
|
|
25
26
|
{
|
|
26
27
|
label: "Run a query and print the results as a table",
|
|
@@ -28,21 +29,30 @@ export function queryCommand() {
|
|
|
28
29
|
},
|
|
29
30
|
{
|
|
30
31
|
label: "Run a query and print the JSON results payload",
|
|
31
|
-
command: "dx studio query 'SELECT id, name FROM
|
|
32
|
+
command: "dx studio query 'SELECT id, name FROM github_repositories LIMIT 5' --json",
|
|
32
33
|
},
|
|
33
34
|
{
|
|
34
35
|
label: "Run a query and save the full result set as CSV",
|
|
35
36
|
command: "dx studio query 'SELECT * FROM github_pulls' --output pulls.csv",
|
|
36
37
|
},
|
|
38
|
+
{
|
|
39
|
+
label: "Run a parameterized query with a scalar variable",
|
|
40
|
+
command: "dx studio query 'SELECT * FROM github_repositories WHERE name = $name' --variable name=my-repo",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: "Run a parameterized query with an array variable",
|
|
44
|
+
command: "dx studio query 'SELECT * FROM github_repositories WHERE id IN ($repo_ids)' --variable repo_ids=1,2,3",
|
|
45
|
+
},
|
|
37
46
|
]))
|
|
38
47
|
.action(wrapAction(async (sql, options, command) => {
|
|
39
48
|
const context = getContext(command);
|
|
40
49
|
if (context.json && options.output) {
|
|
41
50
|
throw new CliError("--output cannot be used with --json", EXIT_CODES.ARGUMENT_ERROR);
|
|
42
51
|
}
|
|
52
|
+
const variables = parseVariables(options.variable);
|
|
43
53
|
const runtime = buildRuntime(context);
|
|
44
54
|
const progress = new QueryProgressReporter();
|
|
45
|
-
const queryRun = await executeQuery(runtime, progress, sql);
|
|
55
|
+
const queryRun = await executeQuery(runtime, progress, sql, variables);
|
|
46
56
|
await waitForQuery(runtime, progress, queryRun.id);
|
|
47
57
|
if (options.output) {
|
|
48
58
|
await downloadStudioQueryResultsCsv(runtime, queryRun.id, options.output);
|
|
@@ -58,11 +68,11 @@ export function queryCommand() {
|
|
|
58
68
|
}
|
|
59
69
|
}));
|
|
60
70
|
}
|
|
61
|
-
async function executeQuery(runtime, progress, sql) {
|
|
71
|
+
async function executeQuery(runtime, progress, sql, variables) {
|
|
62
72
|
try {
|
|
63
73
|
renderRunningQuery(sql);
|
|
64
74
|
progress.start(ui.bold("Submitting query"));
|
|
65
|
-
const executeResponse = await executeStudioQuery(runtime, sql);
|
|
75
|
+
const executeResponse = await executeStudioQuery(runtime, sql, variables);
|
|
66
76
|
const queryRun = executeResponse.body.query_run;
|
|
67
77
|
await waitForRetryAfter(executeResponse.retryAfterMs);
|
|
68
78
|
return queryRun;
|
|
@@ -115,10 +125,10 @@ function renderRunningQuery(sql) {
|
|
|
115
125
|
function renderPendingQueryStatus(queryRunId) {
|
|
116
126
|
return `${ui.bold("Query running")} ${ui.dim(`(${queryRunId})`)}`;
|
|
117
127
|
}
|
|
118
|
-
async function executeStudioQuery(runtime, sql) {
|
|
128
|
+
async function executeStudioQuery(runtime, sql, variables) {
|
|
119
129
|
return request(runtime, "/studio.queryRuns.execute", {
|
|
120
130
|
method: "POST",
|
|
121
|
-
body: { sql },
|
|
131
|
+
body: variables ? { sql, variables } : { sql },
|
|
122
132
|
});
|
|
123
133
|
}
|
|
124
134
|
async function getStudioQueryRun(runtime, id) {
|
|
@@ -262,6 +272,24 @@ async function writeResponseBodyToFile(response, filename) {
|
|
|
262
272
|
reader.releaseLock();
|
|
263
273
|
}
|
|
264
274
|
}
|
|
275
|
+
function parseVariables(vars) {
|
|
276
|
+
if (vars.length === 0)
|
|
277
|
+
return undefined;
|
|
278
|
+
const result = {};
|
|
279
|
+
for (const v of vars) {
|
|
280
|
+
const eqIdx = v.indexOf("=");
|
|
281
|
+
if (eqIdx === -1) {
|
|
282
|
+
throw new CliError(`Invalid variable format: "${v}". Expected key=value.`, EXIT_CODES.ARGUMENT_ERROR);
|
|
283
|
+
}
|
|
284
|
+
const key = v.slice(0, eqIdx);
|
|
285
|
+
const raw = v.slice(eqIdx + 1);
|
|
286
|
+
const parts = raw.includes(",") ? raw.split(",") : [raw];
|
|
287
|
+
const coerced = parts.map((p) => p !== "" && !isNaN(Number(p)) ? Number(p) : p);
|
|
288
|
+
result[key] =
|
|
289
|
+
coerced.length === 1 ? coerced[0] : coerced;
|
|
290
|
+
}
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
265
293
|
function buildFailedQueryError(error) {
|
|
266
294
|
if (!error) {
|
|
267
295
|
return new CliError("Query failed.", 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@get-dx/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "DX CLI",
|
|
5
5
|
"author": "DX <developers@getdx.com>",
|
|
6
6
|
"bugs": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"homepage": "https://github.com/get-dx/cli#readme",
|
|
17
17
|
"license": "Apache-2.0",
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": "20.
|
|
19
|
+
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
|
|
20
20
|
},
|
|
21
21
|
"private": false,
|
|
22
22
|
"publishConfig": {
|