Module: AppQuery

Defined in:
lib/app_query.rb,
lib/app_query/rspec.rb,
lib/app_query/railtie.rb,
lib/app_query/version.rb,
lib/app_query/mappable.rb,
lib/app_query/tokenizer.rb,
lib/app_query/base_query.rb,
lib/app_query/paginatable.rb,
lib/app_query/rspec/helpers.rb,
lib/app_query/render_helpers.rb,
lib/generators/app_query/query_generator.rb,
lib/generators/app_query/example_generator.rb

Overview

AppQuery provides a way to work with raw SQL queries using ERB templating, parameter binding, and CTE manipulation.

Examples:

Using the global function

AppQuery("SELECT * FROM users WHERE id = $1").select_one(binds: [1])
AppQuery("SELECT * FROM users WHERE id = :id").select_one(binds: {id: 1})

Loading queries from files

# Loads from app/queries/invoices.sql
AppQuery[:invoices].select_all

Configuration

AppQuery.configure do |config|
  config.query_path = "db/queries"
end

CTE manipulation

AppQuery(<<~SQL).select_all("select * from articles where id = 1")
  WITH articles AS(...)
  SELECT * FROM articles
  ORDER BY id
SQL

Defined Under Namespace

Modules: Generators, Mappable, Paginatable, RSpec, RenderHelpers Classes: BaseQuery, Configuration, Error, Q, Railtie, Result, Tokenizer, UnrenderedQueryError

Constant Summary collapse

VERSION =

This should just contain the .dev of the upcoming version. When doing the actual release, CI will write the tag here before pushing the gem.

"0.8.0.dev"

Quoting Helpers collapse

Class Method Summary collapse

Class Method Details

.[](query_name, **opts) ⇒ Q

Loads a query from a file in the configured query path.

When no extension is provided, tries .sql first, then .sql.erb. Raises an error if both files exist (ambiguous).

Examples:

Load a .sql file

AppQuery[:invoices]  # loads app/queries/invoices.sql

Load a .sql.erb file (when .sql doesn't exist)

AppQuery[:dynamic_report]  # loads app/queries/dynamic_report.sql.erb

Load from a subdirectory

AppQuery["reports/weekly"]  # loads app/queries/reports/weekly.sql

Load with explicit extension

AppQuery["invoices.sql.erb"]  # loads app/queries/invoices.sql.erb

Parameters:

  • query_name (String, Symbol)

    the query name or path (without extension)

  • opts (Hash)

    additional options passed to AppQuery::Q#initialize

Returns:

  • (Q)

    a new query object loaded from the file

Raises:

  • (Error)

    if both .sql and .sql.erb files exist for the same name



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/app_query.rb', line 118

def self.[](query_name, **opts)
  base = Pathname.new(configuration.query_path) / query_name.to_s

  full_path = if File.extname(query_name.to_s).empty?
    sql_path = base.sub_ext(".sql").expand_path
    erb_path = base.sub_ext(".sql.erb").expand_path
    sql_exists = sql_path.exist?
    erb_exists = erb_path.exist?

    if sql_exists && erb_exists
      raise Error, "Ambiguous query name #{query_name.inspect}: both #{sql_path} and #{erb_path} exist"
    end

    sql_exists ? sql_path : erb_path
  else
    base.expand_path
  end

  Q.new(full_path.read, name: "AppQuery #{query_name}", filename: full_path.to_s, **opts)
end

.configurationConfiguration

Returns the current configuration.

Returns:



50
51
52
# File 'lib/app_query.rb', line 50

def self.configuration
  @configuration ||= AppQuery::Configuration.new
end

.configure {|Configuration| ... } ⇒ Object

Yields the configuration for modification.

Examples:

AppQuery.configure do |config|
  config.query_path = "db/queries"
end

Yields:



62
63
64
# File 'lib/app_query.rb', line 62

def self.configure
  yield configuration if block_given?
end

.quote_column(name) ⇒ String

Quotes a column name for safe use in SQL.

Parameters:

  • name (String, Symbol)

    the column name

Returns:

  • (String)

    the quoted column name



90
91
92
# File 'lib/app_query.rb', line 90

def self.quote_column(name)
  ActiveRecord::Base.connection.quote_column_name(name)
end

.quote_table(name) ⇒ String

Quotes a table name for safe use in SQL.

Parameters:

  • name (String, Symbol)

    the table name

Returns:

  • (String)

    the quoted table name



82
83
84
# File 'lib/app_query.rb', line 82

def self.quote_table(name)
  ActiveRecord::Base.connection.quote_table_name(name)
end

.reset_configuration!void

This method returns an undefined value.

Resets configuration to default values.



69
70
71
72
73
# File 'lib/app_query.rb', line 69

def self.reset_configuration!
  configure do |config|
    config.query_path = "app/queries"
  end
end

.table(name, **opts) ⇒ Q

Creates a query that selects all columns from a table.

Convenience method for quickly querying a table without writing SQL.

Examples:

Basic usage

AppQuery.table(:products).count
AppQuery.table(:products).take(5)

With binds

AppQuery.table(:users, binds: {active: true})
  .select_all("SELECT * FROM :_ WHERE active = :active")

Parameters:

  • name (Symbol, String)

    the table name

  • opts (Hash)

    additional options passed to AppQuery::Q#initialize

Returns:

  • (Q)

    a new query object selecting from the table



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

def self.table(name, **opts)
  Q.new("SELECT * FROM #{quote_table(name)}", name: "AppQuery.table(#{name})", **opts)
end