Documentation
¶
Overview ¶
Package console holds the database commands: db, db:monitor, db:show, db:table, db:wipe and model:prune.
A command here is a console.Command value, not a class discovered by scanning a namespace: the listing and the compiler read the same slice, so a command missing from it does not exist and one in it with a broken Run does not build. Commands(deps) answers the slice.
The collaborators each command needs arrive in a Deps value rather than through a registry, which is also what makes every one of them runnable in a test with a fake resolver and no database.
Two commands do less than expected, on purpose ¶
`db` prints the client invocation instead of running it. Executing a binary this framework did not ship, with credentials, from a directory it does not control, is a supply chain problem wearing a convenience's clothes -- and printing it means the person's own client, history and .psqlrc are the ones that get used. The password is never printed; CommandEnvironment names the variable it should travel in.
`model:prune` prunes what the application registered rather than what a directory scan found. Go has no such scan -- a type nothing references is not in the binary -- and the register is also the list somebody can read to find out what the command is going to delete.
There is no dump command, for the reason `db` gives: it would shell out to pg_dump and mysqldump.
Reaching the schema catalogue is the Tables function on Deps, because the catalogue is the schema package's business and this one does not depend on it.
Index ¶
- Variables
- func CommandArguments(connection *database.Connection) []string
- func CommandEnvironment(connection *database.Connection) []string
- func Commands(deps Deps) []console.Command
- func DbCommand(deps Deps) console.Command
- func GetCommand(connection *database.Connection) string
- func MonitorCommand(deps Deps) console.Command
- func ProhibitDestructiveCommands(prohibit bool)
- func PruneCommand(deps Deps) console.Command
- func ShowCommand(deps Deps) console.Command
- func TableCommand(deps Deps) console.Command
- func WipeCommand(deps Deps) console.Command
- type Deps
- type TableInfo
Constants ¶
This section is empty.
Variables ¶
var DestructiveCommands = []string{
"db:wipe",
"migrate:fresh",
"migrate:refresh",
"migrate:reset",
"migrate:rollback",
}
DestructiveCommands are the five that throw data away.
They are named here rather than found by a marker on each command, because the list is the point: somebody reading it can see exactly what ProhibitDestructiveCommands turns off, and adding a sixth destructive command without adding it here is a mistake a reviewer can catch.
db:wipe drops every table. migrate:fresh drops them and migrates again. migrate:refresh rolls everything back and replays it. migrate:reset rolls everything back. migrate:rollback undoes the last batch.
Functions ¶
func CommandArguments ¶
func CommandArguments(connection *database.Connection) []string
CommandArguments returns the argument list for the engine's client, as a slice rather than one string.
GetCommand joins these for printing; this is what a caller that wants to run the client itself passes to exec.Command, where a joined string would have to be re-split -- and re-splitting a command line is how a database name with a space in it becomes two arguments.
func CommandEnvironment ¶
func CommandEnvironment(connection *database.Connection) []string
CommandEnvironment returns the variables the client reads a password out of, so it never reaches the process list.
It returns the names and not the values, because the caller has the connection and this package should not be copying secrets around to be helpful.
func Commands ¶
Commands builds every database command in this package against one Deps, so an application registers the whole group in a single call rather than naming each command and threading the same dependencies through all six.
The group is db, db:show, db:table, db:monitor, db:wipe and model:prune. The migration and seed commands are not here: they need a Migrator and a seeder registry this package does not have, and they are built by database/console/migrations and database/console/seeds.
func DbCommand ¶
DbCommand builds `aru db`, which prints the invocation of the engine's own CLI -- mysql, psql, sqlite3 -- with the password left in an environment variable so it does not reach the process list.
It prints the command instead of running it, and the difference is deliberate: a framework that execs a binary it did not ship, with credentials, from a directory it does not control, is a framework with a supply chain problem. Printing it means the person runs their own client, with their own history and their own .psqlrc.
func GetCommand ¶
func GetCommand(connection *database.Connection) string
GetCommand returns the client invocation for a connection.
It never prints the password: that is passed through the environment instead, because a printed command lands in a shell history file that several people can read.
func MonitorCommand ¶
MonitorCommand builds `aru db:monitor`.
It dispatches DatabaseBusy when a connection is over its threshold, which is the event an alerting listener subscribes to. The threshold has no default: a number that means "too many" is per database and per plan, and a framework guessing it would page somebody at three in the morning about a number it made up.
func ProhibitDestructiveCommands ¶
func ProhibitDestructiveCommands(prohibit bool)
ProhibitDestructiveCommands turns DestructiveCommands on or off.
It is the one line an application puts in its bootstrap so that the commands which throw data away cannot run in production:
if config.Env == "production" {
dbconsole.ProhibitDestructiveCommands(true)
}
It calls github.com/arandu-io/hesape/console.Prohibit on the five names, which is where that state already lives.
Go has no default arguments, so the argument is always given. Passing true is what a caller almost always means; passing false is how a test that needs to exercise one of the five turns the guard back off.
Why a list and not a flag on the command ¶
A destructive command that has to remember to declare itself is a command somebody will add without declaring. The list is read by a person, in one place, and the guard it feeds is checked by console.IsProhibited on the way in -- so the command still exists, still appears in the help, and refuses with a sentence instead of vanishing.
func PruneCommand ¶
PruneCommand builds `aru model:prune`.
There is no directory scan for prunable models -- a type nothing references is not in the binary -- so an application registers what it wants pruned, which is also the list somebody can read to find out what this command will delete.
func TableCommand ¶
TableCommand builds `aru db:table`, which prints one table's name, row count and size on disk.
The table is the first argument. Called with none, it lists the tables of the connection and asks which one, so the command is usable without knowing the schema by heart. It reads through Deps.Tables and fails with a message saying so when the application registered none.
Types ¶
type Deps ¶
type Deps struct {
// Connections is the resolver the commands read through.
Connections database.ConnectionResolverInterface
// Events is where DatabaseBusy is dispatched, for db:monitor.
Events database.Dispatcher
// Wipe drops every table on a connection. db:wipe refuses to run without
// it, because "drop everything" is not a capability a framework should
// assume it has.
Wipe func(ctx context.Context, connection string) error
// Tables answers the tables of a connection with their row counts, for
// db:show and db:table. It is a function because the catalogue query is
// the schema package's business and this package does not depend on it.
Tables func(ctx context.Context, connection string) ([]TableInfo, error)
// Prunables answers what model:prune should prune. Each entry prunes and
// answers how many rows it removed.
Prunables map[string]func(ctx context.Context) (int, error)
// Environment is what the destructive commands check before they run.
Environment string
}
Deps is what the database commands need: a connection resolver and a dispatcher.
They are a value the application builds where it wires everything else, which is also what makes every command below testable with a fake resolver and no database.
type TableInfo ¶
type TableInfo struct {
// Schema is the schema the table lives in, empty where the engine has none.
Schema string
// Name is the table name.
Name string
// Rows is the row count, or -1 when it was not asked for.
Rows int64
// Size is the table's size in bytes, or -1 when the engine does not say.
Size int64
}
TableInfo is one row of the db:show table listing: schema, name, row count and size, read off the schema builder.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package factories will hold make:factory, and holds nothing yet.
|
Package factories will hold make:factory, and holds nothing yet. |
|
Package migrations holds the eight migration commands as console.Command values, with the flags --database, --path, --pretend, --step, --batch, --seed and --force.
|
Package migrations holds the eight migration commands as console.Command values, with the flags --database, --path, --pretend, --step, --batch, --seed and --force. |
|
Package seeds holds db:seed and make:seeder.
|
Package seeds holds db:seed and make:seeder. |