Skip to content
This repository has been archived by the owner on Dec 1, 2024. It is now read-only.

Commit

Permalink
feat: add view structure
Browse files Browse the repository at this point in the history
  • Loading branch information
ppvan committed May 17, 2024
1 parent 49c8a0e commit d85652d
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 159 deletions.
2 changes: 2 additions & 0 deletions resources/gtk/icons/copy-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 16 additions & 2 deletions resources/gtk/schema-view.blp
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,22 @@ template $PsequelSchemaView: Adw.Bin {
icon-name: "library-symbolic";
title: "Structure";

// child: $PsequelTableGraph {};
child: $PsequelTableStructureView {};
child: Stack {
visible-child-name: bind template.view-mode;
transition-type: slide_left_right;

StackPage {
name: "table";

child: $PsequelTableStructureView {};
}

StackPage {
name: "view";

child: $PsequelViewStructureView {};
}
};
}

Adw.ViewStackPage {
Expand Down
27 changes: 15 additions & 12 deletions resources/gtk/table-cols.blp
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ using Gtk 4.0;
using Adw 1;

template $PsequelTableColumnInfo: Adw.Bin {
ScrolledWindow {
ColumnView view {
model: SingleSelection {
model: bind template.columns;
autoselect: true;
};
ScrolledWindow {
ColumnView view {
model: SingleSelection {
model: bind template.columns;
autoselect: true;
};

styles [
"data-table"
]
styles [
"data-table"
]

show-column-separators: true;
show-row-separators: true;
show-column-separators: true;
show-row-separators: true;
}

vexpand: true;
}

vexpand: true;
}
}
113 changes: 81 additions & 32 deletions resources/gtk/view-structure-view.blp
Original file line number Diff line number Diff line change
@@ -1,36 +1,85 @@
using Gtk 4.0;
using GtkSource 5;

template $PsequelViewStructureView: Box {
orientation: vertical;
spacing: 4;
margin-start: 8;
margin-top: 12;
margin-bottom: 12;
// width-request: 960;
// height-request: 800;
Label {
styles [
"title-3"
]

label: "Column Info";
halign: start;
}

// $PsequelTableColInfo columns {
// columns: bind template.columns;
// }

Label {
styles [
"title-3"
]

label: "Indexes";
halign: start;
}

// $PsequelTableIndexInfo indexes {
// indexes: bind template.indexes;
// }
orientation: vertical;
spacing: 4;
margin-top: 22;
// width-request: 960;
// height-request: 800;
Grid {
hexpand: true;
vexpand: true;
row-homogeneous: true;
column-homogeneous: true;
row-spacing: 24;

$PsequelTableColumnInfo columns {
columns: bind template.columns;

layout {
row: 0;
column: 1;
}
}

Box {
vexpand: true;
spacing: 8;
orientation: vertical;

Box {
halign: fill;
Label {
styles [
"title-3"
]
margin-start: 8;
label: "View definition";
halign: start;
}

Label {
hexpand: true;
}

Button {
icon-name: "copy-symbolic";
halign: end;
tooltip-text: "Copy View Defs";
margin-end: 8;
clicked => $on_copy_clicked();
}
}

ScrolledWindow {
vexpand: true;

GtkSource.View editor {
buffer: GtkSource.Buffer buffer {};

wrap-mode: word;
editable: false;
monospace: true;
auto-indent: true;
show-line-numbers: true;
smart-backspace: true;
smart-home-end: before;
top-margin: 6;
highlight-current-line: true;
insert-spaces-instead-of-tabs: true;
vexpand: true;
}
}

layout {
row: 2;
column: 1;
}
}
}

// $PsequelTableIndexInfo indexes {
// indexes: bind template.indexes;
// }
}
1 change: 1 addition & 0 deletions resources/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ icons = [
'export-symbolic.svg',
'filemanager-app-symbolic.svg',
'application-certificate-symbolic.svg',
'copy-symbolic.svg'
]


Expand Down
4 changes: 2 additions & 2 deletions src/models/Table.vala
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public sealed class Table : BaseTable {
}

public sealed class View : BaseTable {
public List <Column> columns { get; owned set; default = new List <Column> (); }
public List <Index> indexes { get; owned set; default = new List <Index> (); }
public Vec <Column> columns { get; owned set; default = new Vec <Column> (); }
public string defs {get; set; default = "";}

public View(Schema schema) {
Object(schema: schema);
Expand Down
68 changes: 50 additions & 18 deletions src/ui/schema/ViewStructureView.vala
Original file line number Diff line number Diff line change
@@ -1,35 +1,67 @@
using GtkSource;

namespace Psequel {
[GtkTemplate(ui = "/me/ppvan/psequel/gtk/view-structure-view.ui")]
public class ViewStructureView : Gtk.Box {
public ViewStructureViewModel viewstructure_viewmodel { get; set; }

public Gtk.FilterListModel columns { get; set; }
public Gtk.FilterListModel indexes { get; set; }
public Gtk.StringFilter filter { get; set; }
public ViewViewModel view_viewmodel { get; set; }
public ListModel columns { get; private set; }

public ViewStructureView() {
Object();
}

construct {
this.viewstructure_viewmodel = autowire <ViewStructureViewModel> ();
this.view_viewmodel = autowire <ViewViewModel> ();

view_viewmodel.notify["selected-view"].connect(() => {
var obs_list = new ObservableList <Column> ();
obs_list.append_all(view_viewmodel.selected_view.columns.as_list());

var expresion = new Gtk.PropertyExpression(typeof(BaseType), null, "table");
this.filter = new Gtk.StringFilter(expresion);
this.filter.match_mode = Gtk.StringFilterMatchMode.EXACT;
columns = obs_list;
buffer.text = view_viewmodel.selected_view.defs;
});

var app = autowire <Application> ();

columns = new Gtk.FilterListModel(viewstructure_viewmodel.columns, filter);
indexes = new Gtk.FilterListModel(viewstructure_viewmodel.indexes, filter);
filter.search = "";
var lang = LanguageManager.get_default().get_language("sql");
buffer.language = lang;

viewstructure_viewmodel.notify["selected-view"].connect(() => {
var view = viewstructure_viewmodel.selected_view;
filter.search = view.name;
app.style_manager.bind_property("dark", buffer, "style_scheme", BindingFlags.SYNC_CREATE, (binding, from, ref to) => {
var is_dark = from.get_boolean();
if (is_dark)
{
var scheme = StyleSchemeManager.get_default().get_scheme("Adwaita-dark");
to.set_object(scheme);
}
else
{
var scheme = StyleSchemeManager.get_default().get_scheme("Adwaita");
to.set_object(scheme);
}

debug("Notify View: %s", view.name);
debug("Filter: %s", filter.search);
debug("columns: %u", columns.get_n_items());
return(true);
});
}

[GtkCallback]
private void on_copy_clicked() {
clipboard_push(view_viewmodel.selected_view.defs);

var window = get_parrent_window(this);
Adw.Toast toast = new Adw.Toast(view_viewmodel.selected_view.name + " view definitions copied") {
timeout = 1,
};
window.add_toast(toast);
}

private void clipboard_push(string text) {
var primary = Gdk.Display.get_default();
var clipboard = primary.get_clipboard();

clipboard.set_text(text);
}

[GtkChild]
private unowned GtkSource.Buffer buffer;
}
}
90 changes: 4 additions & 86 deletions src/viewmodels/ViewStructureViewModel.vala
Original file line number Diff line number Diff line change
@@ -1,102 +1,20 @@
namespace Psequel {
public class ViewStructureViewModel : Object {
public SQLService sql_service { get; private set; }

public View selected_view { get; set; }

public ObservableList <Column> columns { get; set; default = new ObservableList <Column> (); }
public ObservableList <Index> indexes { get; set; default = new ObservableList <Index> (); }
public ListModel columns { get; set; }

public ViewStructureViewModel(SQLService sql_service) {
base();
this.sql_service = sql_service;

EventBus.instance().selected_view_changed.connect((view) => {
selected_view = view;
});
var obs_list = new ObservableList<Column> ();
obs_list.append_all (view.columns.as_list ());

EventBus.instance().schema_changed.connect((schema) => {
load_data.begin(schema);
columns = obs_list;
});
}

private async void load_data(Schema schema) {
columns.clear();
indexes.clear();

columns.append_all(yield _get_columns(schema));
indexes.append_all(yield _get_indexes(schema));

debug("cols: %d indx: %d", columns.size, indexes.size);
}

private async List <Column> _get_columns(Schema schema) {
var list = new List <Column> ();

try {
var query = new Query.with_params(COLUMN_SQL, { schema.name });
var relation = yield sql_service.exec_query_params(query);

foreach (var row in relation)
{
var col = new Column();
col.schemaname = schema.name;
col.name = row[0];
col.table = row[1];
col.column_type = row[2];
col.nullable = row[3] == "YES" ? true : false;
col.default_val = row[4];

list.append(col);
}
} catch (PsequelError err) {
debug(err.message);
}

return(list);
}

private async List <Index> _get_indexes(Schema schema) {
var list = new List <Index> ();

try {
var query = new Query.with_params(INDEX_SQL, { schema.name });
var relation = yield sql_service.exec_query_params(query);

foreach (var row in relation)
{
var index = new Index();
index.schemaname = schema.name;
index.name = row[0];
index.table = row[1];
index.size = row[2];
index.indexdef = row[3];

list.append(index);
}
} catch (PsequelError err) {
debug(err.message);
}

return(list);
}

public const string COLUMN_SQL = """
SELECT column_name, table_name,
case
when domain_name is not null then domain_name
when data_type='character varying' THEN 'varchar('||character_maximum_length||')'
when data_type='numeric' THEN 'numeric('||numeric_precision||','||numeric_scale||')'
else data_type
end as data_type,
is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = $1;
""";
public const string INDEX_SQL = """
SELECT indexname, tablename, pg_size_pretty(pg_relation_size(indexname::regclass)) as size, indexdef
FROM pg_indexes
WHERE schemaname = $1;
""";
}
}
Loading

0 comments on commit d85652d

Please sign in to comment.