sql

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Nov 29, 2025 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package sql contains helper functions that connect a standard Go database/sql object to the GoRADD system.

Most of the functionality in this package is used by database implementations. GoRADD users would not normally directly call functions in this package.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateDelete

func GenerateDelete(db DbI, table string, where map[string]any, useOr bool) (sql string, args []any)

GenerateDelete is a helper function for database implementations to generate a delete statement. useOr will determine if the where items are initially ANDed or ORed

func GenerateInsert

func GenerateInsert(db DbI, table string, fields map[string]any) (sql string, args []any)

GenerateInsert is a helper function for database implementations to generate an insert statement. Pass the quoted table name to quotedTable. Include the schema name here if applicaable.

func GenerateSelect

func GenerateSelect(db DbI, table string, fieldNames []string, where map[string]any, orderBy []string) (sql string, args []any)

GenerateSelect is a helper function for database implementations to generate a select statement.

func GenerateUpdate

func GenerateUpdate(db DbI, table string, fields map[string]any, where map[string]any, useOr bool) (sql string, args []any)

GenerateUpdate is a helper function for database implementations to generate an update statement. useOr will indicate whether to OR or AND the items in the where group. If where has a map[string]any object in it, the items in that map will be OR'd or AND'd opposite to userOr. This is recursive.

func GenerateVersionLock

func GenerateVersionLock(db DbI, table string, pkName string, pkValue any, versionName string, inTransaction bool) (sql string, args []any)

GenerateVersionLock is a helper function for database implementations to implement optimistic locking. It generates the sql that will return the version number of the record, while also doing an exclusive write lock on the row, if a transaction is active. If a transaction is not active, it will simply do a read of the version number.

func GetDataDefLength

func GetDataDefLength(description string) (l int, subLen int)

GetDataDefLength will extract the length from the definition given a data definition description of the table. Example:

bigint(21) -> 21

varchar(50) -> 50 decimal(10,2) -> 10

func NewSqlCursor

func NewSqlCursor(rows *sql.Rows,
	columnTypes []query.ReceiverType,
	columnNames []string,
	joinTree *jointree.JoinTree,
	sql string,
	args []any,
) query.CursorI

NewSqlCursor is a new cursor created from the result of a sql query. columnTypes are the receiver types in the order of the query. columnNames are optional, and if left off, will be taken from the rows value as described in the database. builder is optional, and is used for unpacking joined tables.

func ReceiveRows

func ReceiveRows(rows *sql.Rows,
	columnTypes []query.ReceiverType,
	columnNames []string,
	joinTree *jointree.JoinTree,
	sql string,
	args []any,
) (values []map[string]any, err error)

ReceiveRows gets data from a sql result set and returns it as a slice of maps.

Each column is mapped to its column name. If you provide columnNames, those will be used in the map. Otherwise, it will get the column names out of the result set provided.

If joinTree is provided, it will be used to unpack the result into a hierarchy.

func RowClose

func RowClose(c io.Closer)

Types

type Base

type Base struct {
	// contains filtered or unexported fields
}

Base is a mixin for SQL database drivers that implement the standard Go database/sql interface.

func NewBase

func NewBase(dbKey string, db *sql.DB, dbi DbI) Base

NewBase creates a default Base mixin.

func (*Base) BuilderQuery

func (h *Base) BuilderQuery(ctx context.Context, builder *Builder) (ret any, err error)

BuilderQuery performs a complex query using a query builder. The data returned will depend on the command inside the builder. Be sure when using BuilderCommandLoadCursor you close the returned cursor, probably with a defer.

func (*Base) CheckLock

func (h *Base) CheckLock(ctx context.Context,
	table string,
	pkName string,
	pkValue any,
	optLockFieldName string,
	optLockFieldValue int64) (newLock int64, err error)

func (*Base) CreateSchema

func (h *Base) CreateSchema(ctx context.Context, s schema2.Database) error

func (*Base) DbKey

func (h *Base) DbKey() string

DbKey returns the key of the database in the global database store.

func (*Base) Delete

func (h *Base) Delete(ctx context.Context, table string, primaryKey map[string]any, optLockFieldName string, optLockFieldValue int64) error

Delete deletes a single record from the database. Care should be exercised when calling this directly, since linked records are not modified in any way. If this record has linked records, the database structure may be corrupted.

func (*Base) DeleteWhere

func (h *Base) DeleteWhere(ctx context.Context, table string, where map[string]any) error

DeleteWhere deletes the records from the table indicated by the fields in where. If where is empty, all the records will be deleted.

func (*Base) DestroySchema

func (h *Base) DestroySchema(ctx context.Context, s schema2.Database) error

DestroySchema removes all tables and data from the tables found in the given schema s. Some databases automatically commit transactions during the process, so do not do this inside of a transaction. This operation is not reversible. Circular references on certain databases may fail if the data is not destroyed first.

func (*Base) IsInTransaction

func (h *Base) IsInTransaction(ctx context.Context) (inTx bool)

IsInTransaction returns true if the database is in the middle of a transaction.

func (*Base) Query

func (h *Base) Query(ctx context.Context, table string, fields map[string]ReceiverType, where map[string]any, orderBy []string) (CursorI, error)

Query queries table for fields and returns a cursor that can be used to scan the result set. If where is provided, it will limit the result set to rows with fields that match the where values. If orderBy is provided, the result set will be sorted in ascending order by the fields indicated there. The returned cursor must eventually be closed.

func (*Base) SqlDb

func (h *Base) SqlDb() *sql.DB

SqlDb returns the underlying database/sql database object.

func (*Base) SqlExec

func (h *Base) SqlExec(ctx context.Context, sql string, args ...interface{}) (r sql.Result, err error)

SqlExec executes the given SQL code, without returning any result rows.

func (*Base) SqlQuery

func (h *Base) SqlQuery(ctx context.Context, sql string, args ...interface{}) (r *sql.Rows, err error)

SqlQuery executes the given sql, and returns a row result set.

func (*Base) StartProfiling

func (h *Base) StartProfiling()

StartProfiling will start the database profiling process.

func (*Base) StopProfiling

func (h *Base) StopProfiling()

StopProfiling will stop the database profiling process.

func (*Base) WithSameConnection

func (h *Base) WithSameConnection(ctx context.Context, f func(ctx context.Context) error) (err error)

WithSameConnection ensures that all database operations that happen inside the handler use the same database connection session.

The Go SQL driver uses connection pooling. Each separate database operation may happen on a different connection in the pool, even if inside a transaction. However, this breaks some processes on particular databases. For example, in MySQL and SQLite, the process of turning off and on foreign key checks only works within the same connection, so trying to bracket that with some separate calls to the database will not work. The solution is here, to call WithSameConnection, which will pin a connection to the context within f. It is important to not have too many of these calls happening at the same time, or the connection pool may run out, causing subsequent database calls to block until one is freed.

Nested calls will operate on the same connection.

func (*Base) WithTransaction

func (h *Base) WithTransaction(ctx context.Context, f func(ctx context.Context) error) (err error)

WithTransaction wraps the function f in a database transaction. While the ORM by default will wrap individual database calls with a timeout, it will not apply this timeout to a transaction. It is up to you to pass a context that has a timeout to prevent the overall transaction from hanging. Nested calls will operate within the same transaction, and the outermost call will determine when the transaction is finally committed.

type DbI

type DbI interface {
	// SqlExec executes a query that does not expect to return values.
	// It will time out the query if contextTimeout is exceeded
	SqlExec(ctx context.Context, sql string, args ...interface{}) (r sql.Result, err error)
	// SqlQuery executes a SQL query that returns values.
	// It will time out the query if contextTimeout is exceeded
	SqlQuery(ctx context.Context, sql string, args ...interface{}) (r *sql.Rows, err error)
	// QuoteIdentifier will put quotes around an identifier in a database specific way.
	QuoteIdentifier(string) string
	// FormatArgument will return the placeholder string for the n'th argument
	// in a sql string. Some sqls just use "?" while others identify an argument
	// by location, like Postgres's $1, $2, etc.
	FormatArgument(n int) string
	// SupportsForUpdate will return true if it supports SELECT ... FOR UPDATE clauses for row level locking in a transaction
	SupportsForUpdate() bool
	// TableDefinitionSql returns the sql that will create table.
	TableDefinitionSql(d *schema2.Database, table *schema2.Table) (tableSql string, extraSql []string)
}

The DbI interface describes the interface that a sql database needs to implement so that it will work with the Builder object. If you know a DatabaseI object is a standard Go database/sql database, you can cast it to this type to gain access to the low level SQL driver and send it raw SQL commands.

type SqlReceiver

type SqlReceiver struct {
	R interface{}
}

SqlReceiver is an encapsulation of a way of receiving data from sql queries as interface{} pointers. This allows you to get data without knowing the type of data you are asking for ahead of time, and is easier for dealing with NULL fields. Some database drivers (MySql for one) return different results in fields depending on how you call the query (using a prepared statement can return different results than without one), or if the data does not quite fit (UInt64 in particular will return a string if the returned value is bigger than MaxInt64, but smaller than MaxUint64.)

Pass the address of the R member to the sql.Scan method when using an object of this type, because there are some idiosyncrasies with how Go treats return values that prevents returning an address of R from a function

func (SqlReceiver) Unpack

func (r SqlReceiver) Unpack(typ ReceiverType) interface{}

Unpack converts a SqlReceiver to a type corresponding to the given ReceiverType

func (SqlReceiver) UnpackDefaultValue

func (r SqlReceiver) UnpackDefaultValue(typ schema.ColumnType, size int) interface{}

UnpackDefaultValue converts a SqlReceiver used to get the default value to a type corresponding to typ.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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