Documentation
¶
Index ¶
- Variables
- func JoinColumnName(cns []ColumnName, format string, sep string) string
- func MakeErrSQLRow(err error) sql.Row
- func MakeRowsIterator[T any](rows Rows, mapper RowMapper[T]) iterkit.ErrSeq[T]
- func QueryMany[T any](c Queryable, ctx context.Context, mapper RowMapper[T], query string, ...) (iterkit.ErrSeq[T], error)
- type ColumnName
- type Connection
- type ConnectionAdapter
- func (c ConnectionAdapter[DB, TX]) BeginTx(ctx context.Context) (context.Context, error)
- func (c ConnectionAdapter[DB, TX]) Close() error
- func (c ConnectionAdapter[DB, TX]) CommitTx(ctx context.Context) error
- func (c ConnectionAdapter[DB, TX]) ExecContext(ctx context.Context, query string, args ...any) (Result, error)
- func (c ConnectionAdapter[DB, TX]) LookupTx(ctx context.Context) (*TX, bool)
- func (c ConnectionAdapter[DB, TX]) QueryContext(ctx context.Context, query string, args ...any) (Rows, error)
- func (c ConnectionAdapter[DB, TX]) QueryRowContext(ctx context.Context, query string, args ...any) Row
- func (c ConnectionAdapter[DB, TX]) RollbackTx(ctx context.Context) error
- type DTO
- type DTOJSON
- type MapScan
- type Mapping
- type MigrationStep
- type QueryArgs
- type Queryable
- type QueryableAdapter
- type Result
- type Row
- type RowMapper
- type Rows
- type Scanner
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ContextSQLTxOptions contextkit.ValueHandler[ctxKeyTxOptions, *sql.TxOptions]
Functions ¶
func JoinColumnName ¶
func JoinColumnName(cns []ColumnName, format string, sep string) string
Example ¶
package main import ( "go.llib.dev/frameless/pkg/flsql" ) func main() { _ = flsql.JoinColumnName([]flsql.ColumnName{"foo", "bar", "baz"}, "%q", ", ") // `"foo", "bar", "baz"` }
Output:
func MakeErrSQLRow ¶
func MakeRowsIterator ¶ added in v0.285.0
MakeRowsIterator allow you to use the same iterator pattern with sql.Rows structure. it allows you to do dynamic filtering, pipeline/middleware pattern on your sql results by using this wrapping around it. it also makes testing easier with the same Interface interface.
Types ¶
type ColumnName ¶
type ColumnName string
func SplitArgs ¶
func SplitArgs(cargs map[ColumnName]any) ([]ColumnName, []any)
type Connection ¶
type Connection interface { comproto.OnePhaseCommitProtocol Queryable io.Closer }
Connection represent an open connection. Connection will respect the transaction state in the received context.Context.
type ConnectionAdapter ¶
type ConnectionAdapter[DB, TX any] struct { // DB is the underlying Database type to access. // It is ideal if ConnectionAdapter used as the Connection type implementation, but you need access to not exposed functionalities. // // type Connection flsql.ConnectionAdapter[*sql.DB, *sql.Tx] // DB *DB // TxAdapter provides the mapping for a native driver specific TX type to be usable as a Queryable. TxAdapter func(tx *TX) Queryable // DBAdapter provides the mapping for a native driver specific DB type to be usable as a Queryable. DBAdapter func(db *DB) Queryable // Begin is a function that must create a new transaction that is also a connection. Begin func(ctx context.Context, db *DB) (*TX, error) // Commit is a function that must commit a given transaction. Commit func(ctx context.Context, tx *TX) error // Rollback is a function that must rollback a given transaction. Rollback func(ctx context.Context, tx *TX) error // OnClose [optional] is used to implement the io.Closer. // If The ConnectionAdapter needs to close something, // then this function can be used for that. // // default: DB.Close() OnClose func() error // ErrTxDone is the error returned when the transaction is already finished. // ErrTxDone is an optional field. // // default: sql.ErrTxDone ErrTxDone error }
ConnectionAdapter is generic implementation to handle query interactions which are aware of trasnactions within the context.
Example:
type Connection = flsql.ConnectionAdapter[*sql.DB, *sql.Tx]
Example ¶
package main import ( "context" "database/sql" "os" "go.llib.dev/frameless/pkg/flsql" ) func main() { db, err := sql.Open("dbname", os.Getenv("DATABASE_URL")) if err != nil { panic(err) } _ = flsql.ConnectionAdapter[sql.DB, sql.Tx]{ DB: db, DBAdapter: flsql.QueryableSQL[*sql.DB], TxAdapter: flsql.QueryableSQL[*sql.Tx], Begin: func(ctx context.Context, db *sql.DB) (*sql.Tx, error) { // TODO: integrate begin tx options return db.BeginTx(ctx, nil) }, Commit: func(ctx context.Context, tx *sql.Tx) error { return tx.Commit() }, Rollback: func(ctx context.Context, tx *sql.Tx) error { return tx.Rollback() }, } }
Output:
func SQLConnectionAdapter ¶
SQLConnectionAdapter is a built-in ConnectionAdapter usage for the stdlib sql.DB/sql.Tx. This can be used with any sql driver that integartes with the sql stdlib.
Example ¶
package main import ( "database/sql" "os" "go.llib.dev/frameless/pkg/flsql" ) func main() { db, err := sql.Open("dbname", os.Getenv("DATABASE_URL")) if err != nil { panic(err) } _ = flsql.SQLConnectionAdapter(db) }
Output:
func (ConnectionAdapter[DB, TX]) Close ¶
func (c ConnectionAdapter[DB, TX]) Close() error
func (ConnectionAdapter[DB, TX]) CommitTx ¶
func (c ConnectionAdapter[DB, TX]) CommitTx(ctx context.Context) error
func (ConnectionAdapter[DB, TX]) ExecContext ¶
func (ConnectionAdapter[DB, TX]) LookupTx ¶ added in v0.248.0
func (c ConnectionAdapter[DB, TX]) LookupTx(ctx context.Context) (*TX, bool)
func (ConnectionAdapter[DB, TX]) QueryContext ¶
func (ConnectionAdapter[DB, TX]) QueryRowContext ¶
func (ConnectionAdapter[DB, TX]) RollbackTx ¶
func (c ConnectionAdapter[DB, TX]) RollbackTx(ctx context.Context) error
type DTO ¶ added in v0.236.0
DTO (Data Transfer Object) is an object used to transfer data between the database and your application. It acts as a bridge between the entity field types in your application and the table column types in your database, to making it easier to map data between them. This helps keep the data structure consistent when passing information between layers or systems.
type DTOJSON ¶ added in v0.244.0
func (*DTOJSON[T]) MarshalJSON ¶ added in v0.244.0
func (*DTOJSON[T]) UnmarshalJSON ¶ added in v0.244.0
type Mapping ¶
type Mapping[ENT, ID any] struct { // TableName is the name of the table in the database. TableName string // ToQuery suppose to return back with the column names that needs to be selected from the table, // and the corresponding scan function that // ctx enables you to accept custom query instructions through the context if you require that. ToQuery func(ctx context.Context) ([]ColumnName, MapScan[ENT]) // QueryID will convert an ID into query components—specifically, // column names and their corresponding values—that represent the ID in an SQL WHERE statement. // If ID is nil, then QueryID func(id ID) (QueryArgs, error) // ToArgs converts an entity pointer into a list of query arguments for CREATE or UPDATE operations. // It must handle empty or zero values and still return a valid column statement. ToArgs func(ENT) (QueryArgs, error) // Prepare is an optional field that allows you to configure an entity prior to crud.Create call. // This is a good place to add support in your Repository implementation for custom ID injection or special timestamp value arrangement. // // To have this working, the user of Mapping needs to call Mapping.OnPrepare method within in its crud.Create method implementation. Prepare func(context.Context, *ENT) error // ID [optional] is a function that allows the ID lookup from an entity. // The returned ID value will be used to Lookup the ID value, or to set a new ID value. // Mapping will panic if ID func is provided, but returns a nil, as it is considered as implementation error. // // Example implementation: // // flsql.Mapping[Foo, FooID]{..., ID: func(v Foo) *FooID { return &v.ID }} // // default: extid.Lookup, extid.Set, which will use either the `ext:"id"` tag, or the `ENT.ID()` & `ENT.SetID()` methods. ID extid.Accessor[ENT, ID] }
Mapping is a table mapping
Example ¶
package main import ( "context" "go.llib.dev/frameless/pkg/flsql" ) func main() { type ExampleEntity struct { ID int64 Col1 int Col2 string Col3 bool } _ = flsql.Mapping[ExampleEntity, int64]{ TableName: `"public"."entities"`, QueryID: func(id int64) (flsql.QueryArgs, error) { return flsql.QueryArgs{"entity_id": id}, nil }, ToArgs: func(ee ExampleEntity) (flsql.QueryArgs, error) { return flsql.QueryArgs{ "entity_id": ee.ID, "col1": ee.Col1, "col2": ee.Col2, "col3": ee.Col3, }, nil }, ToQuery: func(ctx context.Context) ([]flsql.ColumnName, flsql.MapScan[ExampleEntity]) { return []flsql.ColumnName{"entity_id", "col1", "col2", "col3"}, func(e *ExampleEntity, s flsql.Scanner) error { return s.Scan(&e.ID, &e.Col1, &e.Col2, &e.Col3) } }, } }
Output:
type MigrationStep ¶ added in v0.238.0
type MigrationStep[C Queryable] struct { Up func(C, context.Context) error UpQuery string Down func(C, context.Context) error DownQuery string }
func (MigrationStep[C]) MigrateDown ¶ added in v0.238.0
func (m MigrationStep[C]) MigrateDown(c C, ctx context.Context) error
type QueryArgs ¶ added in v0.238.0
type QueryArgs map[ColumnName]any
type Queryable ¶
type Queryable interface { ExecContext(ctx context.Context, query string, args ...any) (Result, error) QueryContext(ctx context.Context, query string, args ...any) (Rows, error) QueryRowContext(ctx context.Context, query string, args ...any) Row }
func QueryableSQL ¶
func QueryableSQL[SQLQ sqlQueryable](q SQLQ) Queryable
type QueryableAdapter ¶
type QueryableAdapter struct { ExecFunc func(ctx context.Context, query string, args ...any) (Result, error) QueryFunc func(ctx context.Context, query string, args ...any) (Rows, error) QueryRowFunc func(ctx context.Context, query string, args ...any) Row }
func (QueryableAdapter) ExecContext ¶
func (QueryableAdapter) QueryContext ¶
func (QueryableAdapter) QueryRowContext ¶
type Rows ¶
type Rows interface { // Closer is the interface that wraps the basic Close method. io.Closer // Err returns any error that occurred while reading. Err() error // Next prepares the next row for reading. It returns true if there is another // row and false if no more rows are available. It automatically closes rows // when all rows are read. Next() bool // Scan reads the values from the current row into dest values positionally. // dest can include pointers to core types, values implementing the Scanner // interface, and nil. nil will skip the value entirely. It is an error to // call Scan without first calling Next() and checking that it returned true. Scan(dest ...any) error }