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 =

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.6.0.rc7"

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