Documentation
¶
Overview ¶
Package workspace is one person's working state against the databases, and the rules for changing it — with no UI in it.
A Workspace holds the active connection and its catalog, the session pinned to it, the run in flight, and the last statement, error, result and plan. The TUI (package tui) and the browser UI (dbc web) are both clients: they turn keys and clicks into calls here, and draw what comes back. The rules therefore exist once — ONE RUN AT A TIME, A PINNED SESSION per active connection, CANCEL REACHES THE SERVER (see run.go) — rather than as two copies that drift.
Starting work, and where its outcome lands ¶
Methods that start work (Connect, Run, Explain, RunScript) never block. They do the bookkeeping that must happen at once — claim the run slot, record history, bump a generation — and return a Start holding a Job: the blocking half, for the caller to run wherever its UI runs blocking work.
UI goroutine worker goroutine
──────────── ────────────────
st, err := w.Run(...) ── claims the slot, returns st.Job
err != nil → refused (busy, no connection, nothing to run)
log st.Notes
hand st.Job to a worker ─────────► ev := st.Job()
runs the statements
LANDS the outcome under w.mu:
frees the slot, sets last*
◄── returns ev (*RunDone)
draw ev (grid, status, log)
The TUI wraps a Job in a tea.Cmd, and the event comes back to Update as a message; the web layer runs it on a goroutine and writes the event to the workspace's SSE stream. The Job lands its own outcome before returning, so the workspace's state is right no matter when — or whether — a UI gets round to drawing the event.
Why a Job and not a channel of events: Bubble Tea already is an event loop with its own way of running blocking work (tea.Cmd), and the TUI's test harness drives it synchronously — press a key, run the command, feed its message back — so a workspace that ran its own goroutines would make every TUI test a race against a channel. Handing the blocking half back to the caller keeps both UIs in charge of their own concurrency.
Events that happen mid-run rather than at the end — a script's s.Show and s.Print — cannot be a Job's return value, and go to Options.Sink instead.
Locking ¶
mu guards the bookkeeping and is only ever held briefly. sessMu guards the pinned session and is held for as long as a statement runs on it — which may be minutes. The rule that keeps them from deadlocking: never take sessMu while holding mu. (Taking mu under sessMu is not needed today and is avoided too.)
Index ¶
- Constants
- func AttachColumns(ctx ai.Context, cols [][]db.Column, err error) (ai.Context, string)
- func Pick(ed Editor) (stmts []string, tag string)
- func PickAll(text string) (stmts []string, tag string)
- func PlanStatus(p *explain.Plan) string
- func Preview(stmt string) string
- func Project(src *model.Result, rows, cols []int) *model.Result
- func ResultStatus(r *model.Result, maxRows, shown int) string
- func SortRows(order []int, r *model.Result, col int, desc bool, numeric []bool)
- func StmtRange(text string, caret int) [2]int
- func WidestNumeric(r *model.Result, c int) int
- type Connected
- type Editor
- type Event
- type ExplainDone
- type GridView
- type Job
- type Level
- type Note
- type Options
- type Reason
- type Refusal
- type RowCounts
- type RunDone
- type SchemaLoaded
- type SchemaPick
- type ScriptPrint
- type ScriptShow
- type SessionReleased
- type Start
- type Workspace
- func (w *Workspace) Active() string
- func (w *Workspace) Busy() bool
- func (w *Workspace) Cancel() (n Note, status string)
- func (w *Workspace) CancelConnect() (Note, bool)
- func (w *Workspace) Catalog() *model.Result
- func (w *Workspace) CatalogSchema() string
- func (w *Workspace) ChatContext(question string, ed Editor, view GridView) (ctx ai.Context, refs []db.TableRef)
- func (w *Workspace) Close()
- func (w *Workspace) Complete(buffer string, caret int) (res sqlcomplete.Result, ready bool)
- func (w *Workspace) Config() *config.Config
- func (w *Workspace) Connect(name string) Start
- func (w *Workspace) ConnectPick(name string, pick SchemaPick) Start
- func (w *Workspace) Connecting() (name string, ok bool)
- func (w *Workspace) Databases() []db.DatabaseInfo
- func (w *Workspace) Derived(name string) bool
- func (w *Workspace) Diagram(ctx context.Context, sel erd.Selection) (*erd.Schema, error)
- func (w *Workspace) Disconnect() (left string, st Start, err error)
- func (w *Workspace) Explain(stmt, where string, analyze bool) (Start, error)
- func (w *Workspace) ExplainEditor(ed Editor, analyze bool) (Start, error)
- func (w *Workspace) History() *userdata.History
- func (w *Workspace) LastErr() string
- func (w *Workspace) LastResult() *model.Result
- func (w *Workspace) LastStmt() string
- func (w *Workspace) ListTables() (Start, error)
- func (w *Workspace) LoadCompletions(ctx context.Context) error
- func (w *Workspace) LookupColumns(refs []db.TableRef) ([][]db.Column, error)
- func (w *Workspace) Manager() *db.Manager
- func (w *Workspace) PickSchema(pick SchemaPick) (Start, error)
- func (w *Workspace) Plan() *explain.Plan
- func (w *Workspace) Recount(conn string) Job
- func (w *Workspace) Rename(buffer string, caret int, name string) ([]sqlcomplete.Edit, error)
- func (w *Workspace) RowCounts() map[db.TableRef]db.RowCount
- func (w *Workspace) Run(stmts []string, tag string) (Start, error)
- func (w *Workspace) RunEditor(ed Editor, all bool) (Start, error)
- func (w *Workspace) RunProgress() (step, steps int)
- func (w *Workspace) RunScript(path string) (Start, error)
- func (w *Workspace) RunStmts(stmts []string, tag string) (Start, error)
- func (w *Workspace) RunTag() string
- func (w *Workspace) RunningStatus() string
- func (w *Workspace) Schemas() []db.SchemaInfo
- func (w *Workspace) Session() (conn string, stateful bool)
- func (w *Workspace) ShowColumns(qname string) (Start, error)
- func (w *Workspace) Stop()
- func (w *Workspace) Switch(name string) Start
- func (w *Workspace) SwitchPick(name string, pick SchemaPick) Start
- func (w *Workspace) TableIndex() *db.TableIndex
- func (w *Workspace) Ticking(gen int) (status string, ok bool)
Constants ¶
const CompletionTimeout = DiagramTimeout
CompletionTimeout bounds reading a schema for completion. The ERD's bound: the same three catalog queries.
const DiagramTimeout = 30 * time.Second
DiagramTimeout bounds reading a schema for a diagram: three catalog queries, which take milliseconds on a normal database and seconds on a catalog of tens of thousands of tables. Longer than SchemaLookupTimeout, because here the user asked for the diagram and is waiting for it, while the assistant's lookup is a side errand that must not hold up a question.
const MaxSchemaTables = 8
MaxSchemaTables caps how many tables' columns go with one question. A query joining more than this is rare; a question whose words happen to name a dozen tables is not asking about all of them.
const SchemaLookupTimeout = 3 * time.Second
SchemaLookupTimeout bounds the catalog query a question's tables cost at send time. Past it the question goes without columns rather than waiting on a busy database: the model answering a little less precisely beats the user watching a spinner for a lookup they never asked for.
Variables ¶
This section is empty.
Functions ¶
func AttachColumns ¶
AttachColumns puts a lookup's columns into the context a question was asked with. Only the tables the catalog could describe are kept, so the transcript's "sent: schema of …" names exactly the tables whose columns went. A failed lookup drops the schema entirely and returns the line the transcript shows about it: the question still goes, and the user is told why the model may be guessing column names rather than reading dbc's.
Both UIs call this, so the rule for what a failed or partial lookup sends cannot differ between the terminal and the browser.
func Pick ¶
Pick is what Ctrl+R executes: the selection's statements when there is a selection, otherwise the statement under the caret. tag names the run for the status bar and log: "query" when the buffer holds one statement, "statement 2/4" when the caret picked one of several, "selection" or "selection (3 statements)".
func PickAll ¶
PickAll is what Ctrl+Shift+R executes: every statement in the buffer, whatever the caret or selection says. A one-statement buffer is tagged "query", as Pick tags it, since "all" of one says nothing more.
func PlanStatus ¶
PlanStatus is the status-bar summary of a plan: "plan · 12 steps, cost 431 · 2 findings".
func Project ¶
Project builds a Result holding the given result rows (in the order given — a slice of a display order) and result columns (likewise), with Raw carried along — so a copied selection exports exactly like a whole result: NULLs stay NULLs, numbers stay right-aligned in HTML.
Only the listed columns are taken, so a column the grid hides is left out by not listing it: a copy takes what the user sees. That is what makes hiding useful for sharing — hide the noisy columns, then copy the table for Teams.
func ResultStatus ¶
ResultStatus is the status-bar summary of a result. shown is how many rows the UI displays (max_display_rows can cap it below len(r.Rows)).
func SortRows ¶
SortRows fills order with the display order of r's rows sorted by result column col (ascending, or descending with desc). col < 0 means the result's own order. numeric says which columns compare as numbers — pass export.NumericColumns(r); it is a parameter because a UI computes it once per result, and this may run on every header click.
NULLs sort LAST in both directions: "biggest first" should not open on a screen of nothing. A numeric column compares numbers, so 10 sorts after 9; anything else compares its text case-insensitively. The sort is stable, so rows that tie keep the result's order.
func StmtRange ¶
StmtRange is the byte range of the statement under the caret, for an editor's gutter marker — zero when the buffer holds fewer than two statements, since marking the only one says nothing.
func WidestNumeric ¶
WidestNumeric is the widest display value of numeric column c over EVERY row of r — for a column export.NumericColumns vouched for.
Auto-sizing measures only a grid's first few hundred rows (a text column's width costs a grapheme walk per value, and a huge result should not pay that on arrival), which is fine for text, whose width varies without pattern, and wrong for numbers, which grow: an id column sized by rows 1–500 shows "10…" at row 1,000. A number's display text is plain ASCII, so its width is len() — no decoding — and scanning every row is a length read per cell. NULLs count as their "NULL" text, which is how both grids draw them.
The widest text is measured rather than derived from the column's min/max: a float's text is not monotonic in its value (0.123456789 is wider than 1000), and a length scan is as cheap as a comparison.
Types ¶
type Connected ¶
type Connected struct {
Name string
Catalog *model.Result // the connection's tables; nil if the catalog query failed
// Databases and Schemas are the levels above the tables: the server's
// databases, on a driver with a database picker (db.HasDatabases:
// Postgres, MySQL), and this database's schemas with their table
// counts, on one whose sidebar is loaded a schema at a time
// (db.Navigable: Postgres). Schema is the one whose tables Catalog
// holds, "" for every schema's. Each is empty on the other drivers,
// and Databases or Schemas is nil when its listing failed.
Databases []db.DatabaseInfo
Schemas []db.SchemaInfo
Schema string
Err error // the connect's failure (db.ErrCanceled when stopped); nil on success
Changed bool // the active connection moved to Name
// Left is the connection Changed moved away from, "" when there was
// none (the first connect, or one after a Disconnect). A UI that knows
// no other workspace is on it may close its pool once Release has run
// — see Workspace.Derived for the one kind worth closing.
Left string
// Stale reports a connect superseded by a newer one: nothing landed,
// and a UI draws nothing.
Stale bool
Notes []Note
Status string // for a status bar; "" leaves it
// Release, when non-nil, closes the session pinned to the connection
// just left — rolling back what it left open. It is a separate Job
// because it waits for any statement still running on that session,
// and the switch itself must not.
Release Job
// Counts, when non-nil, fetches the row counts of the catalog's tables
// for the sidebar; its event is a *RowCounts. It is separate so the
// tables list draws at once and the numbers fill in after — a count
// reads a table's rows, and the list must never wait for that.
Counts Job
}
Connected lands a connect.
type Editor ¶
Editor is what a UI's SQL editor holds at the moment of a request: the buffer, the caret as a byte offset into it, and the selected text ("" when nothing is selected). The UI sends the caret and the workspace picks the statement, so "the statement under the caret" means the same thing in every UI.
type Event ¶
type Event interface {
// contains filtered or unexported methods
}
Event is something that happened in the workspace. The concrete types are the pointers below.
type ExplainDone ¶
type ExplainDone struct {
Tag string
Conn string
Stmt string
Plan *explain.Plan
Err error
Elapsed time.Duration
Stale bool
Notes []Note
Status string // as RunDone's: set on failure only
}
ExplainDone lands an explain.
type GridView ¶
type GridView struct {
Result *model.Result // the result the grid holds
Hidden []int // result columns hidden in the grid, ascending
SortCol int // the result column sorted on; -1 for the result's own order
SortDesc bool
Order []int // display row → result row; read, never kept
}
GridView is how a UI's grid shows the result it holds — presentation, so it stays with each UI, but the assistant's data rule needs it: rows go in the order the user sees them, and hidden columns stay out.
type Job ¶
type Job func() Event
Job is the blocking half of a request: it does the work, lands the outcome in the workspace, and returns an Event describing what landed (nil when there is nothing to tell). Run it off the UI goroutine.
type Level ¶
type Level int
Level is how a Note should be shown — the TUI's log colors, the web log's classes.
type Note ¶
Note is one line for the user's log. The workspace writes the words, so a busy refusal or a stopped run reads the same in the terminal and the browser.
type Options ¶
type Options struct {
// Sink receives the events that happen mid-run, from the run's own
// goroutine: a script's ScriptShow and ScriptPrint. It must not block
// for long, and must not call back into the Workspace's start methods
// synchronously. nil drops them.
Sink func(Event)
// WholeCatalog is for a UI with no schema picker (the TUI): a connect
// that names no schema lists every schema's tables, as long as the
// database has at most db.AllSchemasLimit of them, instead of opening
// on the search_path's first schema. Past the limit it opens on that
// schema all the same, with a note: listing a huge catalog is the cost
// the per-schema load exists to avoid.
WholeCatalog bool
}
Options configure New beyond the config.
type Reason ¶
type Reason int
Reason is why a request was refused — what the web layer maps to a status code (Busy → 409, the rest → 400).
type Refusal ¶
Refusal is a request the workspace declined, with the reason in words for the user. It is an error, but not a failure: nothing was attempted, and nothing about the workspace changed.
type RowCounts ¶ added in v0.3.0
type RowCounts struct {
Conn string
Counts map[db.TableRef]db.RowCount // read-only; see db.Manager.RowCounts
// Stale reports counts for a connection that is no longer the active
// one, or a counting a later connect canceled: nothing landed, and a UI
// draws nothing.
Stale bool
Notes []Note
}
RowCounts lands the row counts of the active connection's tables. The counts are also kept in the workspace (see Workspace.RowCounts), so a UI that redraws its tables list later finds them there.
type RunDone ¶
type RunDone struct {
Tag string
Conn string
Stmts []string // what ran; nil for a script
Result *model.Result // the last statement's result; nil on failure and for a script
Plan *explain.Plan // Result is itself a query plan (an EXPLAIN the user typed)
Err error // the failure, or db.ErrCanceled when stopped
Script bool
Elapsed time.Duration
Stale bool // a straggler from a run already written off: draw nothing
Notes []Note
// Status is for the status bar when the run failed or stopped. On
// success it is "": the summary depends on how many rows the UI shows
// (see ResultStatus).
Status string
// Counts, when non-nil, refreshes the sidebar's row counts: the run may
// have changed rows (db.ChangesRows), failed or not. Its event is a
// *RowCounts, as Connected.Counts's is.
Counts Job
}
RunDone lands a run of statements, or of a script.
type SchemaLoaded ¶ added in v0.3.0
type SchemaLoaded struct {
Conn string
Schema string // the schema loaded; "" for every schema
Catalog *model.Result // its tables; nil when the load failed, and the old list stays
// Stale reports a load superseded by a later pick or connect: nothing
// landed, and a UI draws nothing.
Stale bool
Notes []Note
// Counts is the row counting of the new tables, as on Connected.
Counts Job
}
SchemaLoaded lands a schema pick (Workspace.PickSchema): the tables of another schema of the active database, in place of the ones the sidebar listed.
type SchemaPick ¶ added in v0.3.0
type SchemaPick struct {
// Name is the schema to list. One the database no longer has falls
// back to the default rather than to an empty list.
Name string
// All lists every schema's tables, where the database has at most
// db.AllSchemasLimit of them; past that, the default schema, with a
// note saying why.
All bool
}
SchemaPick says which tables a sidebar on a db.Navigable driver lists (Postgres: see db/navigate.go). The zero value is the default: the first schema on search_path, which is what a bare table name means there.
type ScriptPrint ¶
type ScriptPrint struct{ Text string }
ScriptPrint is a script's s.Print, mid-run: a line for the log.
type ScriptShow ¶
ScriptShow is a script's s.Show, mid-run: a result to put in the grid.
type SessionReleased ¶
type SessionReleased struct {
Conn string
Stateful bool // it held state, now gone
Notes []Note // a warning when it did
}
SessionReleased reports that switching connections closed the session pinned to the previous one.
type Start ¶
type Start struct {
Tag string // names the run: "query", "statement 2/4", "explain", …
Gen int // the run generation, for a ticker (see Ticking)
Notes []Note // what to log now — present even when the request was refused
Job Job // the blocking half; nil when refused or when there is nothing to do
}
Start is what a start method returns.
type Workspace ¶
type Workspace struct {
// contains filtered or unexported fields
}
Workspace is one person's working state. Its methods are safe for concurrent use.
func New ¶
New builds a workspace over cfg's connections. It does no IO: the first connect is the caller's Connect(w.Active()).
The active connection starts as the config's default_connection, or the first connection when that names none — so a UI can draw it before the connect completes.
func (*Workspace) Busy ¶
Busy reports whether a run (statements, an explain or a script) is in flight.
func (*Workspace) Cancel ¶
Cancel is Ctrl+K and the Stop button: it stops the run in flight or, with none, the connect in flight. The Note says what it did; status is for a status bar ("" leaves it). The stopped work still lands, as stopped.
func (*Workspace) CancelConnect ¶
CancelConnect abandons the connect in flight. It reports false when there is none. The connect still lands, as canceled.
func (*Workspace) Catalog ¶
Catalog is the active connection's tables, as its catalog query returned them; nil before the first connect completes, or when the query failed.
func (*Workspace) CatalogSchema ¶ added in v0.3.0
CatalogSchema is the schema whose tables Catalog holds, or "" when it holds every schema's (always, on a driver that is not db.Navigable).
func (*Workspace) ChatContext ¶
func (w *Workspace) ChatContext(question string, ed Editor, view GridView) (ctx ai.Context, refs []db.TableRef)
ChatContext gathers what the next question may carry — see package ai for what actually goes, which is decided by the connection's ai_rows.
Which statement is "this query": the one under the editor's caret, since that is what the user is looking at. When it is the statement that last ran, its result (or error) comes along; when the editor is empty, the last run's statement stands in.
question is the question being (or about to be) asked; its words, like the statement's, pick which tables' schema goes along. The Tables come back named but without columns — the caller looks those up (they cost a catalog query) — and refs is the same tables as the catalog knows them, for that lookup.
It is cheap enough to call every frame, as the TUI's context chip does.
func (*Workspace) Close ¶
func (w *Workspace) Close()
Close stops what is in flight and releases the pinned session, rolling back whatever it left open. It waits for a statement still running to return from its cancel.
func (*Workspace) Complete ¶ added in v0.4.0
Complete suggests what to type at caret (a byte offset into buffer), from the active connection's cached schema. It never blocks on the database: ready is false when the schema is not cached yet, and the caller then runs LoadCompletions off its event loop and asks again. With no connection, or after a failed load, it is ready with the dialect's vocabulary alone.
func (*Workspace) Connect ¶
Connect opens the connection and loads its sidebar, opening on the default schema (see SchemaPick, Options.WholeCatalog).
func (*Workspace) ConnectPick ¶ added in v0.3.0
func (w *Workspace) ConnectPick(name string, pick SchemaPick) Start
ConnectPick opens the connection and fetches its catalog for a sidebar. The catalog goes through the pool, not the pinned session: it is the app's query, and must not land inside a transaction the user has open.
On a db.Navigable driver the catalog is three short reads rather than one long one — the server's databases, this database's schemas, and the tables of the one schema pick names — so a connect to a big server costs what its sidebar shows, not what the server holds. Elsewhere it is the whole table list, as it always was — after, on MySQL, the server's databases (db.HasDatabases), for the database picker.
The connect runs under its own context, so Cancel can abandon it — without that, only connect_timeout bounds it, and with connect_timeout = "0" an unreachable host would hold "connecting…" until the OS gave up on the TCP connect, over a minute later. Starting a connect cancels any still in flight: the user has changed their mind, and the older one must not land after the newer one and switch the connection back.
pick A ──► connGen=1, dial A ───────────── (canceled) ──► lands Stale pick B ──► connGen=2, cancel A, dial B ─► lands, active = B
The Job's event is a *Connected.
func (*Workspace) Connecting ¶
Connecting reports whether a connect is in flight, and to what.
func (*Workspace) Databases ¶ added in v0.3.0
func (w *Workspace) Databases() []db.DatabaseInfo
Databases is the active connection's server's databases, for a database picker; nil on a driver without databases (db.HasDatabases), or when the listing failed. The slice is shared: read it, never write to it.
func (*Workspace) Derived ¶ added in v0.3.0
Derived reports whether name is a connection derived onto another of its base's databases ("<conn>/<database>", config.DatabaseSep) rather than a configured one.
It is what a UI asks of Connected.Left before closing the pool a switch left. A derived pool is the one worth closing: browsing a server's databases opens one per database picked, and without a close each stays open (its *sql.DB until dbc exits, its idle connections until conn_idle_timeout), so the count grows with the browsing rather than with the configured connections. A configured connection's pool is kept, as it always was: there is one per row of the Connections list, and switching back to it should not dial again.
func (*Workspace) Diagram ¶ added in v0.3.0
Diagram reads the active connection's schema and narrows it to sel — the entity-relationship diagram both UIs draw (the TUI saves and opens it, dbc web shows it and serves its files). It blocks for the catalog round trips, so a UI calls it off its event loop.
Like LookupColumns it runs on the POOL, not the pinned session: a diagram must not wait for a long query the user is running, nor read the schema from inside their open transaction.
It does not take the run slot either — reading the catalog is not a run, and a diagram while a query runs is a reasonable thing to want.
A table in sel that is not in the schema is refused (Invalid) rather than dropped quietly: a diagram "around orders" that silently shows the whole database would be a confusing answer.
A diagram of everything (sel naming no tables) is of the schema the sidebar lists, when it lists one (CatalogSchema): on a big database "all" means what the user is looking at, not every table the server holds.
A CATALOG TOO BIG TO READ WHOLE (db.ErrCatalogTooBig) is read SCOPED instead, on Postgres, as completion does (complete.go): Manager.SchemaIn over the schemas the selection can be about (diagramScope). The connection is then remembered as too big (complScoped, shared with completion — both read the same Manager.Schema, so one finding it overflow is the other's answer too), and later diagrams and completion loads skip the failing whole read.
whole (Manager.Schema) ──ok────────────────────────────► Select │ ErrCatalogTooBig (or complScoped[conn] already) ▼ complScoped[conn] = true ▼ scoped (Manager.SchemaIn: diagramScope) ──► Select
What a scoped diagram misses: a neighbour (sel.Depth) in a schema outside the scope, since SchemaIn leaves out keys to tables it did not read; and a bare name that is unique in the scope but not in the database resolves rather than being refused as ambiguous. Both are the price of drawing anything at all where the whole read cannot.
func (*Workspace) Disconnect ¶ added in v0.3.0
Disconnect leaves the active connection without picking another: no active connection, no catalog, and — through the Job — the pinned session closed, rolling back whatever it left open, as a switch does. A connect in flight is abandoned with it (connGen moves on, so it lands Stale), as is the sidebar's counting and schema loading. It returns the connection left: on a connect still dialing, the one being dialed when there was no connection before it.
A run in flight is refused rather than canceled: its session is the one the disconnect would close, and a Stop first leaves the user to decide what becomes of the statement. Nothing to disconnect from is refused too.
The pool is not this workspace's to close — other workspaces may be on the same connection (db.Manager is shared); a UI that knows they are not closes it with db.Manager.Disconnect once the Job has run.
The Job's event is a *SessionReleased, or nil when no session was open.
func (*Workspace) Explain ¶
Explain explains one statement on the active connection. where is how the statement was picked ("statement 2/4", "selection"), folded into the tag; "" or "query" adds nothing. The Job's event is an *ExplainDone.
func (*Workspace) ExplainEditor ¶
ExplainEditor is Ctrl+X (estimate) and Alt+X (analyze): explain the statement under the caret, or the selected one.
func (*Workspace) LastErr ¶
LastErr is what the last run failed with, "" if it worked. A stopped run leaves it alone: stopping is the user's choice, not a failure to explain.
func (*Workspace) LastResult ¶
LastResult is the last result published — by a run, or by a script's s.Show. nil before any.
func (*Workspace) ListTables ¶
ListTables is Ctrl+T: the active driver's catalog query, through the same path a run takes, so it lands in the grid and exports like any result. It is the app's query, not the user's, so it is not recorded.
func (*Workspace) LoadCompletions ¶ added in v0.4.0
LoadCompletions reads the active connection's schema into the completion cache, unless it is cached already. It blocks for the catalog round trips (bounded by CompletionTimeout and ctx), so a UI calls it off its event loop. Callers that arrive while a load is in flight wait for that one rather than starting their own.
The error is the load's, for the UI to report once; completion goes on with the vocabulary alone either way.
func (*Workspace) LookupColumns ¶
LookupColumns fetches the columns of the tables a question involves (the refs ChatContext returned) on the active connection, under SchemaLookupTimeout. It blocks for a catalog round trip, so a UI calls it off its event loop; the result goes to AttachColumns.
It runs on the POOL, not the pinned session: the session may be mid-run, and a question about a slow query must not wait for that query to end.
func (*Workspace) PickSchema ¶ added in v0.3.0
func (w *Workspace) PickSchema(pick SchemaPick) (Start, error)
PickSchema lists another schema's tables in the sidebar, on the active connection, in place of the ones listed now. The tables load off the UI's event loop (the Job), like a connect's; the event is a *SchemaLoaded, with a Counts job for the new tables' row counts.
It shares connGen with Connect, so whichever of a pick and a connect starts later wins: a connect supersedes a pick in flight (another database's schemas are not this one's), and a pick supersedes the old list's counting and any earlier pick. A pick while a connect is still in flight is refused — the schema list it would pick from is being replaced.
pick sales ──► gen=5, load sales ───────────── (canceled) ─► Stale pick hr ──► gen=6, cancel sales, load hr ─► lands, schema = hr
func (*Workspace) Recount ¶ added in v0.4.0
Recount refreshes the sidebar's row counts after another workspace's run on conn may have changed rows, or returns nil when this sidebar is not showing conn's tables. A UI that hosts several workspaces on one Manager (dbc web's query tabs and windows) calls it on the others when a RunDone carries Counts, so every sidebar on the connection shows the write, not only the one that made it.
Unlike recountLocked it does not drop the Manager's cached counts: the writer's landRun already did, before its RunDone was delivered, so what is cached now was counted after the write. Dropping again would only make each workspace count afresh instead of sharing the writer's counting (db.Manager.RowCounts waits for one in flight).
func (*Workspace) Rename ¶ added in v0.7.0
Rename renames the alias or CTE under caret in buffer to name (sqlcomplete.Rename), quoting it as the active connection's dialect needs. It needs no schema, so unlike Complete it never waits on a load. The error is a sentence for the user: why there is nothing to rename.
func (*Workspace) RowCounts ¶ added in v0.3.0
RowCounts is the row count of each of the catalog's tables that has one (views never do); nil until the connect's counting lands. The map is shared: read it, never write to it.
func (*Workspace) Run ¶
Run executes statements in order on the pinned session, stopping at the first failure, and publishes the last result. The Job's event is a *RunDone.
func (*Workspace) RunEditor ¶
RunEditor is Ctrl+R (all false) or Ctrl+Shift+R (all true) on what the editor holds.
func (*Workspace) RunProgress ¶
RunProgress is how far a multi-statement run has got: the statement executing now (1-based) and how many there are. steps is 0 when idle, and for work that is not a list of statements.
func (*Workspace) RunScript ¶
RunScript runs a Go script. Its s.Show and s.Print fire from the script's goroutine mid-run and go to the sink as ScriptShow and ScriptPrint; the Job's event is a *RunDone with Script set.
func (*Workspace) RunStmts ¶
RunStmts records statements in the history and runs them. It is how anything the user asked to run by hand gets run: Ctrl+R, run all, a table preview.
func (*Workspace) RunTag ¶
RunTag names the run in flight ("statement 2/4", "explain", "script x.go"); "" when idle.
func (*Workspace) RunningStatus ¶
RunningStatus is the status line for the run in flight, "" when idle.
func (*Workspace) Schemas ¶ added in v0.3.0
func (w *Workspace) Schemas() []db.SchemaInfo
Schemas is every schema of the active database, empty ones included, with its table count; nil on a driver that is not db.Navigable. The slice is shared: read it, never write to it.
func (*Workspace) Session ¶
Session describes the pinned session: the connection it is pinned to ("" when none is) and whether it holds state a close would lose — an open transaction, a SET, a temp table. A UI shows the latter as a "transaction open" badge.
It takes sessMu, so it waits for a statement in flight to finish; call it from a UI only where that is acceptable (not every frame).
func (*Workspace) ShowColumns ¶ added in v0.3.0
ShowColumns lists a table's information_schema.columns rows in the grid, where they can be read, sorted and copied like any result. qname is the name the sidebar shows for the table (see db.TableIndex.Lookup).
It goes through RunStmts, like a table preview: the statement is recorded in the history, because it is what the user would have typed and is the easiest way back to it (or to an edited SELECT * of it). It is not put in the editor, whose text is the user's.
Only a table in the active connection's catalog is accepted. The name is inlined into SQL, so a name from anywhere else is refused, not escaped and tried.
func (*Workspace) Stop ¶
func (w *Workspace) Stop()
Stop cancels the run, the connect and the row counting in flight, if any, without a word — the first step of quitting. The canceled work still lands its outcome.
func (*Workspace) Switch ¶
Switch is picking a connection: a connect with a line for the log, and nothing at all when name is already active and its catalog loaded.
func (*Workspace) SwitchPick ¶ added in v0.3.0
func (w *Workspace) SwitchPick(name string, pick SchemaPick) Start
SwitchPick is Switch, opening the sidebar on pick: a UI that remembers a schema per connection asks for it here, rather than loading the default schema's tables only to replace them with a PickSchema at once.
func (*Workspace) TableIndex ¶
func (w *Workspace) TableIndex() *db.TableIndex
TableIndex is the catalog indexed for name lookups; nil without one.