Documentation
¶
Overview ¶
Package runner executes SQL statements against the AWS RDS Data API and shapes the response into a UI-friendly Result. It is deliberately free of any terminal/bubbletea or HTTP concerns so the TUI, CLI, and GUI can all reuse the same engine.
Index ¶
- Constants
- Variables
- func ColumnWidths(columns []string, rows [][]any) []int
- func DisplayWidth(s string) int
- func FormatCell(v any) string
- func IsReadOnlySQL(sql string) bool
- func NeedsConfirmation(sql string) (bool, string)
- func RenderTable(w io.Writer, r *Result) error
- func Truncate(s string, width int) string
- type Result
- type Target
Constants ¶
const ColumnWidthCap = 40
ColumnWidthCap caps any single column at this many display cells before truncation kicks in, so a very wide value cannot push other columns off screen.
const ExecuteTimeout = 2 * time.Minute
ExecuteTimeout caps a single statement so a runaway query does not lock up the caller. The Data API itself enforces shorter limits, so this is a safety net rather than the primary bound. The caller is free to impose a stricter ctx deadline.
const NullDisplay = "NULL"
NullDisplay is the canonical NULL marker shown in the table and JSON view.
Variables ¶
var ErrEmptySQL = errors.New("enter a SQL statement to run")
ErrEmptySQL is returned when the SQL text is empty or whitespace only. Callers should treat it as a user-facing hint rather than a real error.
var ErrWriteBlocked = errors.New("read-only mode blocks non-SELECT statements")
ErrWriteBlocked is returned when a statement is rejected because the active connection is in read-only mode. Callers surface this to the UI with a hint that the read-only toggle in Settings can be flipped.
Functions ¶
func ColumnWidths ¶
ColumnWidths returns the rendered column widths needed to fit all headers and cell values, capped at ColumnWidthCap per column.
func DisplayWidth ¶
DisplayWidth approximates the visible width of a cell. We deliberately use rune count rather than wcwidth because the input is already free of escape sequences and the table width only needs to be roughly accurate.
func FormatCell ¶
FormatCell renders a typed cell value as a display string for the table view. NULL becomes "NULL", blobs become "<blob N bytes>", and arrays use a JSON-ish notation produced by recursively formatting their elements.
func IsReadOnlySQL ¶
IsReadOnlySQL reports whether the given SQL statement is a pure read operation based on its leading keyword. Line (`--`) and block (`/* */`) comments and surrounding whitespace are skipped before the keyword is extracted. Unknown / non-alphabetic leading tokens return false so the safe default is "reject".
func NeedsConfirmation ¶
NeedsConfirmation reports whether a statement is destructive enough that the UI should require an extra "yes, run it" from the user before dispatching it to the Data API. It returns a short human-readable reason alongside the bool so the confirmation prompt / dialog can quote it verbatim.
The rule is deliberately narrow so it doesn't nag the user on every write: we only warn on the combinations that overwhelmingly correlate with accidents.
- DELETE without a WHERE clause → nukes every row
- UPDATE without a WHERE clause → rewrites every row
- TRUNCATE (no WHERE clause even exists in the grammar) → drops all rows
Comments and string literals are stripped before the WHERE search so `UPDATE t SET c = 'WHERE it failed'` and `DELETE FROM t -- no WHERE here` are not fooled.
func RenderTable ¶ added in v0.0.3
RenderTable writes Result as a psql-style bordered ASCII table.
Numeric columns (int64/float64) are right-aligned so digits line up by magnitude; everything else is left-aligned. Cells wider than ColumnWidthCap are truncated via Truncate so a single long value cannot push other columns off screen. SELECT-shaped results (Updated < 0) append a "(N rows)" footer; write-shaped results leave the footer to the caller so it can be routed to stderr and keep stdout free of non-data noise.
r == nil or a result with no columns renders nothing.
Types ¶
type Result ¶
type Result struct {
Columns []string
Rows [][]any
// Updated is the number of rows affected for INSERT/UPDATE/DELETE.
// -1 means "not applicable" (e.g. SELECT).
Updated int64
// contains filtered or unexported fields
}
Result is a UI-friendly view of an RDS Data API ExecuteStatement response. Cell values are kept in their native Go types so JSON and CSV exports can preserve type information; table rendering converts them to strings on demand.
func ConvertResult ¶
func ConvertResult(out *rdsdata.ExecuteStatementOutput) *Result
ConvertResult turns an ExecuteStatement output into a Result by walking the column metadata for headers and the records grid for cell values. Row length is normalized to len(Columns) so callers can rely on the invariant that every row has exactly one cell per column.
func ExecuteSQL ¶
func ExecuteSQL(ctx context.Context, client *rdsdata.Client, target Target, sql string) (*Result, time.Duration, error)
ExecuteSQL runs the given SQL against the Data API and returns a parsed Result. It is a synchronous, side-effect free function so HTTP handlers and tea.Cmd wrappers can share it. The caller is responsible for history logging.
func (*Result) ExportCSV ¶
ExportCSV writes the result to a timestamped file in the current working directory and returns its path. Filename collisions are resolved by adding a counter suffix so two presses within the same second do not overwrite.
func (*Result) RowJSON ¶
RowJSON renders a single row as a pretty-printed JSON object with the original column order preserved. encoding/json sorts map keys alphabetically, which loses the SELECT order users expect, so we build the outer object by hand and only delegate to json.MarshalIndent for individual values (which keeps native typing for numbers, bools, blobs, and nulls).
func (*Result) ToJSON ¶
ToJSON renders the result as a pretty-printed JSON array of row objects. Because Rows is [][]any with native Go types, encoding/json preserves number/bool/null/blob(base64) without lossy stringification.
func (*Result) Widths ¶
Widths returns the rendered display width for each column, caching the result so a table view can scroll horizontally without re-walking every cell on each keystroke.