Documentation
¶
Index ¶
- Variables
- func BuildRowNormalizer(driverName string, colTypes []*sql.ColumnType) func(row map[string]any)
- func CheckIdentifier(dialect base.DXDatabaseType, identifier string) error
- func Count(ctx context.Context, db *sqlx.DB, tableOrSubquery string, ...) (count int64, err error)
- func DBDriverExcludeSQLExpressionFromWhereKeyValues(driverName string, kv utils.JSON) (r utils.JSON, err error)
- func DBDriverGenerateLimitOffsetClause(driverName string, limitAsInt64, offsetAsInt64 int64, hasLimit bool, ...) (string, string, error)
- func DbDriverConvertValueTypeToDBCompatible(driverName string, v any) (any, error)
- func DbDriverFormatIdentifier(driverName string, identifier string) string
- func DbDriverFormatOrderByFieldName(driverName string, fieldName string, direction string) (string, error)
- func DbOtelStart(ctx context.Context, spanName string, query string, callerSkip int) (context.Context, func(err error, rowsAffected int64))
- func DecryptExpression(dbType base.DXDatabaseType, fieldName string, sessionKey string) string
- func DeformatIdentifier(identifier string, driverName string) string
- func DeformatKeys(kv map[string]interface{}, driverName string, ...) (r map[string]interface{}, err error)
- func Delete(ctx context.Context, db *sqlx.DB, tableName string, ...) (result sql.Result, returningFieldValues []utils.JSON, err error)
- func Exec(ctx context.Context, db *sqlx.DB, sqlStatement string, sqlArguments utils.JSON) (result sql.Result, err error)
- func Insert(ctx context.Context, db *sqlx.DB, tableName string, setFieldValues utils.JSON, ...) (result sql.Result, returningFieldValues utils.JSON, err error)
- func IsConnectionError(err error) bool
- func LogDBDelete(tableName string, whereData utils.JSON, err error)
- func LogDBInsert(tableName string, data utils.JSON, err error)
- func LogDBOperation(operation, sqlStatement string, args []any, err error)
- func LogDBOperationWithJSON(operation, sqlStatement string, data utils.JSON, err error)
- func LogDBUpdate(tableName string, setData, whereData utils.JSON, err error)
- func NewRowNormalizer(driverName string, src ColumnTypesProvider) (normalize func(row map[string]any))
- func OracleSafeBindNames(sqlStatement string, sqlArguments utils.JSON) (string, []any)
- func OracleSelectListField(field string) string
- func QualifyTableNameForExec(dbType base.DXDatabaseType, tableName string) string
- func RawCount(ctx context.Context, db *sqlx.DB, fromWhereJoinPartSqlStatement string, ...) (count int64, err error)
- func RawExec(ctx context.Context, db *sqlx.DB, query string, arg []any) (result sql.Result, err error)
- func RawTxExec(ctx context.Context, tx *sqlx.Tx, query string, arg []any) (result sql.Result, err error)
- func SQLExpressionForDatabaseType(se SQLExpression, dbType base.DXDatabaseType) string
- func SQLExpressionForDriver(se SQLExpression, driverName string) string
- func SQLPartConstructSelect(driverName string, tableName string, fieldNames []string, ...) (s string, err error)
- func SQLPartFieldNames(fieldNames []string, driverName string) (s string)
- func SQLPartInsertFieldNamesFieldValues(insertKeyValues utils.JSON, driverName string) (fieldNames string, fieldValues string)
- func SQLPartOrderByFieldNameDirections(orderByKeyValues map[string]string, driverName string) (string, error)
- func SQLPartUpdateSetFieldValues(setFieldValues utils.JSON, driverName string) (s string)
- func SQLPartWhereAndFieldNameValues(whereKeyValues utils.JSON, driverName string) string
- func SessionKeyExpression(dbType base.DXDatabaseType, sessionKey string) string
- func TextColumnToString(row map[string]any, columnName string)
- func TxCount(ctx context.Context, tx *sqlx.Tx, tableOrSubquery string, ...) (count int64, err error)
- func TxDelete(ctx context.Context, tx *sqlx.Tx, tableName string, ...) (result sql.Result, returningFieldValues []utils.JSON, err error)
- func TxExec(ctx context.Context, tx *sqlx.Tx, sqlStatement string, sqlArguments utils.JSON) (result sql.Result, err error)
- func TxInsert(ctx context.Context, tx *sqlx.Tx, tableName string, setFieldValues utils.JSON, ...) (result sql.Result, returningFieldValues utils.JSON, err error)
- func TxUpdate(ctx context.Context, tx *sqlx.Tx, tableName string, setFieldValues utils.JSON, ...) (result sql.Result, returningFieldValues []utils.JSON, err error)
- func TxUpsert(ctx context.Context, tx *sqlx.Tx, tableName string, insertData utils.JSON, ...) (result sql.Result, id int64, isInsert bool, err error)
- func Update(ctx context.Context, db *sqlx.DB, tableName string, ...) (result sql.Result, returningFieldValues []utils.JSON, err error)
- func Upsert(ctx context.Context, db *sqlx.DB, tableName string, insertData utils.JSON, ...) (result sql.Result, id int64, isInsert bool, err error)
- type ColumnTypesProvider
- type DBOperationError
- func NewDBOperationError(operation, tableName string, data utils.JSON, cause error) *DBOperationError
- func NewDBOperationErrorWithWhere(operation, tableName string, whereData utils.JSON, cause error) *DBOperationError
- func NewDBOperationErrorWithWhereAndSet(operation, tableName string, setData, whereData utils.JSON, cause error) *DBOperationError
- type DXDatabaseTableFieldTypeMapping
- type DXDatabaseTableFieldsOrderBy
- type DXDatabaseTableRowsInfo
- func BaseSelect(ctx context.Context, db *sqlx.DB, tableName string, ...) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)
- func BaseTxSelect(ctx context.Context, tx *sqlx.Tx, tableName string, ...) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)
- func QueryRows(ctx context.Context, db *sqlx.DB, ...) (rowsInfo *DXDatabaseTableRowsInfo, rows []utils.JSON, err error)
- func RawQueryRows(ctx context.Context, db *sqlx.DB, ...) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)
- func RawTxQueryRows(ctx context.Context, tx *sqlx.Tx, ...) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)
- func Select(ctx context.Context, db *sqlx.DB, tableName string, ...) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)
- func SelectPaging(ctx context.Context, db *sqlx.DB, pageIndex int64, rowsPerPage int64, ...) (totalRowCount int64, rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, ...)
- func TxQueryRows(ctx context.Context, tx *sqlx.Tx, ...) (rowsInfo *DXDatabaseTableRowsInfo, rows []utils.JSON, err error)
- func TxSelect(ctx context.Context, tx *sqlx.Tx, tableName string, ...) (rowsInfo *DXDatabaseTableRowsInfo, r []utils.JSON, err error)
- type SQLExpression
Constants ¶
This section is empty.
Variables ¶
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 DbDriverFormatIdentifier ¶
DbDriverFormatIdentifier formats an identifier (column/table name) according to databases requirements
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 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 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 ¶
IsConnectionError checks if the error is a databases connection error
func LogDBDelete ¶
LogDBDelete logs a DELETE operation
func LogDBInsert ¶
LogDBInsert logs an INSERT operation
func LogDBOperation ¶
LogDBOperation logs a databases operation with SQL and arguments
func LogDBOperationWithJSON ¶
LogDBOperationWithJSON logs a databases operation with SQL and JSON arguments
func LogDBUpdate ¶
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 ¶
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 ¶
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 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 ¶
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 ¶
SQLPartUpdateSetFieldValues generates the SET clause for UPDATE statements
func SQLPartWhereAndFieldNameValues ¶
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 ¶
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 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 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 RawQueryRows ¶
func RawTxQueryRows ¶
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 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.