flsql

package
v0.235.0 Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2024 License: Apache-2.0 Imports: 13 Imported by: 3

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func JoinColumnName

func JoinColumnName(cns []ColumnName, sep string, format string) string

func MakeErrSQLRow

func MakeErrSQLRow(err error) sql.Row

func MakeSQLRowsIterator

func MakeSQLRowsIterator[T any](rows sqlRows, mapper SQLRowMapper[T]) iterators.Iterator[T]

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
	// BeginFunc is a function that must create a new transaction that is also a connection.
	BeginFunc func(ctx context.Context) (TX, error)
	// CommitFunc is a function that must commit a given transaction.
	CommitFunc 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],

		BeginFunc: func(ctx context.Context) (*sql.Tx, error) {
			// TODO: integrate begin tx options
			return db.BeginTx(ctx, nil)
		},

		CommitFunc: func(ctx context.Context, tx *sql.Tx) error {
			return tx.Commit()
		},

		Rollback: func(ctx context.Context, tx *sql.Tx) error {
			return tx.Rollback()
		},
	}
}

func SQLConnectionAdapter

func SQLConnectionAdapter(db *sql.DB) ConnectionAdapter[*sql.DB, *sql.Tx]

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)
}

func (ConnectionAdapter[DB, TX]) BeginTx

func (c ConnectionAdapter[DB, TX]) BeginTx(ctx context.Context) (context.Context, error)

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 (c ConnectionAdapter[DB, TX]) ExecContext(ctx context.Context, query string, args ...any) (Result, error)

func (ConnectionAdapter[DB, TX]) QueryContext

func (c ConnectionAdapter[DB, TX]) QueryContext(ctx context.Context, query string, args ...any) (Rows, error)

func (ConnectionAdapter[DB, TX]) QueryRowContext

func (c ConnectionAdapter[DB, TX]) QueryRowContext(ctx context.Context, query string, args ...any) Row

func (ConnectionAdapter[DB, TX]) RollbackTx

func (c ConnectionAdapter[DB, TX]) RollbackTx(ctx context.Context) error

type MapScan

type MapScan[ENT any] func(v *ENT, scan ScanFunc) error

func (MapScan[ENT]) Map

func (ms MapScan[ENT]) Map(scanner Scanner) (ENT, error)

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])
	// ToID 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
	ToID func(id ID) (map[ColumnName]any, 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) (map[ColumnName]any, error)
	// CreatePrepare 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.OnCreate method within in its crud.Create method implementation.
	CreatePrepare func(context.Context, *ENT) error

	// GetID [optional] is a function that allows the ID lookup from an entity.
	//
	// default: extid.Lookup
	GetID func(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"`,

		ToID: func(id int64) (map[flsql.ColumnName]any, error) {
			return map[flsql.ColumnName]any{"entity_id": id}, nil
		},

		ToArgs: func(ee ExampleEntity) (map[flsql.ColumnName]any, error) {
			return map[flsql.ColumnName]any{
				"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(ent *ExampleEntity, scan flsql.ScanFunc) error {
					return scan(&ent.ID, &ent.Col1, &ent.Col2, &ent.Col3)
				}
		},
	}
}

func (Mapping[ENT, ID]) LookupID

func (m Mapping[ENT, ID]) LookupID(ent ENT) (ID, bool)

func (Mapping[ENT, ID]) OnCreate

func (m Mapping[ENT, ID]) OnCreate(ctx context.Context, ptr *ENT) error

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[T any] struct {
	V T

	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[T]) ExecContext

func (a QueryableAdapter[T]) ExecContext(ctx context.Context, query string, args ...any) (Result, error)

func (QueryableAdapter[T]) QueryContext

func (a QueryableAdapter[T]) QueryContext(ctx context.Context, query string, args ...any) (Rows, error)

func (QueryableAdapter[T]) QueryRowContext

func (a QueryableAdapter[T]) QueryRowContext(ctx context.Context, query string, args ...any) Row

type Result

type Result interface {
	// RowsAffected returns the number of rows affected by an
	// update, insert, or delete. Not every database or database
	// driver may support this.
	RowsAffected() (int64, error)
}

type Row

type Row interface {
	// Scan works the same as Rows. with the following exceptions. If no
	// rows were found it returns errNoRows. If multiple rows are returned it
	// ignores all but the first.
	Scan(dest ...any) error
}

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
}

type SQLRowMapper

type SQLRowMapper[T any] interface {
	Map(s Scanner) (T, error)
}

type SQLRowMapperFunc

type SQLRowMapperFunc[T any] func(Scanner) (T, error)

func (SQLRowMapperFunc[T]) Map

func (fn SQLRowMapperFunc[T]) Map(s Scanner) (T, error)

type ScanFunc

type ScanFunc func(dest ...any) error

type Scanner

type Scanner interface{ Scan(dest ...any) error }

Jump to

Keyboard shortcuts

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