runner

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2026 License: MIT Imports: 16 Imported by: 0

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

View Source
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.

View Source
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.

View Source
const NullDisplay = "NULL"

NullDisplay is the canonical NULL marker shown in the table and JSON view.

Variables

View Source
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.

View Source
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

func ColumnWidths(columns []string, rows [][]any) []int

ColumnWidths returns the rendered column widths needed to fit all headers and cell values, capped at ColumnWidthCap per column.

func DisplayWidth

func DisplayWidth(s string) int

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

func FormatCell(v any) string

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

func IsReadOnlySQL(sql string) bool

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

func NeedsConfirmation(sql string) (bool, string)

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

func RenderTable(w io.Writer, r *Result) error

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.

func Truncate

func Truncate(s string, width int) string

Truncate shortens s to at most width display cells, appending an ellipsis when content was dropped.

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

func (r *Result) ExportCSV() (string, error)

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

func (r *Result) RowJSON(idx int) (string, error)

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

func (r *Result) ToJSON() string

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

func (r *Result) Widths() []int

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.

func (*Result) WriteCSV

func (r *Result) WriteCSV(w io.Writer) error

WriteCSV serializes the result as CSV. Numbers, bools, and strings are written in their natural form; NULL becomes the empty field, blobs become base64, and arrays use the same JSON-ish notation as the table view so existing readers can interpret them visually.

type Target

type Target struct {
	Profile  string
	Region   string
	Cluster  string
	Secret   string
	Database string
}

Target captures the RDS Data API connection coordinates resolved by the caller (command layer for TUI, HTTP handler for GUI).

Jump to

Keyboard shortcuts

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