Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web-console): add materialized views support #405

Merged
merged 26 commits into from
Mar 20, 2025
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
0601da4
feat(web-console): add materialized views support
emrberk Mar 13, 2025
b50f1c4
fix test failures
emrberk Mar 13, 2025
65abd14
add mat views e2e tests
emrberk Mar 13, 2025
7136d48
update submodule
emrberk Mar 13, 2025
7cf7b82
add env variable to context path test
emrberk Mar 13, 2025
4e3d5a3
Update packages/web-console/src/scenes/Schema/Table/index.tsx
emrberk Mar 14, 2025
1b38893
Update packages/web-console/src/scenes/Schema/VirtualTables/index.tsx
emrberk Mar 14, 2025
e862f1b
address review comments
emrberk Mar 14, 2025
641df5f
Update packages/web-console/src/scenes/Schema/Table/index.tsx
emrberk Mar 14, 2025
9104ea6
address reviews round 2
emrberk Mar 14, 2025
012d75d
add warning icon when base table is missing
emrberk Mar 15, 2025
6d17ca8
add ss debug
emrberk Mar 15, 2025
18e8001
disable expanding when there is no data source
emrberk Mar 15, 2025
62363af
latest revision
emrberk Mar 18, 2025
39cd00d
update submodule
emrberk Mar 18, 2025
cf60d3d
simplified view for table listing
emrberk Mar 19, 2025
ce5780a
remove react-contextmenu & introduce new context menu styling
emrberk Mar 19, 2025
636b73b
bring data-hooks back
emrberk Mar 20, 2025
df21284
update submodule
emrberk Mar 20, 2025
15fb26b
fixes for unresponsiveness and ci
emrberk Mar 20, 2025
3b0fb50
update submodule
emrberk Mar 20, 2025
b7dadcb
don't select children text on double click
emrberk Mar 20, 2025
67b3415
remove italic style in column types
emrberk Mar 20, 2025
2d32555
introduce icons for column types
emrberk Mar 20, 2025
304928e
tables expanded by default
emrberk Mar 20, 2025
4ddadfb
update submodule
emrberk Mar 20, 2025
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -65,6 +65,7 @@ jobs:
QDB_DEV_MODE_ENABLED: "true"
QDB_HTTP_USER: "admin"
QDB_HTTP_PASSWORD: "quest"
QDB_CAIRO_MAT_VIEW_ENABLED: "true"

- name: Run browser-tests test
run: yarn workspace browser-tests test
1 change: 1 addition & 0 deletions .github/workflows/tests_with_context_path.yml
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@ jobs:
QDB_DEV_MODE_ENABLED: "true"
QDB_HTTP_USER: "admin"
QDB_HTTP_PASSWORD: "quest"
QDB_CAIRO_MAT_VIEW_ENABLED: "true"

- name: Run browser-tests test
run: yarn workspace browser-tests test
281 changes: 216 additions & 65 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
79 changes: 79 additions & 0 deletions packages/browser-tests/cypress/commands.js
Original file line number Diff line number Diff line change
@@ -30,6 +30,12 @@ const tableSchemas = {
my_secrets2: "CREATE TABLE IF NOT EXISTS 'my_secrets2' (secret STRING);",
};

const materializedViewSchemas = {
btc_trades_mv:
"CREATE MATERIALIZED VIEW IF NOT EXISTS btc_trades_mv WITH BASE btc_trades as (" +
"SELECT timestamp, avg(amount) FROM btc_trades SAMPLE BY 1m) PARTITION BY week;",
};

before(() => {
Cypress.on("uncaught:exception", (err) => {
// this error can be safely ignored
@@ -218,6 +224,19 @@ Cypress.Commands.add("createTable", (name) => {
});
});

Cypress.Commands.add("createMaterializedView", (name) => {
const authHeader = localStorage.getItem("basic.auth.header");
cy.request({
method: "GET",
url: `${baseUrl}/exec?query=${encodeURIComponent(
materializedViewSchemas[name]
)};`,
headers: {
Authorization: authHeader,
},
});
});

Cypress.Commands.add("dropTable", (name) => {
const authHeader = localStorage.getItem("basic.auth.header");
cy.request({
@@ -229,6 +248,32 @@ Cypress.Commands.add("dropTable", (name) => {
});
});

Cypress.Commands.add("dropTableIfExists", (name) => {
const authHeader = localStorage.getItem("basic.auth.header");
cy.request({
method: "GET",
url: `${baseUrl}/exec?query=${encodeURIComponent(
`DROP TABLE IF EXISTS ${name};`
)}`,
headers: {
Authorization: authHeader,
},
});
});

Cypress.Commands.add("dropMaterializedView", (name) => {
const authHeader = localStorage.getItem("basic.auth.header");
cy.request({
method: "GET",
url: `${baseUrl}/exec?query=${encodeURIComponent(
`DROP MATERIALIZED VIEW ${name};`
)}`,
headers: {
Authorization: authHeader,
},
});
});

Cypress.Commands.add("interceptQuery", (query, alias, response) => {
cy.intercept(
{
@@ -289,6 +334,40 @@ Cypress.Commands.add("refreshSchema", () => {
cy.getByDataHook("schema-auto-refresh-button").click();
});

Cypress.Commands.add("expandTables", () => {
cy.get("body").then((body) => {
if (body.find('[data-hook="expand-tables"]').length > 0) {
cy.get('[data-hook="expand-tables"]').click({ force: true });
}
});
});

Cypress.Commands.add("collapseTables", () => {
cy.get("body").then((body) => {
if (body.find('[data-hook="collapse-tables"]').length > 0) {
cy.get('[data-hook="collapse-tables"]').click({ force: true });
}
});
});

Cypress.Commands.add("expandMatViews", () => {
cy.get("body").then((body) => {
if (body.find('[data-hook="expand-materialized-views"]').length > 0) {
cy.get('[data-hook="expand-materialized-views"]').click({ force: true });
}
});
});

Cypress.Commands.add("collapseMatViews", () => {
cy.get("body").then((body) => {
if (body.find('[data-hook="collapse-materialized-views"]').length > 0) {
cy.get('[data-hook="collapse-materialized-views"]').click({
force: true,
});
}
});
});

Cypress.Commands.add("getEditorTabs", () => {
return cy.get(".chrome-tab");
});
Original file line number Diff line number Diff line change
@@ -463,7 +463,8 @@ describe("editor tabs", () => {
cy.getByDataHook("editor-tabs-history-item").should("not.exist");
});

it("should drag tabs", () => {
// TODO: fix the flakiness
it.skip("should drag tabs", () => {
cy.get(".new-tab-button").click();
cy.get(getTabDragHandleByTitle("SQL 1")).drag(
getTabDragHandleByTitle("SQL")
113 changes: 107 additions & 6 deletions packages/browser-tests/cypress/integration/console/schema.spec.js
Original file line number Diff line number Diff line change
@@ -10,21 +10,24 @@ const tables = [
"gitlog",
];

const materializedViews = ["btc_trades_mv"];

describe("questdb schema with working tables", () => {
before(() => {
cy.loadConsoleWithAuth();

tables.forEach((table) => {
cy.createTable(table);
});
cy.expandTables();
cy.refreshSchema();
});
it("should show all the tables when there are no suspended", () => {
tables.forEach((table) => {
cy.getByDataHook("schema-table-title").should("contain", table);
});
cy.getByDataHook("schema-filter-suspended-button").should("not.exist");
cy.getByDataHook("schema-suspension-popover-trigger").should("not.exist");
cy.getByDataHook("schema-row-error-icon").should("not.exist");
});

it("should filter the table with input field", () => {
@@ -75,6 +78,7 @@ describe("questdb schema with suspended tables with Linux OS error codes", () =>
});
beforeEach(() => {
cy.loadConsoleWithAuth();
cy.expandTables();
});

it("should work with 2 suspended tables, btc_trades and ecommerce_stats", () => {
@@ -97,9 +101,11 @@ describe("questdb schema with suspended tables with Linux OS error codes", () =>
cy.getByDataHook("schema-filter-suspended-button").click();
});

it("should show the suspension dialog on click with details for btc_trades", () => {
cy.get('input[name="table_filter"]').click().type("btc_trades");
cy.getByDataHook("schema-suspension-dialog-trigger").click();
it("should show the suspension dialog on context menu click with details for btc_trades", () => {
cy.getByDataHook("schema-table-title").contains("btc_trades").rightclick();
cy.getByDataHook("table-context-menu-resume-wal")
.filter(":visible")
.click();
cy.getByDataHook("schema-suspension-dialog").should(
"have.attr",
"data-table-name",
@@ -117,8 +123,10 @@ describe("questdb schema with suspended tables with Linux OS error codes", () =>
});

it("should resume WAL for btc_trades from the suspension popover", () => {
cy.get('input[name="table_filter"]').click().type("btc_trades");
cy.contains("Suspended").click();
cy.getByDataHook("schema-table-title").contains("btc_trades").rightclick();
cy.getByDataHook("table-context-menu-resume-wal")
.filter(":visible")
.click();
cy.getByDataHook("schema-suspension-dialog-restart-transaction").click();
cy.getByDataHook("schema-suspension-dialog-dismiss").click();
cy.getByDataHook("schema-suspension-dialog").should("not.exist");
@@ -144,6 +152,7 @@ describe("table select UI", () => {
});
beforeEach(() => {
cy.loadConsoleWithAuth();
cy.expandTables();
});

it("should show select ui on click", () => {
@@ -208,3 +217,95 @@ describe("questdb schema in read-only mode", () => {
cy.getByDataHook("create-table-panel").should("not.exist");
});
});

describe("materialized views", () => {
before(() => {
cy.loadConsoleWithAuth();

tables.forEach((table) => {
cy.createTable(table);
});
materializedViews.forEach((mv) => {
cy.createMaterializedView(mv);
});
cy.refreshSchema();
});

afterEach(() => {
cy.collapseTables();
cy.collapseMatViews();
});

it("should create materialized views", () => {
cy.getByDataHook("expand-tables").contains(`Tables (${tables.length})`);
cy.getByDataHook("expand-materialized-views").contains(
`Materialized views (${materializedViews.length})`
);

cy.expandTables();
cy.getByDataHook("schema-table-title").should("contain", "btc_trades");
cy.expandMatViews();
cy.getByDataHook("schema-matview-title").should("contain", "btc_trades_mv");
});

it("should show the base table and copy DDL for a materialized view", () => {
cy.expandMatViews();
cy.getByDataHook("schema-matview-title").contains("btc_trades_mv").click();
cy.getByDataHook("base-table-name").contains("btc_trades").should("exist");
cy.getByDataHook("schema-matview-title")
.contains("btc_trades_mv")
.rightclick();
cy.getByDataHook("table-context-menu-copy-schema")
.filter(":visible")
.click();

if (Cypress.isBrowser("electron")) {
cy.window()
.its("navigator.clipboard")
.invoke("readText")
.should(
"match",
/^CREATE MATERIALIZED VIEW.*'btc_trades_mv' WITH BASE 'btc_trades'/
);
}
});

it("should show a warning icon and tooltip when the view is invalidated", () => {
cy.intercept({
method: "GET",
pathname: "/exec",
query: {
query: "materialized_views()",
},
},
(req) => {
req.continue((res) => {
// [view_name, refresh_type, base_table_name, last_refresh_timestamp, view_sql, view_table_dir_name, invalidation_reason, view_status, base_table_txn, applied_base_table_txn]
res.body.dataset[0][6] = "this is an invalidation reason";
res.body.dataset[0][7] = "invalid";
return res;
});
}
);
cy.refreshSchema();
cy.expandMatViews();
cy.getByDataHook("schema-row-error-icon").trigger("mouseover");

cy.getByDataHook("tooltip").should(
"contain",
"Materialized view is invalid: this is an invalidation reason"
);
});

after(() => {
cy.loadConsoleWithAuth();

materializedViews.forEach((mv) => {
cy.dropMaterializedView(mv);
});

tables.forEach((table) => {
cy.dropTableIfExists(table);
});
});
});
2 changes: 1 addition & 1 deletion packages/browser-tests/questdb
Submodule questdb updated 400 files
4 changes: 2 additions & 2 deletions packages/web-console/package.json
Original file line number Diff line number Diff line change
@@ -29,7 +29,8 @@
"@monaco-editor/react": "^4.6.0",
"@popperjs/core": "2.4.2",
"@questdb/react-components": "workspace:^",
"@questdb/sql-grammar": "1.2.2",
"@questdb/sql-grammar": "1.2.3",
"@radix-ui/react-context-menu": "2.1.5",
"@radix-ui/react-dialog": "^1.0.3",
"@styled-icons/bootstrap": "10.47.0",
"@styled-icons/boxicons-logos": "10.47.0",
@@ -69,7 +70,6 @@
"ramda": "0.27.1",
"react": "17.0.2",
"react-calendar": "^4.0.0",
"react-contextmenu": "2.14.0",
"react-dom": "17.0.2",
"react-highlight-words": "^0.20.0",
"react-hook-form": "7.22.3",
46 changes: 0 additions & 46 deletions packages/web-console/src/components/ContextMenu/ContextMenu.tsx

This file was deleted.

Loading
Oops, something went wrong.