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

config

package
v0.13.2 Latest Latest
Warning

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

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

Documentation

Index

Constants

View Source
const (

	// DefaultAIContextRows mirrors ai.DefaultContextRows. It is repeated
	// rather than imported so config stays a leaf package that every other
	// one can depend on.
	DefaultAIContextRows = 10

	// DefaultResultTabs is how many result tabs one connection's result set
	// holds when result_tabs is not set (see Config.ResultTabs), and
	// MaxResultTabs the most it may be set to. Each tab keeps a whole
	// result — up to max_rows rows — alive for as long as its query tab
	// lives, per connection that tab has visited, so the ceiling is there
	// to keep a typo (1000) from quietly pinning a lot of memory.
	DefaultResultTabs = 10
	MaxResultTabs     = 50

	// DefaultConnIdleTimeout is how long a pooled connection may sit unused
	// before the pool closes it (conn_idle_timeout). database/sql's own
	// default is forever, which keeps server-side backends — their memory and
	// a slot in the server's max_connections — alive for hours after the
	// last query. An hour is long enough that interactive use (run, read,
	// think, run again) never pays a reconnect, and short enough that a dbc
	// left open overnight gives its connections back. It is a ceiling, not a
	// keepalive: a server or proxy that cuts idle connections sooner still
	// does, and the drivers' liveness checks on checkout replace those
	// transparently (for Postgres, with db.pgShouldPing's help: pgx alone
	// skips the check within a second of the last checkout). The editor's
	// pinned session is checked out, never idle,
	// so this never expires it.
	DefaultConnIdleTimeout = time.Hour

	// DefaultConnectTimeout bounds opening a connection (connect_timeout):
	// the dial, the handshake and the first ping together. Without it an
	// unreachable host fails only at the OS's TCP connect timeout — over a
	// minute — while the UI shows "connecting…". Five seconds is ample for
	// any reachable server, including one across a VPN, and short enough that
	// a wrong host or a down VPN is reported while the user is still looking.
	DefaultConnectTimeout = 5 * time.Second
)
View Source
const (
	// DemoBytdb is the bytdb-backed demo, and the one active by default.
	DemoBytdb = "demo-bytdb"

	// DemoSQLite is the in-memory SQLite demo. It was plain "demo" before the
	// bytdb demo arrived; the engine suffix now names both the same way. The
	// shipped scripts name it directly — their ? placeholders are SQLite's, so
	// they could not run on the bytdb demo ($1) under any name.
	DemoSQLite = "demo-sqlite"
)

Names of the built-in demo connections. Both are registered when no config file is found, so the two embedded engines can be queried side by side without writing a config first.

View Source
const (
	TLSDisable    = "disable"
	TLSPrefer     = "prefer"
	TLSRequire    = "require"
	TLSVerifyCA   = "verify-ca"
	TLSVerifyFull = "verify-full"
)

TLS modes, as written in the tls key.

View Source
const DatabaseSep = "/"

DatabaseSep joins a configured connection's name to one of its server's databases, in a derived connection's name: "ProdDr/analytics".

A Postgres connection is bound to one database — every catalog the server has is per database, and there is no USE to move a session to another — so reaching a second database on the same host means opening a second pool. A MySQL pool is opened the same way, on the database its sidebar lists (see SupportsDatabases). Naming that pool "<base>/<database>" lets everything keyed by connection name (the Manager's pools and row counts, the pinned session, history, saved tabs, the web layout's per-connection keys) keep working with no second key, and a tab saved on a derived connection reopens on it after a restart, because the name alone says how to rebuild it.

View Source
const DefaultRunsKeep = 200

DefaultRunsKeep is how many records of each job and pipeline are kept when runs_keep does not say.

Variables

View Source
var ErrConnExists = errors.New("a connection by that name already exists")

ErrConnExists is AddConn refusing a name already in use: ConnByName would always find the first of two, so the second could never be reached.

View Source
var ErrConnNotFound = errors.New("no connection by that name")

ErrConnNotFound is ReplaceConn finding no connection by the old name — removed (in another window, say) since the caller looked it up.

TLSModes lists the modes in order of strictness, for messages and the web form's select.

Functions

func DefaultFilesDir added in v0.13.0

func DefaultFilesDir() string

DefaultFilesDir is the home directory, or "." (the working directory, as before files_dir) when there is none.

func DefaultJobsDir added in v0.13.0

func DefaultJobsDir() string

DefaultJobsDir is ~/.config/dbc/jobs; DefaultRunsDir ~/.config/dbc/runs.

func DefaultPipelinesDir added in v0.13.0

func DefaultPipelinesDir() string

DefaultPipelinesDir is where pipelines live when the config does not say.

func DefaultPluginsDir added in v0.13.0

func DefaultPluginsDir() string

DefaultPluginsDir is ~/.config/dbc/plugins.

func DefaultRunsDir added in v0.13.0

func DefaultRunsDir() string

func DefaultScriptsDir added in v0.9.0

func DefaultScriptsDir() string

DefaultScriptsDir is where scripts live when the config does not say: ~/.config/dbc/scripts, or the old cwd-relative "scripts" without a home.

func DemoBytdbPath

func DemoBytdbPath() (string, error)

DemoBytdbPath returns the file backing the built-in bytdb demo, creating its parent directory. It prefers the OS cache directory and falls back to the temp directory on systems where the cache directory is undefined (a bare container with no $HOME, say).

func DerivedName added in v0.3.0

func DerivedName(base, database string) string

DerivedName is the name of base's connection to database.

func ExpandDSN

func ExpandDSN(name, driver, dsn string) (string, []string)

ExpandDSN expands ${VAR} and $VAR in a DSN from the environment, as Load does for the file's connections. It does this itself rather than via os.ExpandEnv so that a typo'd ${PGPASS} comes back as a warning naming it instead of silently becoming "" and surfacing later as a baffling auth failure. name is the connection's, for the warning.

Each value is escaped for where it lands in the DSN of driver (any alias db.Driver accepts): inside a quoted Postgres value, in a URL's password, in a MySQL param — see dsnexpand.go. So a password kept in the environment may hold any character, as one typed into the DSN form's field may.

func ResolveFilesDir added in v0.13.0

func ResolveFilesDir(raw, base string) (string, []string)

ResolveFilesDir turns files_dir as written into the directory a relative file path is joined to, by ResolveScriptsDir's rules.

func ResolveJobsDir added in v0.13.0

func ResolveJobsDir(raw, base string) (string, []string)

ResolveJobsDir turns jobs_dir as written into the directory dbc reads.

func ResolvePipelinesDir added in v0.13.0

func ResolvePipelinesDir(raw, base string) (string, []string)

ResolvePipelinesDir turns pipelines_dir as written into the directory dbc reads, by ResolveScriptsDir's rules.

func ResolvePluginsDir added in v0.13.0

func ResolvePluginsDir(raw, base string) (string, []string)

ResolvePluginsDir turns plugins_dir as written into the directory dbc loads plugins from.

func ResolveRunsDir added in v0.13.0

func ResolveRunsDir(raw, base string) (string, []string)

ResolveRunsDir turns runs_dir as written into the directory dbc writes.

func ResolveScriptsDir added in v0.9.0

func ResolveScriptsDir(raw, base string) (string, []string)

ResolveScriptsDir turns scripts_dir as written into the directory dbc reads, by the rules above. base is the config file's directory ("" when there is no file, and then a relative value stays relative to cwd — it can only come from a test or a caller building a Config by hand). The warnings name unset ${VAR}s, as ExpandDSN's do.

func SavedDir added in v0.3.0

func SavedDir() string

SavedDir is the directory relative tls_* paths of a saved connection (one added in dbc web) resolve against: the saved-connections file's own, as a config file's resolve against its directory. "" when there is no home directory, which leaves them relative to the working directory.

func SavedFile

func SavedFile() string

SavedFile is where saved connections live, beside config.toml; "" when no home directory is known, and they then last only as long as a dbc web.

func SupportsDatabases added in v0.3.0

func SupportsDatabases(driver string) bool

SupportsDatabases reports whether a driver's connections can be derived onto another database of their server: Postgres, and MySQL (MariaDB too). Both tie what a connection's sidebar lists to the database its DSN names — Postgres because every catalog is per database, MySQL because dbc scopes its catalog queries to DATABASE() — so on both another database is another connection. MySQL could USE its way across instead, but a pool's connections are interchangeable and a USE would stick to only one of them; setting the database the pool dials with keeps every connection of it on the same one. SQLite and bytdb open one file, with no server to hold a second database.

db.HasDatabases (the database pickers) is this same set, so a picker never offers a database ConnByName could not derive.

func TildePath added in v0.9.0

func TildePath(p string) string

TildePath shortens a path under the home directory to "~/…" for display (a title, a log line), where the full /Users/name prefix is noise. Paths elsewhere come back unchanged; never pass the result to the filesystem.

Types

type Config

type Config struct {
	// ScriptsDir is where Go scripts live. Load leaves it absolute (see
	// ResolveScriptsDir in scripts.go): as written it is relative to the
	// config file, and absent it is ~/.config/dbc/scripts.
	ScriptsDir string `toml:"scripts_dir"`
	// PipelinesDir is where pipelines live (pipelines.go): absolute after
	// Load, ~/.config/dbc/pipelines when the file does not say.
	PipelinesDir string `toml:"pipelines_dir"`
	// JobsDir is where jobs live (jobs.go: DAGs of pipelines with
	// triggers), RunsDir where each run of a job or a pipeline leaves its
	// record; both absolute after Load, beside the scripts when the file
	// does not say.
	JobsDir string `toml:"jobs_dir"`
	RunsDir string `toml:"runs_dir"`
	// PluginsDir is where the user's pipeline plugins live (plugins.go:
	// Go files, each one kind of node), absolute after Load, beside the
	// scripts when the file does not say.
	PluginsDir string `toml:"plugins_dir"`
	// FilesDir is where a relative path in a pipeline's file node — and in
	// a script's s.Export or s.Path — resolves (files.go), whichever
	// process runs it: absolute after Load, the home directory when the
	// file does not say.
	FilesDir string `toml:"files_dir"`
	// RunsKeep is how many records of each job and of each pipeline are
	// kept, the oldest pruned after a run ends; 0 means DefaultRunsKeep.
	RunsKeep int `toml:"runs_keep"`
	MaxRows  int `toml:"max_rows"` // rows fetched from the server

	// PGBin is the directory holding PostgreSQL's client tools (pg_dump,
	// pg_restore) for dumps — `dbc dump` and both UIs' "Dump database…".
	// Empty means look for them (pgdump.Locate). Resolved like scripts_dir:
	// absolute after Load, relative to the config file as written.
	PGBin string `toml:"pg_bin"`

	// MaxDisplayRows caps how many of those rows the TUI table renders. It is
	// separate from MaxRows because the two are limited by different things:
	// fetching more is a question of memory and patience, rendering more costs
	// a widget per value and shows up as a sluggish scroll. Raising max_rows
	// for the sake of an export should not make the table crawl. Zero means no
	// display cap.
	MaxDisplayRows int `toml:"max_display_rows"`

	// ResultTabs caps the tabs in one connection's result set: each query
	// tab keeps a result set per connection it has been on, and a run
	// lands in the set's current tab, or in a new one when that tab is
	// pinned. Past the cap the oldest unpinned tab is dropped. Unset is
	// DefaultResultTabs; Load keeps it within 1…MaxResultTabs. Read it
	// through ResultTabLimit, which also covers a Config built in code.
	ResultTabs int `toml:"result_tabs"`

	// The AI assistant (package ai). AIAgent picks the ACP backend —
	// "copilot" (the default), "claude" or "gemini"; AIModel is a preferred
	// model id, applied when the agent offers it. AIContextRows caps how many
	// result rows go with a question on connections that allow rows at all
	// (ai_rows); 0 sends none, and unset means ai.DefaultContextRows.
	AIAgent       string `toml:"ai_agent"`
	AIModel       string `toml:"ai_model"`
	AIContextRows int    `toml:"ai_context_rows"`

	// ConnIdleTimeout is how long a pooled connection may sit idle before it
	// is closed; see DefaultConnIdleTimeout. Written as a duration string in
	// the file ("30m", "2h"); 0 keeps idle connections open indefinitely, as
	// database/sql does by default. It applies to every connection — it is a
	// question of how long dbc sits idle, not of which database it talks to.
	ConnIdleTimeout time.Duration `toml:"conn_idle_timeout"`

	// ConnectTimeout caps opening a connection; see DefaultConnectTimeout.
	// A duration string in the file ("10s"); 0 sets no limit of dbc's own,
	// leaving it to the driver (a DSN's own connect_timeout, say) and the OS.
	// A DSN-level timeout still applies either way — whichever is shorter
	// wins. Global for the same reason as ConnIdleTimeout.
	ConnectTimeout time.Duration `toml:"connect_timeout"`

	// PlanTheme is the palette of the plan pictures the shell and the TUI
	// draw — `dbc explain -t pdf|jpeg|png` and the TUI's Save as PDF /
	// JPEG, and the schema diagrams of `dbc erd -t png|jpeg` and the TUI's
	// Diagram items: "dark" (the default, dbc's own slate) or "light" (paper, kinder
	// to a printer). Load normalizes it to one of the two, so readers can
	// hand it to theme.ByName without a second error to handle. dbc web
	// ignores it: its files follow the light or dark the view is wearing.
	// A string rather than a theme.Palette so config stays a leaf package.
	PlanTheme string `toml:"plan_theme"`

	DefaultConnection string `toml:"default_connection"`

	// Connections is written freely while the config is being built (Load,
	// the demo pruning, an ad-hoc --dsn), when nothing else can see it. Once
	// something may run beside a change — dbc web adding a connection while
	// its tabs connect and run — the change goes through AddConn/RemoveConn/
	// ReplaceConn and every reader through Conns/ConnByName, which take connMu.
	//
	// The writers are copy-on-write: AddConn, RemoveConn and ReplaceConn
	// build a new slice rather than edit the old one in place, so a slice a
	// reader got from Conns (or a range over the field that began before the
	// change) never sees an element change under it.
	Connections []Connection `toml:"connection"`

	Path string `toml:"-"` // file the config was loaded from ("" if none)
	Demo bool   `toml:"-"` // true when running with the built-in demo connection

	// Warnings are load-time findings worth telling the user about but not
	// worth refusing to start over, e.g. a DSN referencing an unset env var.
	Warnings []string `toml:"-"`
	// contains filtered or unexported fields
}

Config is the application configuration.

func Load

func Load(explicit string) (*Config, error)

Load reads the config from an explicit path, or searches ./dbc.toml then ~/.config/dbc/config.toml. With no config anywhere, it falls back to the built-in demo connections so the app is usable immediately.

func LoadDemo

func LoadDemo(explicit string, demo DemoEngine) (*Config, error)

LoadDemo is Load with a say in which built-in demo connection starts out active. The choice only matters when there is no config file: a real config names its own default_connection.

func (*Config) AddConn

func (c *Config) AddConn(cn Connection) error

AddConn appends a connection at runtime. The name must be new.

func (*Config) ConnByName

func (c *Config) ConnByName(name string) (Connection, bool)

ConnByName finds a connection config by name. A name no connection has exactly, of the form "<base>/<database>" where base is a Postgres or MySQL connection (SupportsDatabases), is that connection derived onto database (see DatabaseSep): a copy with Name set to name and Base and Database filled in.

The exact match is tried first, so a configured connection whose own name contains a "/" is still found as itself. Then the name is matched against each such connection's name plus the separator, rather than split at a "/": a quoted Postgres database name may contain one, and so may a connection's name. Of two bases that both match ("a" and "a/b" for "a/b/c"), the longer wins, as the more specific.

func (*Config) ConnOrder added in v0.9.0

func (c *Config) ConnOrder(first string) []string

ConnOrder lists the connection names in the order a new script's template wants them (scripts.Fill puts the first in "{{conn}}" and the second in "{{conn2}}"): first, when it names a connection (the tab's own, say); the default connection; then the rest in config order. Each name once. dbc web and the TUI both fill templates through it, so a script started from either names the same connections.

func (*Config) Conns

func (c *Config) Conns() []Connection

Conns is the connection list as it stands, for a reader that may run beside AddConn/RemoveConn. The slice is the one the writers replace wholesale, never edit, so it is safe to keep and range without the lock — callers must not modify it.

func (*Config) FindJob added in v0.13.0

func (c *Config) FindJob(arg string) (JobRef, error)

FindJob resolves ARG as FindPipeline does: an existing file path, then JobsDir/ARG and ARG.json, then the built-in example.

func (*Config) FindPipeline added in v0.13.0

func (c *Config) FindPipeline(arg string) (PipelineRef, error)

FindPipeline resolves ARG as FindScript does: an existing file path, then PipelinesDir/ARG and ARG.json, then the built-in example.

func (*Config) FindScript added in v0.9.0

func (c *Config) FindScript(arg string) (ScriptRef, error)

FindScript turns the argument of `dbc script ARG` into a script to run:

ARG names an existing file (as a path from cwd) ─► that file, as before
ARG has no path separator ─► ScriptsDir/ARG, then ScriptsDir/ARG.go,
                             then the built-in example ARG, ARG.go
otherwise ─► an error naming every place looked

A file in cwd wins over a script of the same name so that every command line that worked before keeps running the same file; the lookup only adds meaning to arguments that used to fail. The examples come last for the same reason: a user's own loop_params.go (likely an edited copy of the sample) is the one they mean.

func (*Config) LoadSaved

func (c *Config) LoadSaved(path string, knownDriver func(string) bool)

LoadSaved merges the saved connections at path into c, after what c already holds, recording anything skipped in c.Warnings. A file that cannot be read or parsed is a warning too, not a failure: the config file's connections still work, and refusing to start over a stray character in a file dbc wrote would be out of proportion. See MergeSaved for knownDriver.

A DSN found plain in the file that belongs encrypted — the file was written by a dbc from before encryption, or by hand — is encrypted here, by rewriting the file through the usual locked edit, rather than left until the next add or edit, which may be months away. A rewrite that fails is a warning, and the next start tries again; the connections are listed either way.

Call it once c is complete (after Load, the demos and any ad-hoc connection), before anything else can see c.

func (*Config) MergeSaved

func (c *Config) MergeSaved(saved []SavedConn, knownDriver func(string) bool) []string

MergeSaved adds saved connections to c, marked Web, and returns warnings for the ones it skips; it does not add them to c.Warnings (dbc web also merges the entries it moves from its old store, and logs them itself).

Skipped, and left in the file for the user to sort out:

  • an entry with no name or no driver (a hand edit gone wrong);
  • a name c already has — the config file's word wins, it being the user's deliberate one where this is only what was once typed in a form; so does the first of two saved entries by one name;
  • a driver knownDriver rejects. config cannot know the drivers itself (it is a leaf; db registers them), so the caller passes db's check. nil accepts every driver, and an unknown one fails at connect;
  • TLS settings TLSOpts.Check refuses. Skipped rather than merged without them: a connection that was meant to verify its server must not quietly connect in plaintext instead.

func (*Config) RemoveConn

func (c *Config) RemoveConn(name string) bool

RemoveConn drops a connection at runtime, reporting whether there was one by that name. A default_connection naming it is left alone: the lookups that honor it (workspace.New, dbc web's defaultConn) already fall back to the first connection when it names nothing.

func (*Config) ReplaceConn

func (c *Config) ReplaceConn(old string, cn Connection) error

ReplaceConn swaps the connection named old for cn, in place: the entry keeps its position, so an edit does not move it down the sidebar. cn may carry a new name; ErrConnExists refuses one another connection already has. Doing the lookup, the clash check and the swap under one lock is what makes two windows editing (or one editing while another removes) safe: the second of them fails here instead of leaving two entries by one name or resurrecting a removed one.

func (*Config) ResultTabLimit added in v0.9.0

func (c *Config) ResultTabLimit() int

ResultTabLimit is how many tabs one connection's result set may hold: ResultTabs, or DefaultResultTabs for a Config that never went through Load (a test's, an ad-hoc one) and so left it zero.

type Connection

type Connection struct {
	Name   string `toml:"name"`
	Driver string `toml:"driver"` // postgres | mysql | sqlite | bytdb
	DSN    string `toml:"dsn"`    // env vars are expanded, e.g. ${PGPASS}

	// TLSOpts holds the tls, tls_ca, tls_cert and tls_key keys: TLS for
	// postgres and mysql, one spelling for both — see tls.go. Embedded
	// untagged so the keys sit flat beside dsn. Load leaves the paths
	// absolute (ExpandTLS), so the db package never has to know which file
	// they were written in.
	TLSOpts

	// Migrations is the directory `dbc migrate` reads for this connection,
	// relative to the working directory. Per connection rather than global
	// because a config typically lists several databases and each has its
	// own schema. Empty means the -dir flag (or ".") decides.
	Migrations string `toml:"migrations"`

	// AIRows lets the AI assistant see this connection's result ROWS (up to
	// ai_context_rows of them). Off by default and per connection, because
	// rows are the database's contents and sending them to a hosted model is
	// a decision about that data: fine for a scratch database, not
	// something a production connection should do because a global switch
	// was flipped. The query text and errors go regardless — see package ai.
	AIRows bool `toml:"ai_rows"`

	// Demo marks a built-in demo connection, the only kind db.Manager seeds
	// with the demo cats table when it opens it. Set by demoFallback alone,
	// never read from a file: seeding runs CREATE TABLE and DELETE FROM cats,
	// so it must not be possible to switch on for a real database. It is a
	// per-connection flag rather than Config.Demo because a demo config can
	// also carry the ad-hoc --dsn connection, which is the user's database.
	Demo bool `toml:"-"`

	// Web marks a connection added from inside dbc — dbc web's browser UI
	// or the TUI's connection form (package connedit) — and kept in the
	// saved-connections file (connections.toml, see SavedStore), not in the
	// config file. Never read from a file's key — MergeSaved sets it — so
	// both UIs can tell which ones they may edit or remove: the config file's
	// connections are the file's to change. Every dbc merges the saved ones,
	// so the TUI and headless runs list them too.
	Web bool `toml:"-"`

	// Base and Database describe a connection derived from a configured
	// one: the same server, credentials and TLS, opened on another database
	// of that server. ConnByName makes one up for a name of the form
	// "<base>/<database>" (see DatabaseSep); none is ever stored, in the
	// config or the saved-connections file. Database overrides whatever
	// database the DSN names when the pool is opened (db.openPool); "" keeps
	// the DSN's. Both are "" on a configured connection.
	Base     string `toml:"-"`
	Database string `toml:"-"`
}

Connection describes one database host connection.

type DemoEngine

type DemoEngine string

DemoEngine names which built-in demo connection starts out active. Both connections exist either way — this only picks the default.

const (
	DemoDefault      DemoEngine = "" // same as DemoEngineBytdb
	DemoEngineBytdb  DemoEngine = "bytdb"
	DemoEngineSQLite DemoEngine = "sqlite"
)

func ParseDemoEngine

func ParseDemoEngine(s string) (DemoEngine, error)

ParseDemoEngine resolves a -demo flag or $DBC_DEMO value. An empty string is the default (bytdb); anything unrecognized is an error rather than a silent fallback, because silently ignoring it would leave the user staring at the engine they just asked not to use.

type JobRef added in v0.13.0

type JobRef struct {
	Path    string
	Example *scripts.Job
}

JobRef is what the argument of `dbc job run ARG` names: a file on disk, or one of the samples built into the binary.

func (JobRef) FileName added in v0.13.0

func (r JobRef) FileName() string

FileName is the job's file name ("nightly.json"), however it was found.

func (JobRef) Label added in v0.13.0

func (r JobRef) Label() string

Label names the job in messages: the file's path, or "example:NAME.json".

func (JobRef) Source added in v0.13.0

func (r JobRef) Source() (string, error)

Source is the job's text.

type PipelineRef added in v0.13.0

type PipelineRef struct {
	Path    string
	Example *scripts.Pipeline
}

PipelineRef is what the argument of `dbc pipeline run ARG` names: a file on disk, or one of the samples built into the binary.

func (PipelineRef) Label added in v0.13.0

func (r PipelineRef) Label() string

Label names the pipeline in messages: the file's path, or "example:NAME.json".

func (PipelineRef) Source added in v0.13.0

func (r PipelineRef) Source() (string, error)

Source is the pipeline's text.

type SavedConn

type SavedConn struct {
	Name   string `toml:"name"`
	Driver string `toml:"driver"`
	DSN    string `toml:"dsn"` // as typed: ${VAR}s unexpanded
	// TLSOpts is Connection.TLSOpts, with its paths as typed too: ${VAR}s
	// unexpanded and a relative path left relative (to SavedDir). Each
	// process resolves them as it merges the entry, as it does the DSN.
	TLSOpts
	// AIRows is Connection.AIRows: the assistant may see result rows.
	AIRows bool `toml:"ai_rows"`
	// Added orders the sidebar in dbc web (after the config file's). It is
	// kept across an edit so an edited entry does not move.
	Added time.Time `toml:"added"`
}

SavedConn is one connection in the saved-connections file.

func ReadSaved

func ReadSaved(path string) ([]SavedConn, error)

ReadSaved reads the saved connections at path, in file order, their DSNs decrypted (secret.go). A missing file, or path == "", is none and no error: most users never add one.

type SavedStore

type SavedStore struct {
	// contains filtered or unexported fields
}

SavedStore is the writer of the saved-connections file, for dbc web: each change is a locked read-modify-write of the whole file, so it always starts from what is on disk — another dbc web's change, or a hand edit, included — rather than from what this process read at startup.

With path == "" (no home directory) it keeps the list in memory, lasting as long as the process, and callers do not branch on which kind they have.

func OpenSaved

func OpenSaved(path string) *SavedStore

OpenSaved returns the store for path. Nothing is read or created until the first call.

func (*SavedStore) Add

func (s *SavedStore) Add(c SavedConn) error

Add appends a connection. A name the file already has is ErrConnExists — another dbc web may have added it since this one started — rather than a replacement. A zero Added is now.

func (*SavedStore) Delete

func (s *SavedStore) Delete(name string) error

Delete removes a connection. A missing one is success: the caller wanted it gone.

func (*SavedStore) Get

func (s *SavedStore) Get(name string) (SavedConn, bool, error)

Get finds one saved connection by name.

func (*SavedStore) List

func (s *SavedStore) List() ([]SavedConn, error)

List returns the saved connections, in file order.

func (*SavedStore) Path

func (s *SavedStore) Path() string

Path is the file; "" for a memory-only store.

func (*SavedStore) Persistent

func (s *SavedStore) Persistent() bool

Persistent reports whether changes reach a file.

func (*SavedStore) Update

func (s *SavedStore) Update(old string, c SavedConn) error

Update replaces the connection named old with c, in place (the file's order is the sidebar's), keeping old's Added. c may carry a new name; one another entry has is ErrConnExists. A missing old is ErrConnNotFound: it was removed meanwhile, and writing c would bring it back.

type ScriptRef added in v0.9.0

type ScriptRef struct {
	Path    string           // the file to run or check
	Example *scripts.Example // the built-in sample, with its source
}

ScriptRef is what the argument of `dbc script ARG` names: a file on disk, or (when no file matched) one of the samples built into the binary. Exactly one of Path and Example is set.

func (ScriptRef) Label added in v0.9.0

func (r ScriptRef) Label() string

Label names the script in messages and in --check's compiler lines: the file's path, or "example:NAME.go" for a built-in sample. A sample has no path, and its bare name would read as a file in the cwd.

func (ScriptRef) Source added in v0.9.0

func (r ScriptRef) Source() (string, error)

Source is the script's text: the file, read now, or the sample's.

type TLSOpts added in v0.3.0

type TLSOpts struct {
	TLS     string `toml:"tls,omitempty" json:"tls,omitempty"`           // a mode above; "" leaves TLS to the DSN
	TLSCA   string `toml:"tls_ca,omitempty" json:"tls_ca,omitempty"`     // PEM file of CA certificates to trust
	TLSCert string `toml:"tls_cert,omitempty" json:"tls_cert,omitempty"` // PEM client certificate, for servers that ask for one
	TLSKey  string `toml:"tls_key,omitempty" json:"tls_key,omitempty"`   // its PEM private key
	// TLSKeyPassword is "${VAR}" (or "$VAR"): the environment variable
	// holding tls_key's passphrase, when the key is encrypted. The
	// reference, never the passphrase — see "AN ENCRYPTED tls_key" above.
	TLSKeyPassword string `toml:"tls_key_password,omitempty" json:"tls_key_password,omitempty"`
}

TLSOpts is a connection's TLS settings. It is embedded (untagged) in Connection and SavedConn, so the TOML keys sit flat beside dsn in both files — a saved entry can still be copied into config.toml as it is. The JSON tags are dbc web's: its connection form and list embed it the same way. None of it is secret (paths, not the keys themselves), so unlike the DSN it does go back to the browser.

func ExpandTLS added in v0.3.0

func ExpandTLS(name string, t TLSOpts, base string) (TLSOpts, []string)

ExpandTLS returns t with its file paths made absolute: ${VAR} and $VAR expanded from the environment (as ExpandDSN does, with a warning for an unset one), a leading ~/ taken as the home directory, and a relative path joined to base — the directory of the file that defines the connection.

Relative to that file, not to the working directory: dbc is started from wherever the user happens to be (a project for its scripts, a migrations folder), and "certs/ca.pem" written next to config.toml should mean the same file every time. base "" leaves a relative path relative to the working directory — the ad-hoc --tls-* flags, typed in the shell, mean that. name is the connection's, for the warnings.

func (*TLSOpts) Check added in v0.3.0

func (t *TLSOpts) Check() error

Check normalizes the mode's case and turns away settings that cannot be what was meant. Every rule here fails closed: a typo in a security setting must not become "no TLS".

  • an unknown mode ("verify_full", "true") is refused rather than read as unset, which would fall back to the DSN — often plaintext;
  • a CA or certificate with no mode is refused: whether it was meant to verify or merely to be offered cannot be guessed;
  • so are files beside tls = "disable", which would never be read;
  • a client certificate needs its key and the other way round;
  • tls_key_password must be an environment reference, and needs a tls_key to unlock. A literal is refused rather than used: accepting it would leave a passphrase in a plain-text file, and in every browser dbc web shows the connection to.

func (TLSOpts) KeyPasswordVar added in v0.3.0

func (t TLSOpts) KeyPasswordVar() string

KeyPasswordVar is the name of the environment variable tls_key_password refers to, or "" when there is none — or when it is not a reference, which Check refuses.

func (TLSOpts) Set added in v0.3.0

func (t TLSOpts) Set() bool

Set reports whether any TLS key is given.

Jump to

Keyboard shortcuts

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