Documentation
¶
Overview ¶
Package processors holds the hook a driver takes to adjust results on the way out of the connection: MySQLProcessor, MariaDBProcessor, PostgresProcessor and SQLiteProcessor over the shared Processor.
A processor exists so that three engines answering the same question three ways arrive at the caller as one answer: Postgres returns an inserted identifier as a row, MySQL reports it out of band, and both come back as an int64. Everything else it does is reshaping what a schema introspection query reported.
Where authorization is, and where it is not ¶
Not here. ProcessInsertGetID does run a statement, through the connection the builder is holding, and the Grant that allowed it was checked one layer up: a *query.Builder is reachable only from a repository that holds an auth.Grant and has already filtered by auth.Tenant(g), on reads exactly as on writes. A processor that took a Grant would be a second place to enforce authorization, and a second place for it to be forgotten.
Signatures ¶
An initialism is upper case: ProcessInsertGetID, MySQLProcessor, MariaDBProcessor.
- ProcessInsertGetID returns (int64, error); query.Processor declares the signature.
- The connection is asked for the identifier through LastInsertIDConnection, because query.connection is narrowed to running statements and holds no driver handle to reach through.
- ProcessColumns takes the CREATE TABLE statement as a variadic argument, because Go has no default argument and SQLite's is the one that reads it.
- A result row is a query.Record -- a map. The values are coerced on the way out, since a driver hands back a count as []byte or int64 depending on which one it is.
There is no SQL Server processor: it is a driver this ecosystem does not carry.
Index ¶
- type LastInsertIDConnection
- type MariaDBProcessor
- type MySQLProcessor
- func (p *MySQLProcessor) ProcessColumnListing(results []query.Record) []stringdeprecated
- func (p *MySQLProcessor) ProcessColumns(results []query.Record, sql ...string) []query.Record
- func (p *MySQLProcessor) ProcessForeignKeys(results []query.Record) []query.Record
- func (p *MySQLProcessor) ProcessIndexes(results []query.Record) []query.Record
- type PostgresProcessor
- func (p *PostgresProcessor) ProcessColumns(results []query.Record, sql ...string) []query.Record
- func (p *PostgresProcessor) ProcessForeignKeys(results []query.Record) []query.Record
- func (p *PostgresProcessor) ProcessIndexes(results []query.Record) []query.Record
- func (p *PostgresProcessor) ProcessInsertGetID(ctx context.Context, q *query.Builder, sql string, values []any, ...) (int64, error)
- func (p *PostgresProcessor) ProcessTypes(results []query.Record) []query.Record
- type Processor
- func (p *Processor) ProcessColumns(results []query.Record, sql ...string) []query.Record
- func (p *Processor) ProcessForeignKeys(results []query.Record) []query.Record
- func (p *Processor) ProcessIndexes(results []query.Record) []query.Record
- func (p *Processor) ProcessInsertGetID(ctx context.Context, q *query.Builder, sql string, values []any, ...) (int64, error)
- func (p *Processor) ProcessSchemas(results []query.Record) []query.Record
- func (p *Processor) ProcessSelect(q *query.Builder, results []query.Record) []query.Record
- func (p *Processor) ProcessTables(results []query.Record) []query.Record
- func (p *Processor) ProcessTypes(results []query.Record) []query.Record
- func (p *Processor) ProcessViews(results []query.Record) []query.Record
- type SQLiteProcessor
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type LastInsertIDConnection ¶
type LastInsertIDConnection interface {
// GetLastInsertID returns the identifier the engine assigned to the last
// inserted row. The sequence names the generator to ask, for an engine
// that has more than one.
GetLastInsertID(sequence string) (int64, error)
}
LastInsertIDConnection is the part of the connection ProcessInsertGetID needs beyond query.connection: the identifier the engine assigned to the row it just inserted.
query.connection is narrowed to running statements and has no such method, so a connection that can answer implements this and one that cannot says so rather than returning a zero that reads like an identifier.
type MariaDBProcessor ¶
type MariaDBProcessor struct {
MySQLProcessor
}
MariaDBProcessor is the Processor for MariaDB.
It adds nothing to MySQL's: MariaDB differs from MySQL in what it accepts, not in what it returns. It exists so that a connection wires a grammar and a processor by the same name, and so that the place to put the first difference already exists.
func NewMariaDBProcessor ¶
func NewMariaDBProcessor() *MariaDBProcessor
NewMariaDBProcessor creates a MariaDBProcessor.
type MySQLProcessor ¶
type MySQLProcessor struct {
Processor
}
MySQLProcessor is the Processor for MySQL.
There is one route to an inserted identifier here -- LastInsertIDConnection -- so the shared ProcessInsertGetID is already the right one and nothing is overridden.
func NewMySQLProcessor ¶
func NewMySQLProcessor() *MySQLProcessor
NewMySQLProcessor creates a MySQLProcessor.
func (*MySQLProcessor) ProcessColumnListing
deprecated
func (p *MySQLProcessor) ProcessColumnListing(results []query.Record) []string
ProcessColumnListing reduces a column listing to the column names.
Deprecated: use ProcessColumns, which reports the same columns along with their type, default and the rest of it.
func (*MySQLProcessor) ProcessColumns ¶
ProcessColumns normalises the columns of a column listing.
func (*MySQLProcessor) ProcessForeignKeys ¶
func (p *MySQLProcessor) ProcessForeignKeys(results []query.Record) []query.Record
ProcessForeignKeys normalises the columns of a foreign key listing.
func (*MySQLProcessor) ProcessIndexes ¶
func (p *MySQLProcessor) ProcessIndexes(results []query.Record) []query.Record
ProcessIndexes normalises the columns of an index listing.
type PostgresProcessor ¶
type PostgresProcessor struct {
Processor
}
PostgresProcessor is the Processor for Postgres: it reads back an inserted identifier from the returning clause, and turns the catalogue's one-letter codes into words.
Postgres reports an insert's identifier as a row rather than out of band, so ProcessInsertGetID runs the statement as a select -- against the write connection, because a replica has not seen the row yet. Everything else here is the schema introspection: pg_type stores a kind as "e" and a category as "n", and ProcessTypes, ProcessColumns, ProcessIndexes and ProcessForeignKeys spell those out so `aru db:show` reads the same whatever the engine.
func NewPostgresProcessor ¶
func NewPostgresProcessor() *PostgresProcessor
NewPostgresProcessor creates a PostgresProcessor.
func (*PostgresProcessor) ProcessColumns ¶
ProcessColumns normalises the columns of a column listing, splitting a generated column's expression out of its default.
func (*PostgresProcessor) ProcessForeignKeys ¶
func (p *PostgresProcessor) ProcessForeignKeys(results []query.Record) []query.Record
ProcessForeignKeys spells out the one letter referential actions for a foreign key's on-update and on-delete behavior.
func (*PostgresProcessor) ProcessIndexes ¶
func (p *PostgresProcessor) ProcessIndexes(results []query.Record) []query.Record
ProcessIndexes normalises the columns of an index listing.
func (*PostgresProcessor) ProcessInsertGetID ¶
func (p *PostgresProcessor) ProcessInsertGetID(ctx context.Context, q *query.Builder, sql string, values []any, sequence string) (int64, error)
ProcessInsertGetID runs an insert and returns the identifier the engine assigned to the new row.
PostgresGrammar compiles the insert with a returning clause, so the identifier comes back as a row and the statement runs as a select. It runs against the write connection, because a replica has not seen the row yet.
It takes no authorization credential and runs the statement it is handed: a caller that reaches this is below the authorization layer, not outside it. The credential was checked where the *query.Builder was obtained, and a second check here would be a second place to forget it.
func (*PostgresProcessor) ProcessTypes ¶
func (p *PostgresProcessor) ProcessTypes(results []query.Record) []query.Record
ProcessTypes spells out the one letter codes pg_type stores for a type's kind and category.
type Processor ¶
type Processor struct{}
Processor is the hook a driver takes to adjust results on the way out of the connection.
Almost every method is the identity, and that is the point: the processor is where an engine that resolves a question differently is made to resolve it the same. Postgres hands back an inserted identifier as a row; MySQL reports it out of band. Both arrive at the caller as an int64.
Where authorization is ¶
Nowhere here, and that is deliberate. ProcessInsertGetID does run a statement, through the connection the builder is holding, and the Grant that allowed it was checked one layer up: a *query.Builder is reachable only from a repository that holds an auth.Grant and has already filtered by auth.Tenant(g). A processor that took a Grant would be a second place to enforce authorization, which is a second place for it to be forgotten.
func (*Processor) ProcessColumns ¶
ProcessColumns is the identity here; a driver processor normalises the columns of a column listing.
The variadic argument is SQLiteProcessor's second parameter, the CREATE TABLE statement it has to read a collation out of. Go has no default argument, so every processor accepts it and only that one reads it.
func (*Processor) ProcessForeignKeys ¶
ProcessForeignKeys is the identity: only a driver processor normalises the columns of a foreign key listing.
func (*Processor) ProcessIndexes ¶
ProcessIndexes is the identity: only a driver processor normalises the columns of an index listing.
func (*Processor) ProcessInsertGetID ¶
func (p *Processor) ProcessInsertGetID(ctx context.Context, q *query.Builder, sql string, values []any, sequence string) (int64, error)
ProcessInsertGetID runs an insert and returns the identifier the engine assigned to the new row. Go initialisms are upper case throughout, hence ID rather than Id.
It returns an int64: query.Processor declares the signature, and an engine whose identifier is not a number is a repository's problem before it is a processor's.
It takes no authorization credential and runs the statement it is handed: a caller that reaches this is below the authorization layer, not outside it. The credential was checked where the *query.Builder was obtained, and a second check here would be a second place to forget it.
func (*Processor) ProcessSchemas ¶
ProcessSchemas normalises the columns of a schema listing.
func (*Processor) ProcessSelect ¶
ProcessSelect is the identity: select results need no adjustment.
func (*Processor) ProcessTables ¶
ProcessTables normalises the columns of a table listing.
func (*Processor) ProcessTypes ¶
ProcessTypes is the identity: only Postgres has types to spell out.
type SQLiteProcessor ¶
type SQLiteProcessor struct {
Processor
}
SQLiteProcessor is the Processor for SQLite.
SQLite reports less about a column than the other two do, so this is the one processor that reads the CREATE TABLE statement back: the collation and the expression of a generated column exist only in the text the table was declared with.
func NewSQLiteProcessor ¶
func NewSQLiteProcessor() *SQLiteProcessor
NewSQLiteProcessor creates a SQLiteProcessor.
func (*SQLiteProcessor) ProcessColumns ¶
ProcessColumns normalises the columns of a column listing, reading the collation and any generated expression out of the CREATE TABLE statement.
The optional argument is that statement; without it the collation and the generated expression come back nil.
func (*SQLiteProcessor) ProcessForeignKeys ¶
func (p *SQLiteProcessor) ProcessForeignKeys(results []query.Record) []query.Record
ProcessForeignKeys normalises the columns of a foreign key listing. SQLite does not name a foreign key, so the name is nil rather than invented.
func (*SQLiteProcessor) ProcessIndexes ¶
func (p *SQLiteProcessor) ProcessIndexes(results []query.Record) []query.Record
ProcessIndexes normalises the columns of an index listing.
SQLite reports the implicit index of a composite primary key alongside the key itself, so when more than one index calls itself primary the named one is dropped and the real key is kept.