Help us shape the future of Go! Take the 2026 Go Developer Survey

sqlcomplete

package
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package sqlcomplete suggests what to type next in a SQL buffer: the columns, tables and join conditions the connection's schema holds, and the dialect's keywords, functions and types. Both UIs ask it — the TUI's editor popup and dbc web's Monaco suggest widget — so the rules for what is offered where exist once, in Go, rather than as a JavaScript copy that would drift from the terminal's.

How a request is answered

buffer + caret ─► the statement under the caret (sqlsplit, the run's splitter)
                     │
                     ├─► tokens (sqlsplit.Lex for strings/comments/quoted names)
                     │
                     ├─► scope: FROM/JOIN/UPDATE/INTO refs and their aliases,
                     │          CTEs with the columns their SELECT lists name
                     │
                     └─► context: what the token before the caret asks for
                               │
           ┌──────────┬────────┴──────┬────────────┬──────────┐
         start      tables       expression     qualified   clause …
       (SELECT…)  (FROM ▮)    (WHERE ▮, =▮)    (o.▮)     (FROM t ▮)
                               │
          candidates ─► filtered by the typed prefix ─► ranked ─► capped

Lexical, not a parse

Like the splitter and the highlighter this is a scanner with a few rules, not a SQL grammar. It knows which keyword precedes the caret and which tables the statement names; it does not know that a subquery's columns are out of scope outside it. Every table the statement names is therefore in scope everywhere in it. Offering a column one subquery too early costs a line in a list; a grammar for four dialects would cost far more and still fail on the half-typed statement a completion request always sees.

Offsets

Every offset in and out is a byte offset into the buffer. dbc web converts to and from the UTF-16 units the browser counts (web/api.go byteOffset), the TUI from its rune positions.

Index

Constants

View Source
const MaxItems = 400

MaxItems caps a result. A catalog of thousands of columns answered in full would be a long list nobody scrolls and a large response per keystroke; the first few hundred, best first, are the useful ones, and Incomplete tells the client to ask again as the prefix narrows it.

View Source
const NotOnSymbol = "works on a table alias, a CTE name, or a column the query names itself"

NotOnSymbol finishes the sentence for a caret on nothing the resolver knows ("rename works on …", "F12 works on …"), so every editor says it in the same words.

Variables

This section is empty.

Functions

This section is empty.

Types

type Edit added in v0.7.0

type Edit struct {
	From int    `json:"from"`
	To   int    `json:"to"`
	Text string `json:"text"`
}

Edit replaces [From, To) of the buffer with Text.

func Rename added in v0.7.0

func Rename(buf string, caret int, name, driver string) ([]Edit, error)

Rename is the edits that rename the symbol under caret to name, quoted as driver's dialect needs (a capital on Postgres, a reserved word, a space). A name the user quoted already is used as written. The error is a sentence for the user: nothing renamable is under the caret, the symbol is a table (or a table's column), or the name is taken in the same query.

type Item

type Item struct {
	Label  string `json:"label"`            // what the list shows
	Kind   Kind   `json:"kind"`             // see Kind
	Detail string `json:"detail,omitempty"` // one line beside the label: a type, a signature
	Doc    string `json:"doc,omitempty"`    // longer text: a table's DDL, a function's description
	Insert string `json:"insert"`           // what replaces [From, To) when picked
	// Filter is the text the typed prefix is matched against when it is
	// not the label — a column offered qualified ("o.id") still matches
	// "id". Empty means the label.
	Filter string `json:"filter,omitempty"`
	// Cursor is where the caret lands inside Insert after the pick, as a
	// byte offset into Insert; -1 means after it. A function lands
	// between its parentheses.
	Cursor int    `json:"cursor"`
	Sort   string `json:"sort"` // ascending sort key; the order Items is already in
}

Item is one suggestion.

type Kind

type Kind string

Kind classifies a suggestion, for its icon and its place in the order.

const (
	KindColumn   Kind = "column"
	KindTable    Kind = "table"
	KindView     Kind = "view"
	KindSchema   Kind = "schema"
	KindAlias    Kind = "alias" // a table reference's alias, or a CTE
	KindJoin     Kind = "join"  // a whole join clause or ON condition from a foreign key
	KindKeyword  Kind = "keyword"
	KindFunction Kind = "function"
	KindType     Kind = "type"
)

type Request

type Request struct {
	// Schema is the connection's tables, columns and keys (the ERD's
	// reading of the catalog); nil offers only the dialect's vocabulary.
	Schema *erd.Schema
	// Driver is the connection's driver as configured (postgres, pg,
	// mysql, sqlite, bytdb …), for the dialect's vocabulary and quoting.
	Driver string
	// Focus is the schema the user is browsing (the sidebar's), whose
	// tables are ranked first; "" when there is none.
	Focus string
	// SearchPath is the schemas a bare table name resolves through, in
	// order (Postgres's current_schemas); nil means the dialect's default
	// (public on Postgres and bytdb). A table in one of them is inserted
	// bare unless a schema earlier on the path has a table of that name.
	SearchPath []string
	// Buffer is the whole editor text and Caret a byte offset into it.
	Buffer string
	Caret  int
}

Request is one completion request.

type Result

type Result struct {
	From, To int    // the byte range a picked item replaces: the word being typed
	Prefix   string // buffer[From:To], what was matched against
	Items    []Item
	// Incomplete reports that Items was cut at MaxItems: a longer prefix
	// may surface items not listed now, so a client should ask again as
	// the prefix grows rather than filter this list itself.
	Incomplete bool
}

Result is the answer to a request.

func Complete

func Complete(req Request) Result

Complete answers req. It never fails: a caret inside a string or a comment, or a context with nothing to offer, is an empty Result.

type Span added in v0.7.0

type Span struct {
	From int `json:"from"`
	To   int `json:"to"`
}

Span is a byte range of the buffer, a token's: a quoted name's quotes included.

type Symbol added in v0.7.0

type Symbol struct {
	Kind SymbolKind `json:"kind"`
	Name string     `json:"name"` // as declared, without quotes
	At   Span       `json:"at"`   // the occurrence under the caret
	Def  Span       `json:"def"`  // where it is declared
	Uses []Span     `json:"uses"` // every occurrence, Def included, in buffer order
	// Fixed says why the name cannot be renamed here; "" when it can.
	Fixed string `json:"fixed,omitempty"`
}

Symbol is the answer to Resolve. A zero Kind means the caret is on nothing the resolver knows: a column, a keyword, blank space.

func Resolve added in v0.7.0

func Resolve(buf string, caret int) Symbol

Resolve finds the symbol under caret (a byte offset into buf) in the statement around it. It never fails: anything it cannot place is a zero Symbol.

type SymbolKind added in v0.7.0

type SymbolKind string

SymbolKind is what a resolved name is.

const (
	SymAlias  SymbolKind = "alias"  // a table reference's alias
	SymCTE    SymbolKind = "cte"    // a WITH query's name
	SymTable  SymbolKind = "table"  // a table referenced without an alias
	SymColumn SymbolKind = "column" // a column the statement itself names
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL