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  # => {author_id: {default: nil}, ...}
ArticlesQuery.vars   # => {order_by: {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

Examples:

SQL template (app/queries/articles.sql.erb)

SELECT * FROM articles
WHERE author_id = :author_id
<% if @editor %>AND status = :status<% end %>
ORDER BY <%= @order_by %>

Query class (app/queries/articles_query.rb)

class ArticlesQuery < AppQuery::BaseQuery
  bind :author_id
  bind :status, default: nil

  var :editor, default: false
  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

See Also:

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**params) ⇒ BaseQuery

Returns a new instance of BaseQuery.

Raises:

  • (ArgumentError)


143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/app_query/base_query.rb', line 143

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)



103
104
105
106
# File 'lib/app_query/base_query.rb', line 103

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



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

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



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

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)



119
120
121
122
# File 'lib/app_query/base_query.rb', line 119

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



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

def vars = _vars

Instance Method Details

#base_queryObject



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

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

#queryObject



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

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