processors

package
v0.25.1 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 6 Imported by: 0

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

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

func (p *MySQLProcessor) ProcessColumns(results []query.Record, sql ...string) []query.Record

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

func (p *PostgresProcessor) ProcessColumns(results []query.Record, sql ...string) []query.Record

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 NewProcessor

func NewProcessor() *Processor

NewProcessor creates a Processor.

func (*Processor) ProcessColumns

func (p *Processor) ProcessColumns(results []query.Record, sql ...string) []query.Record

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

func (p *Processor) ProcessForeignKeys(results []query.Record) []query.Record

ProcessForeignKeys is the identity: only a driver processor normalises the columns of a foreign key listing.

func (*Processor) ProcessIndexes

func (p *Processor) ProcessIndexes(results []query.Record) []query.Record

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

func (p *Processor) ProcessSchemas(results []query.Record) []query.Record

ProcessSchemas normalises the columns of a schema listing.

func (*Processor) ProcessSelect

func (p *Processor) ProcessSelect(q *query.Builder, results []query.Record) []query.Record

ProcessSelect is the identity: select results need no adjustment.

func (*Processor) ProcessTables

func (p *Processor) ProcessTables(results []query.Record) []query.Record

ProcessTables normalises the columns of a table listing.

func (*Processor) ProcessTypes

func (p *Processor) ProcessTypes(results []query.Record) []query.Record

ProcessTypes is the identity: only Postgres has types to spell out.

func (*Processor) ProcessViews

func (p *Processor) ProcessViews(results []query.Record) []query.Record

ProcessViews normalises the columns of a view listing.

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

func (p *SQLiteProcessor) ProcessColumns(results []query.Record, sql ...string) []query.Record

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.

Jump to

Keyboard shortcuts

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