db

package
v1.127.1 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 33 Imported by: 5

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (

	// QuoteCharacters defines the start and end quote characters for different databases
	QuoteCharacters = map[base.DXDatabaseType]struct {
		Start []rune
		End   []rune
	}{
		base.DXDatabaseTypePostgreSQL: {
			Start: []rune{'"'},
			End:   []rune{'"'},
		},
		base.DXDatabaseTypeMariaDB: {

			Start: []rune{'`'},
			End:   []rune{'`'},
		},
		base.DXDatabaseTypeSQLServer: {
			Start: []rune{'[', '"'},
			End:   []rune{']', '"'},
		},
		base.DXDatabaseTypeOracle: {
			Start: []rune{'"'},
			End:   []rune{'"'},
		},
	}
)

Regular expressions for unquoted identifiers by databases type

Functions

func BuildRowNormalizer

func BuildRowNormalizer(driverName string, colTypes []*sql.ColumnType) func(row map[string]any)

BuildRowNormalizer plans the per-column conversions for one query and returns a function that applies them in place to each scanned row.

It returns nil when nothing needs doing — PostgreSQL, an unrecognised driver, or a result set with no convertible column — so the per-row cost at the call site is a single nil check. All reflection happens here, once per query; the returned closures are plain type switches.

Plan keys are the driver's own column names, so this must run on the row as MapScan produced it, before any key deformatting.

func CheckIdentifier

func CheckIdentifier(dialect base.DXDatabaseType, identifier string) error

CheckIdentifier validates table and column names according to databases-specific rules

func Count

func Count(ctx context.Context, db *sqlx.DB, tableOrSubquery string, countExpression string, whereAndFieldNameValues utils.JSON,
	joinSQLPart any, groupByFields []string, havingClause string, withCTE string) (count int64, err error)

Count executes a count query against the databases and returns the result as an int64. This implementation leverages BaseSelect for all databases interactions.

Parameters:

  • db: The databases connection
  • tableOrSubquery: The table name or subquery to count from
  • countExpr: The count expression (e.g., "count(*)", "count(distinct user_id)")
  • whereAndFieldNameValues: Conditions for filtering results
  • joinSQLPart: Optional JOIN clause
  • groupByFields: OutFields to group by
  • havingClause: Optional HAVING clause for filtering grouped results
  • withCTE: Optional Common Table Expression (WITH clause)

Returns:

  • count: The count result as an int64
  • err: Any error that occurred during query execution

When using Common Table Expressions (CTE):

  • Define the CTE in the withCTE parameter (e.g., "recent_orders AS (SELECT * FROM orders WHERE date > '2023-01-01')")
  • Reference the CTE name in the tableOrSubquery parameter (e.g., "recent_orders")

Examples:

// Simple count
count, err := Count(db, "users", "", nil, nil, nil, "", "")
// Generates: SELECT COUNT(*) FROM users

// Count with condition
count, err := Count(db, "orders", "", utils.JSON{"status": "completed"}, nil, nil, "", "")
// Generates: SELECT COUNT(*) FROM orders WHERE status = 'completed'

// Count with CTE
cte := "active_users AS (SELECT * FROM users WHERE status = 'active')"
count, err := Count(db, "active_users", "", nil, nil, nil, "", cte)
// Generates: WITH active_users AS (SELECT * FROM users WHERE status = 'active') SELECT COUNT(*) FROM active_users

// Count with subquery
count, err := Count(db, "(SELECT * FROM orders WHERE date > '2023-01-01')", "", nil, nil, nil, "", "")
// Generates: SELECT COUNT(*) FROM (SELECT * FROM orders WHERE date > '2023-01-01') AS subquery__sq_[unique_id]

func DBDriverExcludeSQLExpressionFromWhereKeyValues

func DBDriverExcludeSQLExpressionFromWhereKeyValues(driverName string, kv utils.JSON) (r utils.JSON, err error)

func DBDriverGenerateLimitOffsetClause

func DBDriverGenerateLimitOffsetClause(driverName string, limitAsInt64, offsetAsInt64 int64, hasLimit bool, currentOrderBy string, orderbyFieldNameDirections DXDatabaseTableFieldsOrderBy) (string, string, error)

func DbDriverConvertValueTypeToDBCompatible

func DbDriverConvertValueTypeToDBCompatible(driverName string, v any) (any, error)

func DbDriverFormatIdentifier

func DbDriverFormatIdentifier(driverName string, identifier string) string

DbDriverFormatIdentifier formats an identifier (column/table name) according to databases requirements

func DbDriverFormatOrderByFieldName

func DbDriverFormatOrderByFieldName(driverName string, fieldName string, direction string) (string, error)

func DbOtelStart

func DbOtelStart(ctx context.Context, spanName string, query string, callerSkip int) (context.Context, func(err error, rowsAffected int64))

DbOtelStart creates a span with rich DB attributes. Returns the modified context and a finish function. The finish function accepts an error and an optional rows-affected count. callerSkip controls how many stack frames to skip for code.* attributes (use 2 from raw functions, 3+ from wrappers).

func DecryptExpression

func DecryptExpression(dbType base.DXDatabaseType, fieldName string, sessionKey string) string

DecryptExpression returns database-specific decryption SQL expression

func DeformatIdentifier

func DeformatIdentifier(identifier string, driverName string) string

func DeformatKeys

func DeformatKeys(kv map[string]interface{}, driverName string, fieldTypeMapping DXDatabaseTableFieldTypeMapping) (r map[string]interface{}, err error)

func Delete

func Delete(ctx context.Context, db *sqlx.DB, tableName string, whereAndFieldNameValues utils.JSON, returningFieldNames []string) (result sql.Result, returningFieldValues []utils.JSON, err error)

Delete executes an SQL DELETE statement with support for returning values

Parameters:

  • db: Database connection
  • tableName: Name of the table to delete from
  • whereAndFieldNameValues: Conditions for filtering which rows to delete
  • returningFieldNames: List of field names to return after delete

Returns:

  • rowsAffected: Number of rows affected by the delete
  • returningFieldValues: Map of returned field names to their values (if requested)
  • err: Any error that occurred during the operation

Supports different returning clause implementations for:

  • PostgreSQL/MariaDB: RETURNING clause
  • SQL Server: OUTPUT clause
  • Oracle: RETURNING INTO clause
  • MySQL: Not supported for DELETE err if requested)

func Exec

func Exec(ctx context.Context, db *sqlx.DB, sqlStatement string, sqlArguments utils.JSON) (result sql.Result, err error)

func Insert

func Insert(ctx context.Context, db *sqlx.DB, tableName string, setFieldValues utils.JSON, returningFieldNames []string) (result sql.Result, returningFieldValues utils.JSON, err error)

Insert performs a databases insert with support for returning values across different databases types Parameters:

  • db: Database connection
  • tableName: Target table name
  • setFieldValues: Map of column names to values
  • returningFieldNames: List of field names to return after insert

Returns:

  • returningFieldValues: Map of field names to their values after insert
  • err: Error if any occurred

func IsConnectionError

func IsConnectionError(err error) bool

IsConnectionError checks if the error is a databases connection error

func LogDBDelete

func LogDBDelete(tableName string, whereData utils.JSON, err error)

LogDBDelete logs a DELETE operation

func LogDBInsert

func LogDBInsert(tableName string, data utils.JSON, err error)

LogDBInsert logs an INSERT operation

func LogDBOperation

func LogDBOperation(operation, sqlStatement string, args []any, err error)

LogDBOperation logs a databases operation with SQL and arguments

func LogDBOperationWithJSON

func LogDBOperationWithJSON(operation, sqlStatement string, data utils.JSON, err error)

LogDBOperationWithJSON logs a databases operation with SQL and JSON arguments

func LogDBUpdate

func LogDBUpdate(tableName string, setData, whereData utils.JSON, err error)

LogDBUpdate logs an UPDATE operation

func NewRowNormalizer

func NewRowNormalizer(driverName string, src ColumnTypesProvider) (normalize func(row map[string]any))

NewRowNormalizer builds the row normaliser for a live result set, or nil when nothing needs converting.

Column metadata is strictly best-effort: an error is ignored, and so is a panic — go-mssqldb panics outright for a type id it has no scan mapping for, and reading metadata must never turn a working query into a failing one.

For a *sqlx.Row this MUST be called before MapScan, which closes the underlying rows.

func OracleSafeBindNames

func OracleSafeBindNames(sqlStatement string, sqlArguments utils.JSON) (string, []any)

OracleSafeBindNames prepares a ":name"-parameterized statement for go-ora. Oracle bind-variable names share the identifier rules — a RESERVED WORD as a bind name (":uid", ":level", ...) is ORA-01745 — and generated SQL derives bind names from COLUMN names, so any reserved-word column breaks the bind. Fix: every ":<argName>" placeholder is rewritten to ":p_<argName>" and the sql.Named args are keyed "p_<argName>" to match. Only placeholders whose name EXACTLY matches a provided arg key are rewritten, so out-binds like ":uid_out" and caller-authored bind names not in the args stay untouched. The SQL is scanned ONCE, token by token (never re-scanning rewritten output — a progressive search-and-replace corrupts args whose name is "p_"+another arg's name); string literals ('...'), casts (::) and PL/SQL assignments (:=) are copied through verbatim.

func OracleSelectListField

func OracleSelectListField(field string) string

OracleSelectListField formats ONE select-list item for Oracle: a plain identifier becomes quoted-UPPERCASE (matching the DDL — an unquoted reserved word like uid silently resolves to the BUILT-IN FUNCTION, returning wrong data with no error); anything else (expression, alias, star) is untouched.

func QualifyTableNameForExec

func QualifyTableNameForExec(dbType base.DXDatabaseType, tableName string) string

QualifyTableNameForExec adapts a logical `schema.table` name to the target engine for EXECUTED SQL. PostgreSQL/SQL Server/Oracle have real schemas, so `schema.table` resolves natively — returned unchanged (byte-identical, no behavior change). MariaDB has NO schema layer: the "schema" is virtual, carried as a SINGLE quoted identifier `schema.table` (the dot is part of the table name), so a dotted name is collapsed into one backtick-quoted identifier. Idempotent (already-backtick-quoted or bare names pass through).

func RawCount

func RawCount(
	ctx context.Context,
	db *sqlx.DB,
	fromWhereJoinPartSqlStatement string,
	sqlArguments utils.JSON,
) (count int64, err error)

func RawExec

func RawExec(ctx context.Context, db *sqlx.DB, query string, arg []any) (result sql.Result, err error)

func RawTxExec

func RawTxExec(ctx context.Context, tx *sqlx.Tx, query string, arg []any) (result sql.Result, err error)

func SQLExpressionForDatabaseType

func SQLExpressionForDatabaseType(se SQLExpression, dbType base.DXDatabaseType) string

SQLExpressionForDatabaseType is SQLExpressionForDriver for callers that already resolved the engine.

func SQLExpressionForDriver

func SQLExpressionForDriver(se SQLExpression, driverName string) string

SQLExpressionForDriver renders an expression for a statement that sqlx.Named will compile on its way to the driver.

Oracle is the exception, and the whole reason this function exists. QueryRows and Exec discard sqlx's output for Oracle and re-derive from the ORIGINAL SQL, because go-ora binds by name. OracleSafeBindNames then treats "::" as a cast and copies both bytes through, so nothing ever un-doubles it: Oracle compared against the wrong string and returned the wrong rows with no error at all.

The doubling cannot simply be dropped for everyone. Handing sqlx.Named a raw expression is a parse failure, not a difference:

unexpected `:` while reading named param at 75

so PostgreSQL, MariaDB and SQL Server still need it.

func SQLPartConstructSelect

func SQLPartConstructSelect(driverName string, tableName string, fieldNames []string,
	whereAndFieldNameValues utils.JSON, joinSQLPart any,
	orderByFieldNameDirections DXDatabaseTableFieldsOrderBy, limit any, offset any, forUpdatePart any,
	groupByFields []string, havingClause utils.JSON, withCTE string) (s string, err error)

SQLPartConstructSelect creates a SELECT query with support for all major SQL features

Parameters:

  • driverName: Database driver name
  • tableName: The table name or subquery to select from
  • fieldNames: OutFields to select (use []string{"*"} for all fields)
  • whereAndFieldNameValues: Conditions for filtering results
  • joinSQLPart: Optional JOIN clause
  • orderByFieldNameDirections: Optional ORDER BY specifications
  • limit: Maximum number of rows to return
  • offset: Number of rows to skip before returning results
  • forUpdatePart: Whether to lock rows with FOR UPDATE
  • groupByFields: OutFields to group by
  • havingClause: Optional HAVING clause for filtering grouped results
  • withCTE: Optional Common Table Expression (WITH clause)

Returns:

  • The complete SQL query string
  • Any error that occurred during query construction

This function builds a complete SQL query by combining all the provided parts in the correct order according to SQL syntax rules. It handles various databases-specific formatting requirements.

func SQLPartFieldNames

func SQLPartFieldNames(fieldNames []string, driverName string) (s string)

SQLPartFieldNames formats field names for use in a SELECT clause

Parameters:

  • fieldNames: Array of fields to include in the SELECT clause
  • driverName: Database driver name for proper identifier formatting

Returns:

  • Properly formatted field list for the SELECT statement

If fieldNames is nil, returns "*" to select all fields Otherwise, joins the field names with commas after formatting each identifier according to databases-specific rules

func SQLPartInsertFieldNamesFieldValues

func SQLPartInsertFieldNamesFieldValues(insertKeyValues utils.JSON, driverName string) (fieldNames string, fieldValues string)

SQLPartInsertFieldNamesFieldValues generates the field names and values parts for an SQL INSERT statement

func SQLPartOrderByFieldNameDirections

func SQLPartOrderByFieldNameDirections(orderByKeyValues map[string]string, driverName string) (string, error)

SQLPartOrderByFieldNameDirections generates ORDER BY clause for different databases types

Parameters:

  • orderByKeyValues: Map of field names to sort directions
  • driverName: Database driver name for proper identifier formatting

Returns:

  • Properly formatted ORDER BY clause string (without the "ORDER BY" keyword)
  • Error if formatting fails for any field

The function formats each field and direction according to databases-specific rules and joins them with commas

func SQLPartUpdateSetFieldValues

func SQLPartUpdateSetFieldValues(setFieldValues utils.JSON, driverName string) (s string)

SQLPartUpdateSetFieldValues generates the SET clause for UPDATE statements

func SQLPartWhereAndFieldNameValues

func SQLPartWhereAndFieldNameValues(whereKeyValues utils.JSON, driverName string) string

SQLPartWhereAndFieldNameValues generates WHERE clause conditions for different databases types

Parameters:

  • whereKeyValues: JSON object mapping field names to values for filtering
  • driverName: Database driver name for proper identifier formatting

Returns:

  • A properly formatted WHERE clause string (without the "WHERE" keyword)

The function handles different value types:

  • nil values are converted to "IS NULL" conditions
  • SQLExpression values are converted to their string representation
  • Regular values use parameterized queries with "=" operator

All conditions are joined with "AND" operators

func SessionKeyExpression

func SessionKeyExpression(dbType base.DXDatabaseType, sessionKey string) string

SessionKeyExpression returns database-specific session key retrieval expression

func TextColumnToString

func TextColumnToString(row map[string]any, columnName string)

TextColumnToString converts one named column's []byte to a string, in place.

The normaliser cannot do this on its own for a decrypted column: MariaDB's AES_DECRYPT() yields a binary string, which the driver reports with a []byte scan type indistinguishable from a real BLOB, so it is deliberately left alone. A caller that knows a specific column holds decrypted text converts exactly that column — never every column in the row, which is what silently corrupted genuine binary data.

The name is matched exactly first, then case-insensitively: a row taken straight from MapScan carries the driver's own column names, and the case-folding engines upper-case them.

func TxCount

func TxCount(ctx context.Context, tx *sqlx.Tx, tableOrSubquery string, countExpression string, whereAndFieldNameValues utils.JSON,
	joinSQLPart any, groupByFields []string, havingClause utils.JSON, withCTE string) (count int64, err error)

TxCount executes a count query within a transaction and returns the result as an int64. This implementation leverages BaseTxSelect for all databases interactions.

Parameters:

  • tx: The databases transaction
  • tableOrSubquery: The table name or subquery to count from
  • countExpr: The count expression (e.g., "count(*)", "count(distinct user_id)")
  • whereAndFieldNameValues: Conditions for filtering results
  • joinSQLPart: Optional JOIN clause
  • groupByFields: OutFields to group by
  • havingClause: Optional HAVING clause for filtering grouped results
  • withCTE: Optional Common Table Expression (WITH clause)

Returns:

  • count: The count result as an int64
  • err: Any error that occurred during query execution

This function is a transaction-based version of the Count function. It provides the same functionality but within a transaction context, which ensures consistency across multiple databases operations.

func TxDelete

func TxDelete(ctx context.Context, tx *sqlx.Tx, tableName string, whereAndFieldNameValues utils.JSON, returningFieldNames []string) (result sql.Result, returningFieldValues []utils.JSON, err error)

TxDelete executes an SQL DELETE statement within a transaction with support for returning values

func TxExec

func TxExec(
	ctx context.Context,
	tx *sqlx.Tx,
	sqlStatement string,
	sqlArguments utils.JSON,
) (result sql.Result, err error)

func TxInsert

func TxInsert(ctx context.Context, tx *sqlx.Tx, tableName string, setFieldValues utils.JSON, returningFieldNames []string) (result sql.Result, returningFieldValues utils.JSON, err error)

func TxUpdate

func TxUpdate(ctx context.Context, tx *sqlx.Tx, tableName string, setFieldValues utils.JSON, whereAndFieldNameValues utils.JSON, returningFieldNames []string) (result sql.Result, returningFieldValues []utils.JSON, err error)

func TxUpsert

func TxUpsert(
	ctx context.Context,
	tx *sqlx.Tx,
	tableName string,
	insertData utils.JSON,
	updateData utils.JSON,
	whereKeys utils.JSON,
	idField string,
) (result sql.Result, id int64, isInsert bool, err error)

TxUpsert is the transactional variant of Upsert. Same contract and dialect matrix.

func Update

func Update(ctx context.Context, db *sqlx.DB, tableName string, setFieldNameValues utils.JSON, whereAndFieldNameValues utils.JSON, returningFieldNames []string) (result sql.Result, returningFieldValues []utils.JSON, err error)

Update executes an SQL UPDATE statement with support for returning values

Parameters:

  • db: Database connection
  • tableName: Name of the table to update
  • setFieldValues: Map of field names to new values
  • whereAndFieldNameValues: Conditions for filtering which rows to update
  • returningFieldNames: List of field names to return after update

Returns:

  • rowsAffected: Number of rows affected by the update
  • returningFieldValues: Map of returned field names to their values (if requested)
  • err: Any error that occurred during the operation

Supports different returning clause implementations for:

  • PostgreSQL/MariaDB: RETURNING clause
  • SQL Server: OUTPUT clause
  • Oracle: RETURNING INTO clause
  • MySQL: Separate SELECT query after UPDATE (with limitations)

func Upsert

func Upsert(
	ctx context.Context,
	db *sqlx.DB,
	tableName string,
	insertData utils.JSON,
	updateData utils.JSON,
	whereKeys utils.JSON,
	idField string,
) (result sql.Result, id int64, isInsert bool, err error)

Upsert performs an atomic single-row UPSERT using the database's native syntax.

Per dialect:

  • PostgreSQL / PostgresSQLV2 : INSERT ... ON CONFLICT (whereKeys) DO UPDATE ... RETURNING id, (xmax = 0)
  • MariaDB / MySQL : INSERT ... ON DUPLICATE KEY UPDATE ..., id = LAST_INSERT_ID(id)
  • SQL Server : MERGE ... WITH (HOLDLOCK) ... OUTPUT inserted.id, $action
  • Oracle : PL/SQL block - try INSERT ... EXCEPTION WHEN DUP_VAL_ON_INDEX THEN UPDATE

PRECONDITION: whereKeys columns MUST have a UNIQUE (or PRIMARY KEY) constraint.

  • PostgreSQL / SQLite : missing constraint -> statement rejected with clear error
  • SQL Server / Oracle : missing constraint -> caller responsibility; MERGE syntax still runs
  • MariaDB / MySQL : missing constraint -> SILENT duplicate insert (DB-level foot-gun)

Affects exactly ONE row per call (never multi-row). Single SQL statement, single round-trip. No SELECT-then-INSERT-or-UPDATE race window.

Returns:

  • sql.Result : non-nil for MariaDB and Oracle paths; nil for PG / MSSQL paths (which use QueryRows)
  • id : newly-inserted row id OR existing row id on update
  • isInsert : true if a new row was inserted, false if an existing row was updated

insertData : full column set for INSERT (typically data ∪ whereKeys, plus insert-audit fields) updateData : columns to assign on UPDATE (omit immutable fields like created_at) whereKeys : identity columns; must be a UNIQUE or PK on the table idField : the row-id column (returned in id)

Types

type ColumnTypesProvider

type ColumnTypesProvider interface {
	ColumnTypes() ([]*sql.ColumnType, error)
}

ColumnTypesProvider is satisfied by *sqlx.Rows, *sql.Rows and *sqlx.Row.

type DBOperationError

type DBOperationError struct {
	Operation  string // "INSERT", "UPDATE", "DELETE"
	TableName  string
	MaskedData string // pre-formatted, sensitive-masked string
	Cause      error
}

DBOperationError wraps a DB error with operation context for consolidated logging. The routeHandler extracts this context to produce a single log entry with all details.

func NewDBOperationError

func NewDBOperationError(operation, tableName string, data utils.JSON, cause error) *DBOperationError

func NewDBOperationErrorWithWhere

func NewDBOperationErrorWithWhere(operation, tableName string, whereData utils.JSON, cause error) *DBOperationError

func NewDBOperationErrorWithWhereAndSet

func NewDBOperationErrorWithWhereAndSet(operation, tableName string, setData, whereData utils.JSON, cause error) *DBOperationError

func (*DBOperationError) DBMaskedDataString

func (e *DBOperationError) DBMaskedDataString() string

func (*DBOperationError) DBOperation

func (e *DBOperationError) DBOperation() string

Methods for structural interface matching at routeHandler (no import needed)

func (*DBOperationError) DBTableName

func (e *DBOperationError) DBTableName() string

func (*DBOperationError) Error

func (e *DBOperationError) Error() string

func (*DBOperationError) Unwrap

func (e *DBOperationError) Unwrap() error

type DXDatabaseTableFieldTypeMapping

type DXDatabaseTableFieldTypeMapping map[string]types.APIParameterType

type DXDatabaseTableFieldsOrderBy

type DXDatabaseTableFieldsOrderBy map[string]string

type DXDatabaseTableRowsInfo

type DXDatabaseTableRowsInfo struct {
	Columns []string
}

func BaseSelect

func BaseSelect(ctx context.Context, db *sqlx.DB, tableName string, fieldTypeMapping DXDatabaseTableFieldTypeMapping,
	fieldNames []string, whereAndFieldNameValues utils.JSON, joinSQLPart any,
	groupByFields []string, havingClause utils.JSON, orderByFieldNameDirections DXDatabaseTableFieldsOrderBy, limit any, offset any, forUpdatePart any,
	withCTE string) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

BaseSelect is the foundational function for executing SQL SELECT queries. It supports all major SQL features including GROUP BY, HAVING, and Common Table Expressions (CTE).

Parameters:

  • db: The databases connection
  • fieldTypeMapping: Type conversion mapping for fields
  • tableName: The table name or subquery to select from
  • fieldNames: OutFields to select (use []string{"*"} for all fields)
  • whereAndFieldNameValues: Conditions for filtering results (nil for no conditions)
  • joinSQLPart: Optional JOIN clause (nil for no joins)
  • orderByFieldNameDirections: Optional ORDER BY specifications (nil for no ordering)
  • limit: Maximum number of rows to return (nil for no limit)
  • offset: Number of rows to skip before returning results (nil for no offset)
  • forUpdatePart: Whether to lock rows with FOR UPDATE (nil or false for no locking)
  • groupByFields: OutFields to group by (nil for no grouping)
  • havingClause: Optional HAVING clause for filtering grouped results (empty string for none)
  • withCTE: Optional Common Table Expression (WITH clause) (empty string for none)

Returns:

  • rowsInfo: Information about the returned columns
  • r: The query results as a slice of JSON objects
  • err: Any error that occurred during query execution

Examples:

// Simple select
rows, err := BaseSelect(db, mapping, "users", []string{"id", "name"}, nil, nil, nil, nil, nil, nil, nil, "", "")
// Generates: SELECT id, name FROM users

// Select with GROUP BY and HAVING
rows, err := BaseSelect(db, mapping, "orders", []string{"customer_id", "COUNT(*) as order_count"},
  nil, nil, nil, nil, nil, nil, []string{"customer_id"}, "COUNT(*) > 5", "")
// Generates: SELECT customer_id, COUNT(*) as order_count FROM orders GROUP BY customer_id HAVING COUNT(*) > 5

// Select with CTE
cte := "recent_orders AS (SELECT * FROM orders WHERE order_date > '2023-01-01')"
rows, err := BaseSelect(db, mapping, "recent_orders", []string{"*"}, nil, nil, nil, nil, nil, nil, nil, "", cte)
// Generates: WITH recent_orders AS (SELECT * FROM orders WHERE order_date > '2023-01-01') SELECT * FROM recent_orders

func BaseTxSelect

func BaseTxSelect(ctx context.Context, tx *sqlx.Tx, tableName string, fieldTypeMapping DXDatabaseTableFieldTypeMapping,
	fieldNames []string, whereAndFieldNameValues utils.JSON, joinSQLPart any, groupByFields []string, havingClause utils.JSON,
	orderByFieldNameDirections DXDatabaseTableFieldsOrderBy, limit any, offset any, forUpdatePart any,
	withCTE string) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

BaseTxSelect is the transaction version of BaseSelect for executing SQL SELECT queries within a transaction. It supports all major SQL features including GROUP BY, HAVING, and Common Table Expressions (CTE).

Parameters:

  • tx: The databases transaction
  • fieldTypeMapping: Type conversion mapping for fields
  • tableName: The table name or subquery to select from
  • fieldNames: OutFields to select (use []string{"*"} for all fields)
  • whereAndFieldNameValues: Conditions for filtering results (nil for no conditions)
  • joinSQLPart: Optional JOIN clause (nil for no joins)
  • orderByFieldNameDirections: Optional ORDER BY specifications (nil for no ordering)
  • limit: Maximum number of rows to return (nil for no limit)
  • offset: Number of rows to skip before returning results (nil for no offset)
  • forUpdatePart: Whether to lock rows with FOR UPDATE (nil or false for no locking)
  • groupByFields: OutFields to group by (nil for no grouping)
  • havingClause: Optional HAVING clause for filtering grouped results (empty string for none)
  • withCTE: Optional Common Table Expression (WITH clause) (empty string for none)

Returns:

  • rowsInfo: Information about the returned columns
  • r: The query results as a slice of JSON objects
  • err: Any error that occurred during query execution

This function is similar to BaseSelect but operates within a transaction context, allowing for consistent reads and potential row locking when used with forUpdatePart=true

func QueryRows

func QueryRows(
	ctx context.Context,
	db *sqlx.DB,
	fieldTypeMapping DXDatabaseTableFieldTypeMapping,
	sqlStatement string,
	sqlArguments utils.JSON,
) (rowsInfo *DXDatabaseTableRowsInfo, rows []utils.JSON, err error)

func RawQueryRows

func RawQueryRows(ctx context.Context, db *sqlx.DB, fieldTypeMapping DXDatabaseTableFieldTypeMapping, query string, arg []any) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

func RawTxQueryRows

func RawTxQueryRows(ctx context.Context, tx *sqlx.Tx, fieldTypeMapping DXDatabaseTableFieldTypeMapping, query string, arg []any) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

func Select

func Select(ctx context.Context, db *sqlx.DB, tableName string, fieldTypeMapping DXDatabaseTableFieldTypeMapping, fieldNames []string,
	whereAndFieldNameValues utils.JSON, joinSQLPart any, groupByFields []string, havingClause utils.JSON, orderByFieldNameDirections DXDatabaseTableFieldsOrderBy,
	limit any, offset any, forUpdatePart any) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

Select is a simplified version of BaseSelect that maintains compatibility with existing code. It doesn't include the additional GROUP BY, HAVING, and CTE features.

Parameters:

  • db: The databases connection
  • fieldTypeMapping: Type conversion mapping for fields
  • tableName: The table name to select from
  • fieldNames: OutFields to select
  • whereAndFieldNameValues: Conditions for filtering results
  • joinSQLPart: Optional JOIN clause
  • orderByFieldNameDirections: Optional ORDER BY specifications
  • limit: Maximum number of rows to return
  • offset: Number of rows to skip before returning results
  • forUpdatePart: Whether to lock rows with FOR UPDATE

Returns:

  • rowsInfo: Information about the returned columns
  • r: The query results as a slice of JSON objects
  • err: Any error that occurred during query execution

This function is a backward-compatible wrapper around BaseSelect. It passes nil or empty values for the GROUP BY, HAVING, and CTE parameters.

func SelectPaging

func SelectPaging(ctx context.Context, db *sqlx.DB, pageIndex int64, rowsPerPage int64, tableName string, fieldTypeMapping DXDatabaseTableFieldTypeMapping, fieldNames []string,
	whereAndFieldNameValues utils.JSON, joinSQLPart any, groupByFields []string, havingClause utils.JSON, orderByFieldNameDirections DXDatabaseTableFieldsOrderBy) (totalRowCount int64, rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

SelectPaging executes a paged SELECT query, returning both the total row count and the page results.

func TxQueryRows

func TxQueryRows(
	ctx context.Context,
	tx *sqlx.Tx,
	fieldTypeMapping DXDatabaseTableFieldTypeMapping,
	sqlStatement string,
	sqlArguments utils.JSON,
) (rowsInfo *DXDatabaseTableRowsInfo, rows []utils.JSON, err error)

func TxSelect

func TxSelect(ctx context.Context, tx *sqlx.Tx, tableName string, fieldTypeMapping DXDatabaseTableFieldTypeMapping, fieldNames []string,
	whereAndFieldNameValues utils.JSON, joinSQLPart any, groupByFields []string, havingClause utils.JSON, orderByFieldNameDirections DXDatabaseTableFieldsOrderBy,
	limit any, offset any, forUpdatePart any) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)

TxSelect is a transaction-based version of the Select function that maintains compatibility with existing code. It doesn't include the additional GROUP BY, HAVING, and CTE features.

Parameters:

  • tx: The databases transaction
  • fieldTypeMapping: Type conversion mapping for fields
  • tableName: The table name to select from
  • fieldNames: OutFields to select
  • whereAndFieldNameValues: Conditions for filtering results
  • joinSQLPart: Optional JOIN clause
  • orderByFieldNameDirections: Optional ORDER BY specifications
  • limit: Maximum number of rows to return
  • offset: Number of rows to skip before returning results
  • forUpdatePart: Whether to lock rows with FOR UPDATE

Returns:

  • rowsInfo: Information about the returned columns
  • r: The query results as a slice of JSON objects
  • err: Any error that occurred during query execution

This function is a transaction-based wrapper around BaseTxSelect. It passes nil or empty values for the GROUP BY, HAVING, and CTE parameters.

type SQLExpression

type SQLExpression struct {
	Expression string
}

SQLExpression is a raw SQL fragment supplied in place of a bound value. It is inlined into the statement text rather than parameterised.

func (SQLExpression) String

func (se SQLExpression) String() string

String returns the expression exactly as written.

It also satisfies fmt.Stringer, and that is why the raw form has to be the default. formatJSONForLog renders values with %v, so every DB_UPDATE and DB_DELETE debug line ran this method -- and until 2026-08-29 it printed colons that were never sent to any database, on all four engines.

func (SQLExpression) StringForNamedQuery

func (se SQLExpression) StringForNamedQuery() string

StringForNamedQuery doubles every colon so it survives sqlx's named-parameter compiler, which reduces "::" back to ":".

Only for statements that genuinely pass through sqlx.Named. Anything else receives the doubled colons verbatim and compares against a string the caller never wrote. Prefer SQLExpressionForDriver, which decides per engine.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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