Module: AppQuery

Defined in:
lib/app_query.rb,
lib/app_query/base.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/render_helpers.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: Mappable, Paginatable, RenderHelpers Classes: Base, BaseQuery, Configuration, Error, Q, Result, Tokenizer, UnrenderedQueryError

Constant Summary collapse

VERSION =
"0.6.0.rc4"

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



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/app_query.rb', line 98

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

.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