Categorygithub.com/remiges-tech/sqld
modulepackage
0.8.0
Repository: https://github.com/remiges-tech/sqld.git
Documentation: pkg.go.dev

# README

SQLD For Dynamic SQL

sqld is a package that provides type-safe dynamic SQL query building and execution. It offers two distinct subsystems:

  1. Structured Query System: Type-safe query building using squirrel with model metadata validation
  2. 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:

  1. Model Metadata System

    • Runtime model registration and validation
    • Field mapping between database, Go types, and JSON
    • Type validation for query parameters
  2. Query Builder

    • Type-safe query building using squirrel
    • Parameter binding and validation
    • Support for pagination and ordering
  3. 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.