Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,12 @@
"category": "dbt Power User",
"icon": "$(play)"
},
{
"command": "dbtPowerUser.executeModel",
"title": "Execute dbt Model",
"category": "dbt Power User",
"icon": "$(play-circle)"
},
{
"command": "dbtPowerUser.buildCurrentModel",
"title": "Build dbt Model",
Expand Down Expand Up @@ -837,6 +843,12 @@
"command": "dbtPowerUser.executeSQL",
"when": "editorFocus && resourceLangId =~ /^sql$|^jinja-sql$/"
},
{
"key": "Ctrl+Shift+Enter",
"mac": "Cmd+Shift+Enter",
"command": "dbtPowerUser.executeModel",
"when": "editorFocus && resourceLangId =~ /^sql$|^jinja-sql$/"
},
{
"key": "Ctrl+'",
"mac": "Cmd+'",
Expand Down Expand Up @@ -954,6 +966,11 @@
"when": "resourceLangId =~ /^sql$|^jinja-sql$/",
"group": "navigation@1"
},
{
"command": "dbtPowerUser.executeModel",
"when": "resourceLangId =~ /^sql$|^jinja-sql$/",
"group": "navigation@2"
},
{
"command": "dbtPowerUser.runCurrentModel",
"when": "resourceLangId =~ /^sql$|^jinja-sql$/",
Expand Down
3 changes: 3 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ export class VSCodeCommands implements Disposable {
commands.registerCommand("dbtPowerUser.executeSQL", () =>
this.runModel.executeQueryOnActiveWindow(),
),
commands.registerCommand("dbtPowerUser.executeModel", () =>
this.runModel.executeModelOnActiveWindow(),
),
commands.registerCommand(
"dbtPowerUser.runSelectedQuery",
(uri: Uri, range: Range) => this.runSelectedQuery(uri, range),
Expand Down
52 changes: 46 additions & 6 deletions src/commands/runModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,42 @@ export class RunModel {
if (query === undefined) {
return;
}
const modelPath = window.activeTextEditor?.document.uri;
if (modelPath) {
const modelName = path.basename(modelPath.fsPath, ".sql");
this.executeSQL(window.activeTextEditor!.document.uri, query, modelName);
const editor = window.activeTextEditor;
if (!editor) {
return;
}
const modelPath = editor.document.uri;
const modelName = path.basename(modelPath.fsPath, ".sql");
// Only a saved, unedited, whole-file preview could have been run as the
// real model node instead. With a selection or unsaved edits, the editor
// contents are the point, so suggesting Execute dbt Model would be wrong.
const couldRunAsModel =
modelPath.scheme !== "untitled" &&
!editor.document.isDirty &&
editor.selection.isEmpty;
this.executeSQL(modelPath, query, modelName, couldRunAsModel);
}

async executeModelOnActiveWindow() {
const editor = window.activeTextEditor;
if (!editor) {
return;
}
const uri = editor.document.uri;
if (uri.scheme === "untitled") {
window.showErrorMessage(
"Execute Model requires a saved dbt model file. Save the file first, or use Execute Query (Cmd+Enter) for ad-hoc SQL.",
);
return;
}
const modelName = path.basename(uri.fsPath, ".sql");
if (!modelName) {
window.showErrorMessage(
"Execute Model requires a saved dbt model file with a valid name.",
);
return;
}
this.executeModel(uri, modelName);
}

runModelOnNodeTreeItem(type: RunModelType) {
Expand Down Expand Up @@ -165,8 +196,17 @@ export class RunModel {
this.dbtProjectContainer.runModelTest(modelPath, modelName);
}

async executeSQL(uri: Uri, query: string, modelName: string) {
this.dbtProjectContainer.executeSQL(uri, query, modelName);
async executeSQL(
uri: Uri,
query: string,
modelName: string,
couldRunAsModel = false,
) {
this.dbtProjectContainer.executeSQL(uri, query, modelName, couldRunAsModel);
}

async executeModel(uri: Uri, modelName: string) {
this.dbtProjectContainer.executeModel(uri, modelName);
}

showCompiledSQL(modelPath: Uri) {
Expand Down
132 changes: 125 additions & 7 deletions src/dbt_client/dbtProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
DeferConfig,
extractOutputColumns,
HealthcheckArgs,
isInlinePreviewCompilationError,

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 20)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 22)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 22)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 20)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 24)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 24)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 20)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 24)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.

Check failure on line 23 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 22)

Module '"@altimateai/dbt-integration"' has no exported member 'isInlinePreviewCompilationError'.
isResourceHasDbColumns,
isResourceNode,
MANIFEST_FILE,
NoCredentialsError,
NodeMetaData,
NotImplementedError,

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 20)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 22)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 22)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 20)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 24)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 24)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 20)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 24)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.

Check failure on line 29 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 22)

Module '"@altimateai/dbt-integration"' has no exported member 'NotImplementedError'.
ParsedManifest,
ProjectHealthcheck,
QueryExecution,
Expand Down Expand Up @@ -89,6 +91,15 @@
[key: string]: string | number | undefined;
}

/**
* Appended to an inline preview's compile error. Names the command rather than
* its keybinding: the chord differs per platform and users can rebind it.
*/
const MODEL_PREVIEW_HINT =
"Hint: Execute SQL previews the editor contents as an anonymous query, so " +
"model.name, this, and model.config do not resolve to this model. " +
'To run it as the real model, use the "Execute dbt Model" command.';

export class DBTProject implements Disposable {
private _manifestCacheEvent?: ManifestCacheProjectAddedEvent;
readonly projectRoot: Uri;
Expand Down Expand Up @@ -1347,17 +1358,27 @@
);
}

async executeSQLOnQueryPanel(query: string, modelName: string) {
async executeSQLOnQueryPanel(
query: string,
modelName: string,
couldRunAsModel = false,
) {
const limit = workspace
.getConfiguration("dbt")
.get<number>("queryLimit", 500);
return this.executeSQLWithLimitOnQueryPanel(query, modelName, limit);
return this.executeSQLWithLimitOnQueryPanel(
query,
modelName,
limit,
couldRunAsModel,
);
}

async executeSQLWithLimitOnQueryPanel(
query: string,
modelName: string,
limit: number,
couldRunAsModel = false,
) {
if (limit <= 0) {
window.showErrorMessage("Please enter a positive number for query limit");
Expand All @@ -1367,15 +1388,112 @@
adapter: this.getAdapterType(),
limit: limit.toString(),
});
const execution = this.dbtProjectIntegration.executeSQLWithLimit(
query,
modelName,
limit,
);
this.eventEmitterService.fire({
command: "executeQuery",
payload: {
query,
fn: this.dbtProjectIntegration.executeSQLWithLimit(
query,
modelName,
limit,
),
fn: this.canOfferModelPreview(modelName, couldRunAsModel)
? this.withModelPreviewHint(execution)
: execution,
projectName: this.getProjectName(),
},
});
}

/**
* Whether suggesting "Execute dbt Model" would actually help if this preview
* fails to compile. Requires a real node to select, and an integration that
* implements the command — Python-bridge mode throws NotImplementedError.
*/
private canOfferModelPreview(
modelName: string,
couldRunAsModel: boolean,
): boolean {
if (!couldRunAsModel) {
return false;
}
const integration = workspace
.getConfiguration("dbt")
.get<string>("dbtIntegration", "core");
if (integration === "core") {
return false;
}
return (
this._manifestCacheEvent?.nodeMetaMap.lookupByBaseName(modelName) !==
undefined
);
}

/**
* Inline previews compile the editor contents as an anonymous node, so Jinja
* reading the current node's identity resolves to a placeholder rather than
* this model. When that is what failed, point the user at the command that
* previews the file as its real node.
*/
private async withModelPreviewHint(
execution: Promise<QueryExecution>,
): Promise<QueryExecution> {
const queryExecution = await execution;
return new QueryExecution(
() => queryExecution.cancel(),
async () => {
try {
return await queryExecution.executeQuery();
} catch (error) {
if (!isInlinePreviewCompilationError(error)) {
throw error;
}
throw new Error(
`${(error as Error).message}\n\n${MODEL_PREVIEW_HINT}`,
);
}
},
);
}

async executeModelOnQueryPanel(modelName: string) {
const limit = workspace
.getConfiguration("dbt")
.get<number>("queryLimit", 500);
return this.executeModelWithLimitOnQueryPanel(modelName, limit);
}

async executeModelWithLimitOnQueryPanel(modelName: string, limit: number) {
if (limit <= 0) {
window.showErrorMessage("Please enter a positive number for query limit");
return;
}
this.terminal.info(
"executeModel",
`Executed model: ${modelName} (limit ${limit})`,
true,
{ adapter: this.getAdapterType(), limit: limit.toString() },
);
let queryExecution: QueryExecution;
try {
queryExecution = await this.dbtProjectIntegration.executeModelWithLimit(

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 20)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 22)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 22)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 20)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 24)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (macos-latest, 24)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 20)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 24)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?

Check failure on line 1479 in src/dbt_client/dbtProject.ts

View workflow job for this annotation

GitHub Actions / test (windows-latest, 22)

Property 'executeModelWithLimit' does not exist on type 'DBTProjectIntegrationAdapter'. Did you mean 'executeSQLWithLimit'?
modelName,
limit,
);
} catch (err) {
if (err instanceof NotImplementedError) {
window.showErrorMessage(
"Execute Model isn't available in Python-bridge mode. Switch `dbt.dbtIntegration` to `corecommand`, `cloud`, or `fusion` in settings.",
);
return;
}
throw err;
}
this.eventEmitterService.fire({
command: "executeQuery",
payload: {
query: `-- dbt show --select ${modelName} --limit ${limit}`,
fn: Promise.resolve(queryExecution),
projectName: this.getProjectName(),
},
});
Expand Down
24 changes: 22 additions & 2 deletions src/dbt_client/dbtProjectContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,12 @@ export class DBTProjectContainer implements Disposable {
this.getProjects().forEach((project) => project.initialize());
}

executeSQL(uri: Uri, query: string, modelName: string): void {
executeSQL(
uri: Uri,
query: string,
modelName: string,
couldRunAsModel = false,
): void {
if (uri.scheme === "untitled") {
const selectedProject = this.getFromWorkspaceState(
"dbtPowerUser.projectSelected",
Expand All @@ -248,7 +253,22 @@ export class DBTProjectContainer implements Disposable {
uri = selectedProject.uri;
}
}
this.findDBTProject(uri)?.executeSQLOnQueryPanel(query, modelName);
this.findDBTProject(uri)?.executeSQLOnQueryPanel(
query,
modelName,
couldRunAsModel,
);
}

executeModel(uri: Uri, modelName: string): void {
const project = this.findDBTProject(uri);
if (!project) {
window.showErrorMessage(
`No dbt project found for ${uri.fsPath}. Execute Model requires a file inside a dbt project.`,
);
return;
}
void project.executeModelOnQueryPanel(modelName);
}

runModel(modelPath: Uri, type?: RunModelType) {
Expand Down
2 changes: 2 additions & 0 deletions src/test/suite/dbtProjectContainer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ describe("DBTProjectContainer Tests", () => {
expect(mockDbtProject.executeSQLOnQueryPanel).toHaveBeenCalledWith(
query,
modelName,
false,
);
});

Expand Down Expand Up @@ -806,6 +807,7 @@ describe("DBTProjectContainer Tests", () => {
expect(mockDbtProject.executeSQLOnQueryPanel).toHaveBeenCalledWith(
query,
modelName,
false,
);
});

Expand Down
Loading
Loading