# README
SQLD For Dynamic SQL
sqld
is a package that provides type-safe dynamic SQL query building and execution. It offers two distinct subsystems:
- Structured Query System: Type-safe query building using squirrel with model metadata validation
- Safe Raw Query System: Validation and execution of raw SQL with named parameters and type checking
Key Features
Structured Query System
- Type-safe query building using squirrel
- Runtime validation against model metadata
- Field validation and mapping between JSON and database fields
- Built-in pagination (page-based or limit/offset)
- Multiple field ordering with direction control
- Support for both sql.DB and pgx.Conn
Safe Raw Query System
- Named parameters using {{param_name}} syntax
- Runtime type validation against parameter struct
- SQL syntax validation using PostgreSQL parser
- SQL injection prevention through parameter validation
- Optional field selection in results
Usage
Structured Query System
// Define and register your model
type Employee struct {
ID int64 `json:"id" db:"id"`
FirstName string `json:"first_name" db:"first_name"`
Department string `json:"department" db:"department"`
Salary float64 `json:"salary" db:"salary"`
IsActive bool `json:"is_active" db:"is_active"`
}
// Required: Implement Model interface
func (Employee) TableName() string {
return "employees"
}
// Register model for metadata validation
if err := sqld.Register(Employee{}); err != nil {
log.Fatal(err)
}
// Execute a query with type-safe building
resp, err := sqld.Execute[Employee](ctx, db, sqld.QueryRequest{
Select: []string{"id", "first_name", "department", "salary"},
Where: map[string]interface{}{
"department": "Engineering",
"is_active": true,
},
OrderBy: []sqld.OrderByClause{
{Field: "salary", Desc: true},
},
Pagination: &sqld.PaginationRequest{
Page: 1, // Page numbers start at 1
PageSize: 10, // Automatically capped at MaxPageSize (100)
},
})
// Response includes data and pagination metadata
fmt.Printf("Total Items: %d\n", resp.Pagination.TotalItems)
for _, employee := range resp.Data {
// Access fields using type-safe struct
}
Safe Raw Query System
// Define your parameter struct with both db and json tags
type QueryParams struct {
Department string `db:"department" json:"department"`
MinSalary float64 `db:"min_salary" json:"min_salary"`
}
// Define your result struct with db tags
type EmployeeResult struct {
ID int64 `db:"id"`
FirstName string `db:"first_name"`
Salary float64 `db:"salary"`
}
// Execute a raw query with validation
results, err := sqld.ExecuteRaw[QueryParams, EmployeeResult](
ctx,
db,
sqld.ExecuteRawRequest{
Query: `
SELECT id, first_name, salary
FROM employees
WHERE department = {{department}}
AND salary >= {{min_salary}}
ORDER BY salary DESC
`,
Params: map[string]interface{}{
"department": "Engineering",
"min_salary": 50000,
},
SelectFields: []string{"first_name", "salary"}, // Optional: filters which fields from the result struct are included in the output
},
)
Architecture
The package is built around these core components:
-
Model Metadata System
- Runtime model registration and validation
- Field mapping between database, Go types, and JSON
- Type validation for query parameters
-
Query Builder
- Type-safe query building using squirrel
- Parameter binding and validation
- Support for pagination and ordering
-
Executor
- Support for both sql.DB and pgx.Conn
- Result mapping with scany
- Pagination metadata handling
Documentation
For more detailed documentation and examples:
- Check the
examples/
directory for working examples - See
doc.go
for package documentation - Try the example server in
examples/main.go
# Packages
No description provided by the author
# Functions
AreTypesCompatible checks if valueType is suitable for fieldType.
AutoRegisterEnums queries the current schema for all user-defined enums, then registers them in pgx's TypeMap as text so we avoid unknown OID errors.
BuildMetadataMap uses reflection on the model struct to map db tags to fieldInfo.
CalculateOffset converts page/pageSize into offset.
CalculatePagination calculates pagination metadata.
Execute runs the query and returns properly scanned results.
ExecuteRaw executes a dynamic SQL query with named parameters and returns the results as a slice of maps.
ExtractNamedPlaceholders finds all named parameters in the {{param_name}} format.
GetNextPage returns the next page number.
GetPreviousPage returns the previous page number.
HasNextPage checks if there is a next page.
HasPreviousPage checks if there is a previous page.
IsNumericType returns true if the reflect.Type is one of the integer or float kinds.
IsTimeType returns true if the reflect.Type is time.Time or a known date/time type.
NewRegistry returns a new instance of the registry.
Register adds a model's metadata to the registry.
RegisterScanner registers a function that creates scanners for a specific type.
ReplaceNamedWithDollarPlaceholders replaces {{param_name}} with $1, $2, ...
ValidateMapParamsAgainstStructNamed ensures the params map matches the expected types from P.
ValidatePagination validates and normalizes pagination parameters.
# Constants
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
# Structs
No description provided by the author
Condition represents a single WHERE condition with an operator.
ErrModelNotRegistered is returned when a model is not found in the registry.
ExecuteRawRequest contains all parameters needed for ExecuteRaw.
Field represents a queryable field with its metadata.
ModelMetadata stores information about a model that represents a database table.
OrderByClause defines how to sort results.
PaginationRequest represents pagination parameters.
PaginationResponse contains pagination metadata.
QueryRequest represents the structure for building dynamic SQL queries.
QueryResponse represents the outgoing JSON structure.
Registry is a type-safe registry for model metadata and scanners.
# Interfaces
Model interface that represents a database table.
PgxQuerier interface for pgx operations.
Querier interface abstracts database operations.
No description provided by the author
# Type aliases
Operator represents a SQL comparison operator.
QueryResult represents a single row as map of field name to value.