Skip to content

Commit

Permalink
feat: add table data tab
Browse files Browse the repository at this point in the history
  • Loading branch information
invm committed Jan 8, 2024
1 parent 6631c57 commit 1d7d070
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 74 deletions.
1 change: 1 addition & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ services:
POSTGRES_DB: dvdrental # https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/
volumes:
- psql:/var/lib/postgresql/data
# - ./db.tar:/tmp/db.tar // pg_restore -U postgres -d dvdrental -1 /tmp/db.tar
ports:
- 5432:5432
3 changes: 0 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,15 @@
"ag-grid-community": "^31.0.1",
"ag-grid-solid": "^31.0.1",
"codemirror": "^6.0.1",
"fuse.js": "^6.6.2",
"i18next": "^23.1.0",
"solid-codemirror": "^2.3.0",
"solid-contextmenu": "^0.0.2",
"solid-form-handler": "^1.2.0",
"solid-js": "^1.7.7",
"solid-transition-group": "^0.2.2",
"split.js": "^1.6.5",
"sql-formatter": "^12.2.3",
"tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store#v1",
"tauri-plugin-window-state-api": "github:tauri-apps/tauri-plugin-window-state#v1",
"tinykeys": "^2.1.0",
"zod": "^3.21.4"
},
"devDependencies": {
Expand Down
57 changes: 6 additions & 51 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 23 additions & 1 deletion src-tauri/src/database/engine/postgresql/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::Result;
use deadpool_postgres::{GenericClient, Pool};
use futures::{pin_mut, TryStreamExt};
use serde_json::Value;
use tracing::debug;

use crate::{
database::connections::{PreparedStatement, ResultSet, TableMetadata},
Expand Down Expand Up @@ -51,7 +52,28 @@ pub async fn execute_tx(pool: &Pool, queries: Vec<PreparedStatement>) -> Result<
let mut conn = pool.get().await?;
let tx = conn.transaction().await?;
for q in queries {
match tx.execute_raw(&q.statement, &q.params).await {
debug!(?q.statement, ?q.params, "Executing query");
// replace each occurence of ? in string with $1, $2, $3, etc.
let mut i = 0;
let query = q
.statement
.clone()
.split("")
.enumerate()
.map(|(_, c)| {
if c == "?" {
i += 1;
format!("${}", i)
} else {
c.to_string()
}
})
.collect::<Vec<String>>()
.join("");

debug!(?query, "Executing query");

match tx.execute_raw(&query, &q.params).await {
Ok(..) => {}
Err(e) => {
tx.rollback().await?;
Expand Down
8 changes: 5 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,30 @@ function App() {
messages: { notify },
} = useAppSelector();

createShortcut(['Meta', 'w'], () => {
createShortcut(['Control', 'w'], () => {
removeContentTab(contentStore.idx);
});

createShortcut(['F1'], () => {
setComponent((s) => (s === 1 ? 0 : 1));
});

createShortcut(['Meta', 't'], () => {
createShortcut(['Control', 't'], () => {
addContentTab();
});

createShortcut(['Control', 'Tab'], () => {
console.log('createShortcut');
setNextContentIdx();
});

createShortcut(['Control', 'Shift', 'Tab'], () => {
console.log('createShortcut');
setPrevContentIdx();
});

for (let i = 1; i <= 9; i++) {
createShortcut(['Meta', String(i)], () => {
createShortcut(['Control', String(i)], () => {
setContentIdx(i - 1);
});
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/Screens/Console/Content/DataTab/DataTab.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { useAppSelector } from 'services/Context';
import { Results } from '../QueryTab/Results';

const DataTab = () => {
return <Results editable={true} />;
const {
connections: { getContentData },
} = useAppSelector();
return <Results editable={true} table={getContentData('Data').table} />;
};

export { DataTab };
4 changes: 2 additions & 2 deletions src/components/Screens/Console/Content/QueryTab/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@ export const Editor = () => {
setSchema(_schema);
}, connectionStore.idx);

createShortcut(['Meta', 'k'], () => {
createShortcut(['Control', 'k'], () => {
if (focused() && vimModeOn()) {
const fn = moveCompletionSelection(false);
fn(editorView());
}
});

createShortcut(['Meta', 'j'], () => {
createShortcut(['Control', 'j'], () => {
if (focused() && vimModeOn()) {
const fn = moveCompletionSelection(true);
fn(editorView());
Expand Down
46 changes: 37 additions & 9 deletions src/components/Screens/Console/Content/QueryTab/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import AgGridSolid, { AgGridSolidRef } from 'ag-grid-solid';
import { useContextMenu, Menu, animation, Item } from 'solid-contextmenu';

import { useAppSelector } from 'services/Context';
import { Row } from 'interfaces';
import { QueryTaskEnqueueResult, Row } from 'interfaces';
import { ContentTabData } from 'services/Connections';
import { Pagination } from './components/Pagination';
import { NoResults } from './components/NoResults';
Expand Down Expand Up @@ -37,15 +37,29 @@ const getColumnDefs = (rows: Row[], columns: Row[], constraints: Row[]): ColDef[
return true;
}
}) ?? {};
const visible_type = getAnyCase(col, 'COLUMN_TYPE');
// const type = visible_type?.split('(')[0];
// let gridType = 'text';
// if (type.includes('int') || type === 'decimal' || type === 'float' || type === 'double') {
// gridType = 'number';
// } else if (type === 'date' || type === 'datetime' || type === 'timestamp') {
// gridType = 'dateString';
// } else if (type === 'tinyint' || type === 'boolean') {
// gridType = 'boolean';
// } else if (type === 'json' || type === 'jsonb') {
// gridType = 'object';
// }

return {
editable: !key,
// editable: !key,
// checkboxSelection: _i === 0,
filter: true,
// type: gridType,
headerComponent: () => (
<div class="flex items-center justify-between w-full">
<div>
<span class="mr-2 text-sm">{field}</span>
<span class="text-xs text-base-content">{getAnyCase(col, 'COLUMN_TYPE')}</span>
<span class="text-xs text-base-content">{visible_type}</span>
</div>
<Show when={key}>
<Key />
Expand All @@ -64,14 +78,14 @@ type Changes = {
updateKey: string;
updateVal: string;
changes: {
[key: string]: string | number | boolean;
[key: string]: string;
};
};
};

export const Results = (props: { editable: boolean }) => {
export const Results = (props: { editable?: boolean; table?: string }) => {
const {
connections: { queryIdx, contentStore, getConnection },
connections: { queryIdx, contentStore, getConnection, updateContentTab },
backend: { getQueryResults, pageSize, downloadCsv },
messages: { notify },
} = useAppSelector();
Expand Down Expand Up @@ -170,8 +184,9 @@ export const Results = (props: { editable: boolean }) => {
let statement = `UPDATE ${table()} SET `;
const row = allChanges[rowIndex];
const params = Object.values(row.changes)
.reduce((acc, val) => [...acc, val], [] as (string | number | boolean)[])
.concat(row.updateVal);
.reduce((acc, val) => [...acc, val], [] as string[])
.concat(row.updateVal)
.map(String);
const _changes = Object.keys(row.changes).map((key) => key + ' = ?');
statement += _changes.join(', ') + ` WHERE ${row.updateKey} = ?`;
return { statement, params };
Expand All @@ -180,7 +195,20 @@ export const Results = (props: { editable: boolean }) => {
await invoke('execute_tx', { queries, connId: conn.id });
setChanges({});
await invoke('invalidate_query', { path: data()?.path });
// TODO: refresh query
const query = 'SELECT * from ' + props.table!;
const { result_sets } = await invoke<QueryTaskEnqueueResult>('enqueue_query', {
connId: conn.id,
sql: query,
autoLimit: true,
tabIdx: contentStore.idx,
table: {
table,
with_constraints: true,
},
});
updateContentTab('data', {
result_sets: result_sets.map((id) => ({ id })),
});
} catch (error) {
notify(error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const TableColumnsCollapse = (props: { entity: 'views' | 'tables'; title:
try {
const activeConnection = getConnection();
const query = 'SELECT * from ' + table;
const data = { result_sets: [] };
const data = { result_sets: [], table };
addContentTab(newContentTab(table, 'Data', data));
const { result_sets } = await invoke<QueryTaskEnqueueResult>('enqueue_query', {
connId: activeConnection.id,
Expand Down
6 changes: 3 additions & 3 deletions src/components/UI/Keymaps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { For } from 'solid-js';
const keymaps = [
{ action: 'Help', keys: ['F1'] },
{ action: 'Execute query', keys: ['Ctrl', 'e'] },
{ action: 'Select tab', keys: ['Meta', 'number'] },
{ action: 'New tab', keys: ['Meta', 't'] },
{ action: 'Close current tab', keys: ['Meta', 'w'] },
{ action: 'Select tab', keys: ['Ctrl', 'number'] },
{ action: 'New tab', keys: ['Ctrl', 't'] },
{ action: 'Close current tab', keys: ['Ctrl', 'w'] },
{ action: 'Focus on editor', keys: ['Ctrl', 'l'] },
{ action: 'Format query', keys: ['Ctrl', 'Shift', 'f'] },
{ action: 'Select next/previous result', keys: ['Ctrl', 'Shift', 'n/p'] },
Expand Down
1 change: 1 addition & 0 deletions src/services/Connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export type TableStructureContentTabData = {

export type DataContentTabData = {
result_sets: ResultSet[];
table: string;
};

export type ContentTabType = {
Expand Down

0 comments on commit 1d7d070

Please sign in to comment.