Class: AppQuery::BaseQuery

Inherits:
Object
  • Object
show all
Defined in:
lib/app_query/base_query.rb

Overview

Base class for query objects that wrap SQL files.

BaseQuery provides a structured way to work with SQL queries compared to using AppQuery[:my_query] directly.

Benefits over AppQuery[:my_query]

1. Explicit parameter declaration

Declare required binds and vars upfront with defaults:

class ArticlesQuery < AppQuery::BaseQuery bind :author_id # required bind :status, default: nil # optional var :order_by, default: "created_at DESC" end

2. Unknown parameter validation

Raises ArgumentError for typos or unknown parameters:

ArticlesQuery.new(athor_id: 1) # => ArgumentError: Unknown param(s): athor_id

3. Self-documenting queries

Query classes show exactly what parameters are available:

ArticlesQuery.binds # => {default: nil, status: nil} ArticlesQuery.vars # => {default: "created_at DESC"}

4. Middleware support

Include concerns to add functionality:

class ApplicationQuery < AppQuery::BaseQuery include AppQuery::Paginatable include AppQuery::Mappable end

5. Casts

Define casts for columns:

class ApplicationQuery < AppQuery::BaseQuery cast metadata: :json end

Parameter types

  • bind: SQL bind parameters (safe from injection, used in WHERE clauses)
  • var: ERB template variables (for dynamic SQL generation like ORDER BY)

Naming convention

Query class name maps to SQL file:

  • ArticlesQuery -> articles.sql.erb
  • Reports::MonthlyQuery -> reports/monthly.sql.erb

Example

# app/queries/articles.sql.erb SELECT * FROM articles WHERE author_id = :author_id <% if @status %>AND status = :status<% end %> ORDER BY <%= @order_by %>

# app/queries/articles_query.rb class ArticlesQuery < AppQuery::BaseQuery bind :author_id bind :status, default: nil var :order_by, default: "created_at DESC" cast published_at: :datetime end

# Usage ArticlesQuery.new(author_id: 1).entries ArticlesQuery.new(author_id: 1, status: "draft", order_by: "title").first

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**params) ⇒ BaseQuery

Returns a new instance of BaseQuery.

Raises:

  • (ArgumentError)


138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/app_query/base_query.rb', line 138

def initialize(**params)
  all_known = self.class.binds.keys + self.class.vars.keys
  unknown = params.keys - all_known
  raise ArgumentError, "Unknown param(s): #{unknown.join(", ")}" if unknown.any?

  self.class.binds.merge(self.class.vars).each do |name, options|
    value = params.fetch(name) {
      default = options[:default]
      default.is_a?(Proc) ? instance_exec(&default) : default
    }
    instance_variable_set(:"@#{name}", value)
  end
end

Class Method Details

.bind(name, default: nil) ⇒ Object

Declares a bind parameter for the query.

Bind parameters are passed to the database driver and are safe from SQL injection. Use for values in WHERE, HAVING, etc.

Examples:

bind :user_id
bind :status, default: "active"
bind :since, default: -> { 1.week.ago }

Parameters:

  • name (Symbol)

    parameter name (used as :name in SQL)

  • default (Object, Proc) (defaults to: nil)

    default value (Proc is evaluated at instantiation)



98
99
100
101
# File 'lib/app_query/base_query.rb', line 98

def bind(name, default: nil)
  self._binds = _binds.merge(name => {default:})
  attr_reader name
end

.bindsHash

Returns declared bind parameters with their options.

Returns:

  • (Hash)

    declared bind parameters with their options



132
# File 'lib/app_query/base_query.rb', line 132

def binds = _binds

.cast(casts = nil) ⇒ Hash

Sets type casting for result columns.

Examples:

cast published_at: :datetime, metadata: :json

Parameters:

  • casts (Hash{Symbol => Symbol}) (defaults to: nil)

    column name to type mapping

Returns:

  • (Hash)

    current cast configuration when called without arguments



126
127
128
129
# File 'lib/app_query/base_query.rb', line 126

def cast(casts = nil)
  return _casts if casts.nil?
  self._casts = casts
end

.var(name, default: nil) ⇒ Object

Declares a template variable for the query.

Vars are available in ERB as both local variables and instance variables (@var). Use for dynamic SQL generation (ORDER BY, column selection, etc.)

Examples:

var :order_by, default: "created_at DESC"
var :columns, default: "*"

Parameters:

  • name (Symbol)

    variable name

  • default (Object, Proc) (defaults to: nil)

    default value (Proc is evaluated at instantiation)



114
115
116
117
# File 'lib/app_query/base_query.rb', line 114

def var(name, default: nil)
  self._vars = _vars.merge(name => {default:})
  attr_reader name
end

.varsHash

Returns declared template variables with their options.

Returns:

  • (Hash)

    declared template variables with their options



135
# File 'lib/app_query/base_query.rb', line 135

def vars = _vars

Instance Method Details

#base_queryObject



164
165
166
# File 'lib/app_query/base_query.rb', line 164

def base_query
  AppQuery[query_name, cast: self.class.cast]
end

#entriesObject



154
155
156
# File 'lib/app_query/base_query.rb', line 154

def entries
  select_all
end

#queryObject



158
159
160
161
162
# File 'lib/app_query/base_query.rb', line 158

def query
  @query ||= base_query
    .render(**render_vars)
    .with_binds(**bind_vars)
end