diff --git a/pgLabII.Desktop/pgLabII.Desktop.csproj b/pgLabII.Desktop/pgLabII.Desktop.csproj
index 9002229..e989c75 100644
--- a/pgLabII.Desktop/pgLabII.Desktop.csproj
+++ b/pgLabII.Desktop/pgLabII.Desktop.csproj
@@ -20,6 +20,7 @@
NoneAll
+
diff --git a/pgLabII/QueryToolPlan.md b/pgLabII/QueryToolPlan.md
new file mode 100644
index 0000000..e94d51c
--- /dev/null
+++ b/pgLabII/QueryToolPlan.md
@@ -0,0 +1,108 @@
+# Features
+
+- Is a part of the SingleDatabaseWindow
+- It's view should go in QueryToolView.axaml
+- Uses mvvm
+- AvaloniaEdit should be used as a query editor
+
+## Editor
+
+- Use CodeEditorView
+- We want to be able to open and save .sql files with the editor
+
+## Result grid
+
+- Use an Avalonia.Controls.DataGrid
+- The columns will change on runtime so it should be able to get the column count captions and data types from the viewmodel
+- We want to be able to sort the columns
+- We want to be able to filter the rows by defining conditions for the columns
+- We want to be able to copy the rows to the clipboard
+- We want to be able to customize cell rendering to use different colors for types and also do special things like rendering booleans as green checks and red crosses
+- Be aware results may contain many rows, we should make a decision on how to handle this
+- We want to be able to save the results to a file
+
+---
+
+# Step-by-step plan to create the Query Tool
+
+1. Add QueryToolView to the UI shell.
+ - Place the view in pgLabII\Views\QueryToolView.axaml and include it within SingleDatabaseWindow as a child region/panel. Ensure DataContext is set to QueryToolViewModel.
+ - Confirm MVVM wiring: commands and properties will be bound from the ViewModel.
+
+2. Integrate the SQL editor.
+ - Embed AvaloniaEdit editor in the top area of QueryToolView.
+ - Bind editor text to a ViewModel property (e.g., UserSql).
+ - Provide commands for OpenSqlFile and SaveSqlFile; wire to toolbar/buttons and standard shortcuts (Ctrl+O/Ctrl+S).
+ - Ensure file filters default to .sql and that encoding/line-endings preserve content when saving.
+
+3. Add a results toolbar for query operations.
+ - Buttons/controls: Run, Cancel (optional), "Load more", Auto-load on scroll toggle, Export..., and a compact status/summary text (e.g., "Showing X of Y rows").
+ - Bind to RunQuery, LoadMore, ExportResults, AutoLoadMore, ResultSummary, and Status properties.
+
+4. Add the result grid using Avalonia.Controls.DataGrid.
+ - Enable row and column virtualization. Keep cell templates lightweight to preserve performance.
+ - Start with AutoGenerateColumns=true; later switch to explicit columns if custom cell templates per type are needed.
+ - Bind Items to a read-only observable collection of row objects (e.g., Rows).
+ - Enable extended selection and clipboard copy.
+
+5. Support dynamic columns and types from the ViewModel.
+ - Expose a Columns metadata collection (names, data types, display hints) from the ViewModel.
+ - On first page load, update metadata so the grid can reflect the current query’s shape.
+ - If AutoGenerateColumns is disabled, construct DataGrid columns based on metadata (text, number, date, boolean with check/cross visuals).
+
+6. Sorting model.
+ - On column header sort request, send sort descriptor(s) to the ViewModel.
+ - Re-run the query via server-side ORDER BY by wrapping the user SQL as a subquery and applying sort expressions.
+ - Reset paging when sort changes (reload from page 1).
+ - Clearly indicate if sorting is client-side (fallback) and only affects loaded rows.
+
+7. Filtering model.
+ - Provide a simple filter row/panel to define per-column conditions.
+ - Convert user-entered filters to a filter descriptor list in the ViewModel.
+ - Prefer server-side WHERE by wrapping the user SQL; reset paging when filters change.
+ - If server-side wrapping is not possible for a given statement, apply client-side filtering to the currently loaded subset and warn that the filter is partial.
+
+8. Data paging and virtualization (for 100k+ rows).
+ - Choose a default page size of 1000 rows (range 500–2000).
+ - On RunQuery: clear rows, reset page index, set CanLoadMore=true, fetch page 1.
+ - "Load more" fetches the next page and appends. Enable infinite scroll optionally when near the end.
+ - Display summary text: "Showing N of M+ rows" when total is known; otherwise "Showing N rows".
+ - Consider a cap on retained rows (e.g., last 10–20k) if memory is a concern.
+
+9. Query execution abstraction.
+ - Use a service (e.g., IQueryExecutor) to run database calls.
+ - Provide: FetchPageAsync(userSql, sort, filters, page, size, ct) and StreamAllAsync(userSql, sort, filters, ct) for export.
+ - Wrap user SQL as a subquery to inject WHERE/ORDER BY/LIMIT/OFFSET safely; trim trailing semicolons.
+ - Prefer keyset pagination when a stable ordered key exists.
+
+10. Export/Save results.
+ - Export should re-execute the query and stream the full result set directly from the database to CSV/TSV/JSON.
+ - Do not export from the grid items because the grid may contain only a subset of rows.
+ - Provide a Save As dialog with format choice and destination path.
+
+11. Copy to clipboard and selection.
+ - Enable extended row selection in the grid; support Ctrl+C to copy selected rows.
+ - Provide a toolbar "Copy" button as an alternative entry point.
+
+12. Status, cancellation, and errors.
+ - Show progress/state (Running, Idle, Loading page k, Cancelled, Error).
+ - Support cancellation tokens for long-running queries and paging operations.
+ - Surface exceptions as non-blocking notifications and preserve the last successful rows.
+
+13. Theming and custom cell rendering.
+ - Apply subtle coloring by type (numbers, dates, strings) via cell styles or templates.
+ - Render booleans as green checks/red crosses with minimal template overhead to keep virtualization effective.
+
+14. Wiring in SingleDatabaseWindow.
+ - Add a dedicated region/tab/panel for the Query Tool.
+ - Ensure lifetime management of the QueryToolViewModel aligns with the connection/session scope.
+ - Provide the active connection context/service to the ViewModel (DI or constructor).
+
+15. Testing and verification.
+ - Manual test: small query, large query (100k rows), sorting, filtering, load more, infinite scroll, export, copy, boolean rendering.
+ - Edge cases: empty results, wide tables (many columns), slow network, cancellation mid-page, schema change between pages.
+ - Performance check: scroll smoothness, memory growth under repeated paging, export throughput.
+
+16. Documentation and UX notes.
+ - In help/tooltip, clarify that sorting/filtering are server-side when possible; otherwise they apply only to loaded rows.
+ - Show a banner when results are truncated by paging limits and how to load more.
diff --git a/pgLabII/ViewModels/QueryToolViewModel.cs b/pgLabII/ViewModels/QueryToolViewModel.cs
index a2a1854..3f573a3 100644
--- a/pgLabII/ViewModels/QueryToolViewModel.cs
+++ b/pgLabII/ViewModels/QueryToolViewModel.cs
@@ -1,22 +1,94 @@
-using System.Reactive;
+using System;
+using System.Collections.ObjectModel;
+using System.Reactive;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
namespace pgLabII.ViewModels;
+public class ColumnInfo
+{
+ public string Name { get; set; } = string.Empty;
+ public string? DisplayName { get; set; }
+ public Type DataType { get; set; } = typeof(string);
+ public bool IsSortable { get; set; } = true;
+ public bool IsFilterable { get; set; } = true;
+ // Add more metadata as needed (format, cell template, etc.)
+}
+
public partial class QueryToolViewModel : ViewModelBase, IViewItem
{
- [Reactive] private string _caption = "Cap";
+ // Tab caption
+ [Reactive] private string _caption = "Query";
- [Reactive] private string _query = "";
+ // SQL text bound to the editor
+ [Reactive] private string _userSql = "SELECT 1 AS one, 'hello' AS text;";
- public ReactiveCommand EditCommand { get; }
+ // Summary and status labels
+ [Reactive] private string _resultSummary = "Showing 0 rows";
+ [Reactive] private string _status = "Ready";
+
+ // Paging flags
+ [Reactive] private bool _canLoadMore = false;
+ [Reactive] private bool _autoLoadMore = false;
+
+ // Rows shown in the DataGrid. For now, simple object rows for AutoGenerateColumns.
+ public ObservableCollection