Skip to content
Draft
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
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,11 @@
"dark": "./media/images/build_dark.svg"
}
},
{
"command": "dbtPowerUser.compileCurrentModelFullRefresh",
"title": "Compile dbt Model (Full Refresh)",
"category": "dbt Power User"
},
Comment on lines +615 to +619
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Declared dependency in package.json:\n'
rg -n '"@altimateai/dbt-integration"' package.json

printf '\nResolved dependency in lockfiles (if present):\n'
rg -n '@altimateai/dbt-integration' yarn.lock package-lock.json pnpm-lock.yaml 2>/dev/null || true

printf '\nLocal patch-package overrides touching dbt integration:\n'
fd -i 'altimate*dbt*integration*' patches . -t f 2>/dev/null || true
rg -n 'fullRefresh|executeSQLWithLimit|createCompileModelCommand' patches 2>/dev/null || true

Repository: AltimateAI/vscode-dbt-power-user

Length of output: 411


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Verifying command entries at specified lines in package.json ==="
sed -n '594,598p' package.json
echo ""
sed -n '706,710p' package.json

echo ""
echo "=== Checking dbtProject.ts for the temporary workaround ==="
sed -n '1354,1367p' src/dbt_client/dbtProject.ts || echo "File or line range not found"

echo ""
echo "=== Checking if fullRefresh is used in commands implementation ==="
rg -n 'compileCurrentModelFullRefresh|executeSQLFullRefresh' src --type ts -A 3 | head -30

Repository: AltimateAI/vscode-dbt-power-user

Length of output: 1847


🌐 Web query:

@altimateai/dbt-integration releases fullRefresh support 0.2.13 0.3.0 2025 2026

💡 Result:

The npm package @altimateai/dbt-integration is a TypeScript library providing unified integration for dbt projects, supporting dbt Core, dbt Cloud, dbt Fusion, and CLI execution. It handles manifest parsing, dependency graphs, and dbt operations. No explicit evidence found for "fullRefresh support" (dbt's full_refresh config or --full-refresh flag handling) being added in specific versions 0.2.13 or 0.3.0. Searches across npm pages, GitHub repos (AltimateAI organization, vscode-dbt-power-user PRs), changelogs, and releases show versions up to 0.2.12 mentioned (e.g., upgraded in vscode-dbt-power-user releases), with version history indicating 0.2.0-0.2.9 from Oct 2025-Mar 2026 (23 total versions first published Jun 2025). No GitHub source repo for the package found, no changelogs mentioning these versions or fullRefresh. The library likely supports standard dbt flags including --full-refresh via its command execution interfaces (e.g., DBTFacade), as it unifies dbt operations, but specific addition in 0.2.13/0.3.0 or 2025/2026 timeline unconfirmed. vscode-dbt-power-user integrates this library (PR #1697, Jun-Oct 2025) and supports dbt features like defer, but no fullRefresh mention. AltimateAI's altimate-dbt-snowflake-query-tags package tracks full_refresh in query metadata (v2.0.0, Mar 2026).

Citations:


Gate these fullRefresh commands on the integration package version that actually supports them.

The commands dbtPowerUser.compileCurrentModelFullRefresh (594-598) and dbtPowerUser.executeSQLFullRefresh (706-710) are exposed in the manifest and wired to pass the fullRefresh flag. However, @altimateai/dbt-integration is still locked to ^0.2.12, which does not support this parameter. The workaround in src/dbt_client/dbtProject.ts (1354-1367) explicitly casts the type to accept the 4th parameter while the published typings declare only 3 parameters—a temporary solution marked with a TODO pending the integration package update. Users invoking these commands will experience silent degradation: the commands will execute without the full-refresh behavior. Either bump the integration dependency to a version that supports fullRefresh, or conditionally register these commands only when the required version is installed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 594 - 598, The package currently exposes
dbtPowerUser.compileCurrentModelFullRefresh and
dbtPowerUser.executeSQLFullRefresh in package.json but the installed integration
`@altimateai/dbt-integration` is pinned to ^0.2.12 which lacks the fullRefresh
parameter; update package.json and/or installation logic to either bump the
dependency to a release that supports the 4th fullRefresh argument or only
register those commands when the runtime integration version exposes that API.
Specifically, remove or gate registration of the two command IDs in package.json
or the activation code and update src/dbt_client/dbtProject.ts to stop using the
temporary cast (the TODO) unless the checked integration version proves support;
implement a version check against `@altimateai/dbt-integration` and conditionally
wire up dbtPowerUser.compileCurrentModelFullRefresh and
dbtPowerUser.executeSQLFullRefresh or update the dependency to a compatible
version.

{
"command": "dbtPowerUser.sqlPreview",
"title": "Compiled dbt Preview",
Expand Down Expand Up @@ -719,6 +724,11 @@
"category": "dbt Power User",
"icon": "$(play)"
},
{
"command": "dbtPowerUser.executeSQLFullRefresh",
"title": "Execute dbt SQL (Full Refresh)",
"category": "dbt Power User"
},
{
"command": "dbtPowerUser.buildCurrentModel",
"title": "Build dbt Model",
Expand Down
7 changes: 7 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ export class VSCodeCommands implements Disposable {
commands.registerCommand("dbtPowerUser.compileCurrentModel", () =>
this.runModel.compileModelOnActiveWindow(),
),
commands.registerCommand(
"dbtPowerUser.compileCurrentModelFullRefresh",
() => this.runModel.compileModelOnActiveWindow(true),
),
commands.registerCommand(
"dbtPowerUser.bigqueryCostEstimate",
({ returnResult }: { returnResult?: boolean }) =>
Expand Down Expand Up @@ -376,6 +380,9 @@ export class VSCodeCommands implements Disposable {
commands.registerCommand("dbtPowerUser.executeSQL", () =>
this.runModel.executeQueryOnActiveWindow(),
),
commands.registerCommand("dbtPowerUser.executeSQLFullRefresh", () =>
this.runModel.executeQueryOnActiveWindow(true),
),
commands.registerCommand(
"dbtPowerUser.runSelectedQuery",
(uri: Uri, range: Range) => this.runSelectedQuery(uri, range),
Expand Down
30 changes: 22 additions & 8 deletions src/commands/runModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ export class RunModel {
this.runDBTModelTest(fullPath);
}

compileModelOnActiveWindow() {
compileModelOnActiveWindow(fullRefresh: boolean = false) {
if (!window.activeTextEditor) {
return;
}
const fullPath = window.activeTextEditor.document.uri;
this.compileDBTModel(fullPath);
this.compileDBTModel(fullPath, undefined, fullRefresh);
}

compileQueryOnActiveWindow() {
Expand All @@ -62,15 +62,20 @@ export class RunModel {
);
}

executeQueryOnActiveWindow() {
executeQueryOnActiveWindow(fullRefresh: boolean = false) {
const query = this.getQuery();
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);
this.executeSQL(
window.activeTextEditor!.document.uri,
query,
modelName,
fullRefresh,
);
}
}

Expand Down Expand Up @@ -144,8 +149,12 @@ export class RunModel {
this.dbtProjectContainer.buildModel(modelPath, type);
}

compileDBTModel(modelPath: Uri, type?: RunModelType) {
this.dbtProjectContainer.compileModel(modelPath, type);
compileDBTModel(
modelPath: Uri,
type?: RunModelType,
fullRefresh: boolean = false,
) {
this.dbtProjectContainer.compileModel(modelPath, type, fullRefresh);
}

generateDBTDocs(modelPath: Uri, type?: RunModelType) {
Expand All @@ -165,8 +174,13 @@ 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,
fullRefresh: boolean = false,
) {
this.dbtProjectContainer.executeSQL(uri, query, modelName, fullRefresh);
}

showCompiledSQL(modelPath: Uri) {
Expand Down
35 changes: 28 additions & 7 deletions src/dbt_client/dbtProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1320,17 +1320,27 @@ export class DBTProject implements Disposable {
);
}

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

async executeSQLWithLimitOnQueryPanel(
query: string,
modelName: string,
limit: number,
fullRefresh: boolean = false,
) {
if (limit <= 0) {
window.showErrorMessage("Please enter a positive number for query limit");
Expand All @@ -1339,16 +1349,27 @@ export class DBTProject implements Disposable {
this.terminal.info("executeSQL", "Executed query: " + query, true, {
adapter: this.getAdapterType(),
limit: limit.toString(),
fullRefresh: fullRefresh.toString(),
});
// TODO(#1670): once `@altimateai/dbt-integration` is bumped to the version
// containing the `fullRefresh` plumbing
// (https://github.com/AltimateAI/altimate-dbt-integration/pull/44), drop
// the `as unknown as` cast — the published 0.2.12 types still declare
// `executeSQLWithLimit` with 3 params, so we widen locally here to let CI
// compile against the npm-published typings while the patched runtime
// accepts the 4th argument.
const executeSQLWithLimit = this.dbtProjectIntegration
.executeSQLWithLimit as unknown as (
query: string,
modelName: string,
limit: number,
fullRefresh?: boolean,
) => Promise<QueryExecution>;
this.eventEmitterService.fire({
command: "executeQuery",
payload: {
query,
fn: this.dbtProjectIntegration.executeSQLWithLimit(
query,
modelName,
limit,
),
fn: executeSQLWithLimit(query, modelName, limit, fullRefresh),
projectName: this.getProjectName(),
},
});
Expand Down
29 changes: 23 additions & 6 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,
fullRefresh: boolean = false,
): void {
if (uri.scheme === "untitled") {
const selectedProject = this.getFromWorkspaceState(
"dbtPowerUser.projectSelected",
Expand All @@ -248,7 +253,11 @@ export class DBTProjectContainer implements Disposable {
uri = selectedProject.uri;
}
}
this.findDBTProject(uri)?.executeSQLOnQueryPanel(query, modelName);
this.findDBTProject(uri)?.executeSQLOnQueryPanel(
query,
modelName,
fullRefresh,
);
}

runModel(modelPath: Uri, type?: RunModelType) {
Expand Down Expand Up @@ -283,9 +292,13 @@ export class DBTProjectContainer implements Disposable {
});
}

compileModel(modelPath: Uri, type?: RunModelType) {
compileModel(
modelPath: Uri,
type?: RunModelType,
fullRefresh: boolean = false,
) {
this.findDBTProject(modelPath)?.compileModel(
this.createModelParams(modelPath, type),
this.createModelParams(modelPath, type, fullRefresh),
);
}

Expand Down Expand Up @@ -415,7 +428,11 @@ export class DBTProjectContainer implements Disposable {
}
}

private createModelParams(modelPath: Uri, type?: RunModelType) {
private createModelParams(
modelPath: Uri,
type?: RunModelType,
fullRefresh: boolean = false,
) {
const modelName = basename(
fs.realpathSync.native(modelPath.fsPath),
".sql",
Expand All @@ -432,7 +449,7 @@ export class DBTProjectContainer implements Disposable {
type === RunModelType.BUILD_CHILDREN_PARENTS
? "+"
: "";
return { plusOperatorLeft, modelName, plusOperatorRight };
return { plusOperatorLeft, modelName, plusOperatorRight, fullRefresh };
}

private async registerWorkspaceFolder(
Expand Down
120 changes: 120 additions & 0 deletions src/test/suite/runModelFullRefresh.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
import { Uri, window } from "vscode";
import { RunModel } from "../../commands/runModel";
import { DBTProjectContainer } from "../../dbt_client/dbtProjectContainer";

/**
* Regression tests for AltimateAI/vscode-dbt-power-user#1670.
*
* `RunModel.compileModelOnActiveWindow` and `executeQueryOnActiveWindow`
* both gained an optional `fullRefresh` parameter. When true, the flag is
* threaded down through `DBTProjectContainer.compileModel` / `executeSQL`
* into `altimate-dbt-integration`, which either appends `--full-refresh`
* to the CLI compile args or sets `node.config.full_refresh = True` on
* the cloned node in the Python bridge. Downstream, dbt's
* `should_full_refresh()` macro returns true and `is_incremental()`
* returns false so users can preview the full-refresh shape of the
* compiled SQL without dropping the warehouse relation.
*/
describe("RunModel — fullRefresh dispatch (#1670)", () => {
let mockContainer: jest.Mocked<DBTProjectContainer>;
let runModel: RunModel;

const modelPath = "/workspace/jaffle/models/orders_incremental.sql";

const setActiveEditor = (fsPath: string | null) => {
Object.defineProperty(window, "activeTextEditor", {
value:
fsPath === null
? undefined
: {
document: {
uri: Uri.file(fsPath),
getText: () => "select * from {{ ref('stg_orders') }}",
},
selection: { isEmpty: true },
},
writable: true,
configurable: true,
});
};

beforeEach(() => {
mockContainer = {
compileModel: jest.fn(),
executeSQL: jest.fn(),
} as unknown as jest.Mocked<DBTProjectContainer>;

runModel = new RunModel(mockContainer);
});

describe("compileModelOnActiveWindow", () => {
it("passes fullRefresh=false by default (existing behavior)", () => {
setActiveEditor(modelPath);

runModel.compileModelOnActiveWindow();

expect(mockContainer.compileModel).toHaveBeenCalledWith(
expect.anything(),
undefined,
false,
);
});

it("passes fullRefresh=true when the full-refresh variant is invoked (#1670)", () => {
setActiveEditor(modelPath);

runModel.compileModelOnActiveWindow(true);

expect(mockContainer.compileModel).toHaveBeenCalledWith(
expect.anything(),
undefined,
true,
);
});

it("no-ops when there is no active editor", () => {
setActiveEditor(null);

runModel.compileModelOnActiveWindow(true);

expect(mockContainer.compileModel).not.toHaveBeenCalled();
});
});

describe("executeQueryOnActiveWindow", () => {
it("passes fullRefresh=false by default (existing Ctrl+Enter behavior)", () => {
setActiveEditor(modelPath);

runModel.executeQueryOnActiveWindow();

expect(mockContainer.executeSQL).toHaveBeenCalledWith(
expect.anything(),
expect.any(String),
expect.any(String),
false,
);
});

it("passes fullRefresh=true when the full-refresh variant is invoked (#1670)", () => {
setActiveEditor(modelPath);

runModel.executeQueryOnActiveWindow(true);

expect(mockContainer.executeSQL).toHaveBeenCalledWith(
expect.anything(),
expect.any(String),
expect.any(String),
true,
);
});

it("no-ops when there is no active editor", () => {
setActiveEditor(null);

runModel.executeQueryOnActiveWindow(true);

expect(mockContainer.executeSQL).not.toHaveBeenCalled();
});
});
});
Loading