arel-9.0.0/0000755000004100000410000000000013272030740012471 5ustar www-datawww-dataarel-9.0.0/README.md0000644000004100000410000002075413272030740013760 0ustar www-datawww-data# Arel * http://github.com/rails/arel * [API Documentation](http://www.rubydoc.info/github/rails/arel) ## DESCRIPTION Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby. It 1. simplifies the generation of complex SQL queries, and 2. adapts to various RDBMSes. It is intended to be a framework framework; that is, you can build your own ORM with it, focusing on innovative object and collection modeling as opposed to database compatibility and query generation. ## Status For the moment, Arel uses Active Record's connection adapters to connect to the various engines and perform connection pooling, quoting, and type conversion. ## A Gentle Introduction Generating a query with Arel is simple. For example, in order to produce ```sql SELECT * FROM users ``` you construct a table relation and convert it to SQL: ```ruby users = Arel::Table.new(:users) query = users.project(Arel.sql('*')) query.to_sql ``` ### More Sophisticated Queries Here is a whirlwind tour through the most common SQL operators. These will probably cover 80% of all interaction with the database. First is the 'restriction' operator, `where`: ```ruby users.where(users[:name].eq('amy')) # => SELECT * FROM users WHERE users.name = 'amy' ``` What would, in SQL, be part of the `SELECT` clause is called in Arel a `projection`: ```ruby users.project(users[:id]) # => SELECT users.id FROM users ``` Comparison operators `=`, `!=`, `<`, `>`, `<=`, `>=`, `IN`: ```ruby users.where(users[:age].eq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" = 10 users.where(users[:age].not_eq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" != 10 users.where(users[:age].lt(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" < 10 users.where(users[:age].gt(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" > 10 users.where(users[:age].lteq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" <= 10 users.where(users[:age].gteq(10)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" >= 10 users.where(users[:age].in([20, 16, 17])).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE "users"."age" IN (20, 16, 17) ``` Bitwise operators `&`, `|`, `^`, `<<`, `>>`: ```ruby users.where((users[:bitmap] & 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" & 16) > 0 users.where((users[:bitmap] | 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" | 16) > 0 users.where((users[:bitmap] ^ 16).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" ^ 16) > 0 users.where((users[:bitmap] << 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" << 1) > 0 users.where((users[:bitmap] >> 1).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ("users"."bitmap" >> 1) > 0 users.where((~ users[:bitmap]).gt(0)).project(Arel.sql('*')) # => SELECT * FROM "users" WHERE ~ "users"."bitmap" > 0 ``` Joins resemble SQL strongly: ```ruby users.join(photos).on(users[:id].eq(photos[:user_id])) # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id ``` Left joins: ```ruby users.join(photos, Arel::Nodes::OuterJoin).on(users[:id].eq(photos[:user_id])) # => SELECT FROM users LEFT OUTER JOIN photos ON users.id = photos.user_id ``` What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel: ```ruby users.take(5) # => SELECT * FROM users LIMIT 5 users.skip(4) # => SELECT * FROM users OFFSET 4 ``` `GROUP BY` is called `group`: ```ruby users.project(users[:name]).group(users[:name]) # => SELECT users.name FROM users GROUP BY users.name ``` The best property of Arel is its "composability," or closure under all operations. For example, to restrict AND project, just "chain" the method invocations: ```ruby users \ .where(users[:name].eq('amy')) \ .project(users[:id]) \ # => SELECT users.id FROM users WHERE users.name = 'amy' ``` All operators are chainable in this way, and they are chainable any number of times, in any order. ```ruby users.where(users[:name].eq('bob')).where(users[:age].lt(25)) ``` The `OR` operator works like this: ```ruby users.where(users[:name].eq('bob').or(users[:age].lt(25))) ``` The `AND` operator behaves similarly. Here is an example of the `DISTINCT` operator: ```ruby posts = Arel::Table.new(:posts) posts.project(posts[:title]) posts.distinct posts.to_sql # => 'SELECT DISTINCT "posts"."title" FROM "posts"' ``` Aggregate functions `AVG`, `SUM`, `COUNT`, `MIN`, `MAX`, `HAVING`: ```ruby photos.group(photos[:user_id]).having(photos[:id].count.gt(5)) # => SELECT FROM photos GROUP BY photos.user_id HAVING COUNT(photos.id) > 5 users.project(users[:age].sum) # => SELECT SUM(users.age) FROM users users.project(users[:age].average) # => SELECT AVG(users.age) FROM users users.project(users[:age].maximum) # => SELECT MAX(users.age) FROM users users.project(users[:age].minimum) # => SELECT MIN(users.age) FROM users users.project(users[:age].count) # => SELECT COUNT(users.age) FROM users ``` Aliasing Aggregate Functions: ```ruby users.project(users[:age].average.as("mean_age")) # => SELECT AVG(users.age) AS mean_age FROM users ``` ### The Advanced Features The examples above are fairly simple and other libraries match or come close to matching the expressiveness of Arel (e.g. `Sequel` in Ruby). #### Inline math operations Suppose we have a table `products` with prices in different currencies. And we have a table `currency_rates`, of constantly changing currency rates. In Arel: ```ruby products = Arel::Table.new(:products) # Attributes: [:id, :name, :price, :currency_id] currency_rates = Arel::Table.new(:currency_rates) # Attributes: [:from_id, :to_id, :date, :rate] ``` Now, to order products by price in user preferred currency simply call: ```ruby products. join(:currency_rates).on(products[:currency_id].eq(currency_rates[:from_id])). where(currency_rates[:to_id].eq(user_preferred_currency), currency_rates[:date].eq(Date.today)). order(products[:price] * currency_rates[:rate]) ``` #### Complex Joins ##### Alias Where Arel really shines is in its ability to handle complex joins and aggregations. As a first example, let's consider an "adjacency list", a tree represented in a table. Suppose we have a table `comments`, representing a threaded discussion: ```ruby comments = Arel::Table.new(:comments) ``` And this table has the following attributes: ```ruby # [:id, :body, :parent_id] ``` The `parent_id` column is a foreign key from the `comments` table to itself. Joining a table to itself requires aliasing in SQL. This aliasing can be handled from Arel as below: ```ruby replies = comments.alias comments_with_replies = \ comments.join(replies).on(replies[:parent_id].eq(comments[:id])).where(comments[:id].eq(1)) # => SELECT * FROM comments INNER JOIN comments AS comments_2 # WHERE comments_2.parent_id = comments.id AND comments.id = 1 ``` This will return the reply for the first comment. ##### CTE [Common Table Expressions (CTE)](https://en.wikipedia.org/wiki/Common_table_expressions#Common_table_expression) support via: Create a `CTE` ```ruby cte_table = Arel::Table.new(:cte_table) composed_cte = Arel::Nodes::As.new(cte_table, photos.where(photos[:created_at].gt(Date.current))) ``` Use the created `CTE`: ```ruby users. join(cte_table).on(users[:id].eq(cte_table[:user_id])). project(users[:id], cte_table[:click].sum). with(composed_cte) # => WITH cte_table AS (SELECT FROM photos WHERE photos.created_at > '2014-05-02') # SELECT users.id, SUM(cte_table.click) # FROM users INNER JOIN cte_table ON users.id = cte_table.user_id ``` #### Write SQL strings When your query is too complex for `Arel`, you can use `Arel::SqlLiteral`: ```ruby photo_clicks = Arel::Nodes::SqlLiteral.new(<<-SQL CASE WHEN condition1 THEN calculation1 WHEN condition2 THEN calculation2 WHEN condition3 THEN calculation3 ELSE default_calculation END SQL ) photos.project(photo_clicks.as("photo_clicks")) # => SELECT CASE WHEN condition1 THEN calculation1 # WHEN condition2 THEN calculation2 # WHEN condition3 THEN calculation3 # ELSE default_calculation END # FROM "photos" ``` ## Contributing to Arel Arel is the work of many contributors. You're encouraged to submit pull requests, propose features and discuss issues. See [CONTRIBUTING](CONTRIBUTING.md). ## License Arel is released under the [MIT License](http://www.opensource.org/licenses/MIT). arel-9.0.0/History.txt0000644000004100000410000001710113272030740014673 0ustar www-datawww-data=== 9.0.0 / 2017-11-14 * Enhancements * `InsertManager#insert` is now chainable * Support multiple inserts === 8.0.0 / 2017-02-21 * Enhancements * Remove deprecated type casting support in Arel * Frozen all string literals in Arel === 7.1.1 / 2016-07-27 * Bug Fixes * Fix warning in `Casted#hash` === 7.1.0 / 2016-07-19 * Enhancements * Support Ruby 2.4 unified Integer class * Implement `CASE` conditional expression * Support for Bitwise Operations as `InfixOperations` === 7.0.0 / 2015-12-17 * Enhancements * Remove deprecated method `Table#primary_key` * Remove engine from the constructor arguments `Arel::Table` * Deprecate automatic type casting within Arel === 6.0.0 / 2014-11-25 * Enhancements * Remove deprecated `Arel::Expression` * Remove deprecated `Arel::SqlLiteral` * Remove deprecated `SelectManager#joins` * Remove deprecated `SelectManager#to_a` * Remove deprecated `Arel::Sql::Engine` * Remove deprecated `Arel::InnerJoin` constant * Remove deprecated `Arel::OuterJoin` constant == 5.0.0 / 2013-12-04 * Enhancements * Remove deprecated code * Bug Fixes * Fix serializing a relation when calling `to_yaml` === 4.0.2 / 2014-02-05 * Bug Fixes * Fix `SqlLiteral` YAML serialization * PostgreSQL bugfix for invalid SQL in subqueries == 4.0.1 / 2013-10-22 * Enhancements * Cache visitor dispatch on a per-visitor basis * Improve performance of #uniq across a large number of nodes * Bug Fixes * Make visitors threadsafe by removing @last_column * Support `columns_for_distinct` with Oracle adapter == 3.0.3 / 2013-11-12 * Enhancements * Support ANSI 2003 window functions * Bug Fixes * Fix joins in Informix == 3.0.2 / 2012-02-21 * Enhancements * Added a module for visiting and transforming bind values * Fix in [] to be false, not in [] to be true * Bug Fixes * Revert fix for LIMIT / OFFSET when query is ordered in Oracle == 3.0.1 / 2012-02-17 * Bug Fixes * Fixed LIMIT / OFFSET when query is ordered in Oracle == 3.0.0 / 2012-01-12 * Enhancements * Support connection pool and schema cache * Bug Fixes * Conditions with no column can be followed by other conditions in Postgres == 2.2.3 / 2012-02-21 * Enhancements * Added a module for visiting and transforming bind values == 2.2.2 / 2012-02-20 * Enhancements * Support LOCK * Allow using non-table alias as a right-hand relation name * Added SelectManager#distinct == 2.2.1 / 2011-09-15 * Enhancements * Added UpdateManager#key to access the key value * Added SelectManager#projections= to override any existing projections * Added SelectManager#source to get the source of the last select core in the AST == 2.2.0 / 2011-08-09 * Bug Fixes * The database connection caches visitors for generating SQL. * FALSE and TRUE nodes can be constructed. * Fixed ORDER BY / LIMIT clauses for UPDATE statements in Oracle. == 2.1.4 / 2011-07-25 * Bug Fixes * Fix depth-first traversal to understand ascending / descending nodes. * Parenthesis are suppressed with nested unions in MySQL. Thanks jhtwong! == 2.1.3 / 2011-06-27 * Bug Fixes * Fixed broken gem build. == 2.1.2 / 2011-06-27 * Bug Fixes * Visitors can define their own cache strategy so caches are not shared. Fixes #57 * Informix support fixed. Thanks Khronos. * Ordering nodes broken to subclasses. Thanks Ernie Miller! * Reversal supported in ordering nodes. Thanks Ernie Miller! == 2.1.1 / 2011/05/14 * Bug fixes * Fixed thread safety bug in ToSql visitor. Thanks Damon McCormick and Cameron Walters! == 2.1.0 / 2011/04/30 * Enhancements * AST is now Enumerable * AND nodes are now n-ary nodes * SQL Literals may be used as Attribute names * Added Arel::Nodes::NamedFunction for representing generic SQL functions * Add Arel::SelectManager#limit= * Add Arel::SelectManager#offset * Add Arel::SelectManager#offset= * Added Arel::SelectManager#create_insert for building an insert manager. * SQL Literals are allowed for values in INSERT statements. * Math operations have been added to attributes, thanks to Vladimir Meremyanin. * Bug fixes * MSSQL adds TOP to sub selects * Assigning nil to take() removes LIMIT from statement. * Assigning nil to offset() removes OFFSET from statement. * TableAlias leg ordering fixed * Deprecations * Calls to `insert` are deprecated. Please use `compile_insert` then call `to_sql` on the resulting object and execute that SQL. * Calls to `update` are deprecated. Please use `compile_update` then call `to_sql` on the resulting object and execute that SQL. * Calls to `delete` are deprecated. Please use `compile_delete` then call `to_sql` on the resulting object and execute that SQL. * Arel::Table#joins is deprecated and will be removed in 3.0.0 with no replacement. * Arel::Table#columns is deprecated and will be removed in 3.0.0 with no replacement. * Arel::Table.table_cache is deprecated and will be removed in 3.0.0 with no replacement. * Arel::Nodes::And.new takes a single list instead of left and right. * Arel::Table#primary_key is deprecated and will be removed in 3.0.0 with no replacement. * Arel::SelectManager#where_clauses is deprecated and will be removed in 3.0.0 with no replacement. * Arel::SelectManager#wheres is deprecated and will be removed in 3.0.0 with no replacement. == 2.0.9 / 2010/02/25 * Bug Fixes * Custom LOCK strings are allowed. Fixes LH # 6399 https://rails.lighthouseapp.com/projects/8994/tickets/6399-allow-database-specific-locking-clauses-to-be-used * Strings passed to StringManager#on will be automatically tagged as SQL literals. Fixes Rails LH #6384 https://rails.lighthouseapp.com/projects/8994/tickets/6384-activerecord-303-and-3-0-stable-generate-invalid-sql-for-has_many-through-association-with-conditions == 2.0.8 / 2010/02/08 * Bug Fixes * Added set operation support * Fixed problems with *_any / *_all methods. == 2.0.7 * Bug Fixes * Limit members are visited * Fixing MSSQL TOP support == 2.0.6 12/01/2010 * Bug Fixes * Rails 3.0.x does not like that Node is Enumerable, so removing for now. == 2.0.5 11/30/2010 * Enhancements * Arel::Visitors::DepthFirst can walk your AST depth first * Arel::Nodes::Node is enumerable, depth first * Bug fixes * #lock will lock SELECT statements "FOR UPDATE" on mysql * Nodes::Node#not factory method added for creating Nodes::Not nodes * Added an As node * Deprecations * Support for Subclasses of core classes will be removed in Arel version 2.2.0 == 2.0.4 * Bug fixes * Speed improvements for Range queries. Thanks Rolf Timmermans! == 2.0.3 * Bug fixes * Fixing Oracle support * Added a visitor for "Class" objects == 2.0.2 * Bug fixes * MySQL selects from DUAL on empty FROM * Visitor translates nil to NULL * Visitor translates Bignum properly == 2.0.1 * Bug fixes == 2.0.0 / 2010-08-01 * Enhancements * Recreate library using the Visitor pattern. http://en.wikipedia.org/wiki/Visitor_pattern == 0.3.0 / 2010-03-10 * Enhancements * Introduced "SQL compilers" for query generation. * Added support for Oracle (Raimonds Simanovskis) and IBM/DB (Praveen Devarao). * Improvements to give better support to Active Record. == 0.2.1 / 2010-02-05 * Enhancements * Bump dependency version of activesupport to 3.0.0.beta == 0.2.0 / 2010-01-31 * Ruby 1.9 compatibility * Many improvements to support the Arel integration into Active Record (see `git log v0.1.0..v0.2.0`) * Thanks to Emilio Tagua and Pratik Naik for many significant contributions! == 0.1.0 / 2009-08-06 * 1 major enhancement * Birthday! arel-9.0.0/lib/0000755000004100000410000000000013272030740013237 5ustar www-datawww-dataarel-9.0.0/lib/arel/0000755000004100000410000000000013272030740014162 5ustar www-datawww-dataarel-9.0.0/lib/arel/factory_methods.rb0000644000004100000410000000151613272030740017704 0ustar www-datawww-data# frozen_string_literal: true module Arel ### # Methods for creating various nodes module FactoryMethods def create_true Arel::Nodes::True.new end def create_false Arel::Nodes::False.new end def create_table_alias relation, name Nodes::TableAlias.new(relation, name) end def create_join to, constraint = nil, klass = Nodes::InnerJoin klass.new(to, constraint) end def create_string_join to create_join to, nil, Nodes::StringJoin end def create_and clauses Nodes::And.new clauses end def create_on expr Nodes::On.new expr end def grouping expr Nodes::Grouping.new expr end ### # Create a LOWER() function def lower column Nodes::NamedFunction.new 'LOWER', [Nodes.build_quoted(column)] end end end arel-9.0.0/lib/arel/select_manager.rb0000644000004100000410000001273213272030740017465 0ustar www-datawww-data# frozen_string_literal: true require 'arel/collectors/sql_string' module Arel class SelectManager < Arel::TreeManager include Arel::Crud STRING_OR_SYMBOL_CLASS = [Symbol, String] def initialize table = nil super() @ast = Nodes::SelectStatement.new @ctx = @ast.cores.last from table end def initialize_copy other super @ctx = @ast.cores.last end def limit @ast.limit && @ast.limit.expr end alias :taken :limit def constraints @ctx.wheres end def offset @ast.offset && @ast.offset.expr end def skip amount if amount @ast.offset = Nodes::Offset.new(amount) else @ast.offset = nil end self end alias :offset= :skip ### # Produces an Arel::Nodes::Exists node def exists Arel::Nodes::Exists.new @ast end def as other create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other) end def lock locking = Arel.sql('FOR UPDATE') case locking when true locking = Arel.sql('FOR UPDATE') when Arel::Nodes::SqlLiteral when String locking = Arel.sql locking end @ast.lock = Nodes::Lock.new(locking) self end def locked @ast.lock end def on *exprs @ctx.source.right.last.right = Nodes::On.new(collapse(exprs)) self end def group *columns columns.each do |column| # FIXME: backwards compat column = Nodes::SqlLiteral.new(column) if String === column column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column @ctx.groups.push Nodes::Group.new column end self end def from table table = Nodes::SqlLiteral.new(table) if String === table case table when Nodes::Join @ctx.source.right << table else @ctx.source.left = table end self end def froms @ast.cores.map { |x| x.from }.compact end def join relation, klass = Nodes::InnerJoin return self unless relation case relation when String, Nodes::SqlLiteral raise EmptyJoinError if relation.empty? klass = Nodes::StringJoin end @ctx.source.right << create_join(relation, nil, klass) self end def outer_join relation join(relation, Nodes::OuterJoin) end def having expr @ctx.havings << expr self end def window name window = Nodes::NamedWindow.new(name) @ctx.windows.push window window end def project *projections # FIXME: converting these to SQLLiterals is probably not good, but # rails tests require it. @ctx.projections.concat projections.map { |x| STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x } self end def projections @ctx.projections end def projections= projections @ctx.projections = projections end def distinct(value = true) if value @ctx.set_quantifier = Arel::Nodes::Distinct.new else @ctx.set_quantifier = nil end self end def distinct_on(value) if value @ctx.set_quantifier = Arel::Nodes::DistinctOn.new(value) else @ctx.set_quantifier = nil end self end def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @ast.orders.concat expr.map { |x| STRING_OR_SYMBOL_CLASS.include?(x.class) ? Nodes::SqlLiteral.new(x.to_s) : x } self end def orders @ast.orders end def where_sql engine = Table.engine return if @ctx.wheres.empty? viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection) Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value end def union operation, other = nil if other node_class = Nodes.const_get("Union#{operation.to_s.capitalize}") else other = operation node_class = Nodes::Union end node_class.new self.ast, other.ast end def intersect other Nodes::Intersect.new ast, other.ast end def except other Nodes::Except.new ast, other.ast end alias :minus :except def with *subqueries if subqueries.first.is_a? Symbol node_class = Nodes.const_get("With#{subqueries.shift.to_s.capitalize}") else node_class = Nodes::With end @ast.with = node_class.new(subqueries.flatten) self end def take limit if limit @ast.limit = Nodes::Limit.new(limit) @ctx.top = Nodes::Top.new(limit) else @ast.limit = nil @ctx.top = nil end self end alias limit= take def join_sources @ctx.source.right end def source @ctx.source end class Row < Struct.new(:data) # :nodoc: def id data['id'] end def method_missing(name, *args) name = name.to_s return data[name] if data.key?(name) super end end private def collapse exprs, existing = nil exprs = exprs.unshift(existing.expr) if existing exprs = exprs.compact.map { |expr| if String === expr # FIXME: Don't do this automatically Arel.sql(expr) else expr end } if exprs.length == 1 exprs.first else create_and exprs end end end end arel-9.0.0/lib/arel/order_predications.rb0000644000004100000410000000027413272030740020371 0ustar www-datawww-data# frozen_string_literal: true module Arel module OrderPredications def asc Nodes::Ascending.new self end def desc Nodes::Descending.new self end end end arel-9.0.0/lib/arel/tree_manager.rb0000644000004100000410000000137213272030740017143 0ustar www-datawww-data# frozen_string_literal: true require 'arel/collectors/sql_string' module Arel class TreeManager include Arel::FactoryMethods attr_reader :ast def initialize @ctx = nil end def to_dot collector = Arel::Collectors::PlainString.new collector = Visitors::Dot.new.accept @ast, collector collector.value end def to_sql engine = Table.engine collector = Arel::Collectors::SQLString.new collector = engine.connection.visitor.accept @ast, collector collector.value end def initialize_copy other super @ast = @ast.clone end def where expr if Arel::TreeManager === expr expr = expr.ast end @ctx.wheres << expr self end end end arel-9.0.0/lib/arel/nodes/0000755000004100000410000000000013272030740015272 5ustar www-datawww-dataarel-9.0.0/lib/arel/nodes/terminal.rb0000644000004100000410000000037313272030740017435 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Distinct < Arel::Nodes::Node def hash self.class.hash end def eql? other self.class == other.class end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/ascending.rb0000644000004100000410000000045513272030740017556 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Ascending < Ordering def reverse Descending.new(expr) end def direction :asc end def ascending? true end def descending? false end end end end arel-9.0.0/lib/arel/nodes/bind_param.rb0000644000004100000410000000066413272030740017721 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class BindParam < Node attr_accessor :value def initialize(value) @value = value super() end def hash [self.class, self.value].hash end def eql?(other) other.is_a?(BindParam) && value == other.value end alias :== :eql? def nil? value.nil? end end end end arel-9.0.0/lib/arel/nodes/regexp.rb0000644000004100000410000000046413272030740017115 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Regexp < Binary attr_accessor :case_sensitive def initialize(left, right, case_sensitive = true) super(left, right) @case_sensitive = case_sensitive end end class NotRegexp < Regexp; end end end arel-9.0.0/lib/arel/nodes/over.rb0000644000004100000410000000036713272030740016600 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Over < Binary include Arel::AliasPredication def initialize(left, right = nil) super(left, right) end def operator; 'OVER' end end end endarel-9.0.0/lib/arel/nodes/named_function.rb0000644000004100000410000000062113272030740020607 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class NamedFunction < Arel::Nodes::Function attr_accessor :name def initialize name, expr, aliaz = nil super(expr, aliaz) @name = name end def hash super ^ @name.hash end def eql? other super && self.name == other.name end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/join_source.rb0000644000004100000410000000055713272030740020145 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes ### # Class that represents a join source # # http://www.sqlite.org/syntaxdiagrams.html#join-source class JoinSource < Arel::Nodes::Binary def initialize single_source, joinop = [] super end def empty? !left && right.empty? end end end end arel-9.0.0/lib/arel/nodes/sql_literal.rb0000644000004100000410000000047613272030740020141 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class SqlLiteral < String include Arel::Expressions include Arel::Predications include Arel::AliasPredication include Arel::OrderPredications def encode_with(coder) coder.scalar = self.to_s end end end end arel-9.0.0/lib/arel/nodes/descending.rb0000644000004100000410000000045613272030740017727 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Descending < Ordering def reverse Ascending.new(expr) end def direction :desc end def ascending? false end def descending? true end end end end arel-9.0.0/lib/arel/nodes/select_core.rb0000644000004100000410000000317213272030740020111 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class SelectCore < Arel::Nodes::Node attr_accessor :top, :projections, :wheres, :groups, :windows attr_accessor :havings, :source, :set_quantifier def initialize super() @source = JoinSource.new nil @top = nil # http://savage.net.au/SQL/sql-92.bnf.html#set%20quantifier @set_quantifier = nil @projections = [] @wheres = [] @groups = [] @havings = [] @windows = [] end def from @source.left end def from= value @source.left = value end alias :froms= :from= alias :froms :from def initialize_copy other super @source = @source.clone if @source @projections = @projections.clone @wheres = @wheres.clone @groups = @groups.clone @havings = @havings.clone @windows = @windows.clone end def hash [ @source, @top, @set_quantifier, @projections, @wheres, @groups, @havings, @windows ].hash end def eql? other self.class == other.class && self.source == other.source && self.top == other.top && self.set_quantifier == other.set_quantifier && self.projections == other.projections && self.wheres == other.wheres && self.groups == other.groups && self.havings == other.havings && self.windows == other.windows end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/table_alias.rb0000644000004100000410000000107713272030740020064 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class TableAlias < Arel::Nodes::Binary alias :name :right alias :relation :left alias :table_alias :name def [] name Attribute.new(self, name) end def table_name relation.respond_to?(:name) ? relation.name : name end def type_cast_for_database(*args) relation.type_cast_for_database(*args) end def able_to_type_cast? relation.respond_to?(:able_to_type_cast?) && relation.able_to_type_cast? end end end end arel-9.0.0/lib/arel/nodes/casted.rb0000644000004100000410000000213013272030740017056 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Casted < Arel::Nodes::Node # :nodoc: attr_reader :val, :attribute def initialize val, attribute @val = val @attribute = attribute super() end def nil?; @val.nil?; end def hash [self.class, val, attribute].hash end def eql? other self.class == other.class && self.val == other.val && self.attribute == other.attribute end alias :== :eql? end class Quoted < Arel::Nodes::Unary # :nodoc: alias :val :value def nil?; val.nil?; end end def self.build_quoted other, attribute = nil case other when Arel::Nodes::Node, Arel::Attributes::Attribute, Arel::Table, Arel::Nodes::BindParam, Arel::SelectManager, Arel::Nodes::Quoted, Arel::Nodes::SqlLiteral other else case attribute when Arel::Attributes::Attribute Casted.new other, attribute else Quoted.new other end end end end end arel-9.0.0/lib/arel/nodes/case.rb0000644000004100000410000000247613272030740016543 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Case < Arel::Nodes::Node include Arel::OrderPredications include Arel::Predications include Arel::AliasPredication attr_accessor :case, :conditions, :default def initialize expression = nil, default = nil @case = expression @conditions = [] @default = default end def when condition, expression = nil @conditions << When.new(Nodes.build_quoted(condition), expression) self end def then expression @conditions.last.right = Nodes.build_quoted(expression) self end def else expression @default = Else.new Nodes.build_quoted(expression) self end def initialize_copy other super @case = @case.clone if @case @conditions = @conditions.map { |x| x.clone } @default = @default.clone if @default end def hash [@case, @conditions, @default].hash end def eql? other self.class == other.class && self.case == other.case && self.conditions == other.conditions && self.default == other.default end alias :== :eql? end class When < Binary # :nodoc: end class Else < Unary # :nodoc: end end end arel-9.0.0/lib/arel/nodes/values.rb0000644000004100000410000000045613272030740017123 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Values < Arel::Nodes::Binary alias :expressions :left alias :expressions= :left= alias :columns :right alias :columns= :right= def initialize exprs, columns = [] super end end end end arel-9.0.0/lib/arel/nodes/values_list.rb0000644000004100000410000000056413272030740020156 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class ValuesList < Node attr_reader :rows def initialize(rows) @rows = rows super() end def hash @rows.hash end def eql? other self.class == other.class && self.rows == other.rows end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/and.rb0000644000004100000410000000076413272030740016370 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class And < Arel::Nodes::Node attr_reader :children def initialize children super() @children = children end def left children.first end def right children[1] end def hash children.hash end def eql? other self.class == other.class && self.children == other.children end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/extract.rb0000644000004100000410000000071413272030740017273 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Extract < Arel::Nodes::Unary include Arel::AliasPredication include Arel::Predications attr_accessor :field def initialize expr, field super(expr) @field = field end def hash super ^ @field.hash end def eql? other super && self.field == other.field end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/unqualified_column.rb0000644000004100000410000000051313272030740021501 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class UnqualifiedColumn < Arel::Nodes::Unary alias :attribute :expr alias :attribute= :expr= def relation @expr.relation end def column @expr.column end def name @expr.name end end end end arel-9.0.0/lib/arel/nodes/true.rb0000644000004100000410000000036713272030740016604 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class True < Arel::Nodes::Node def hash self.class.hash end def eql? other self.class == other.class end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/binary.rb0000644000004100000410000000162613272030740017110 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Binary < Arel::Nodes::Node attr_accessor :left, :right def initialize left, right super() @left = left @right = right end def initialize_copy other super @left = @left.clone if @left @right = @right.clone if @right end def hash [self.class, @left, @right].hash end def eql? other self.class == other.class && self.left == other.left && self.right == other.right end alias :== :eql? end %w{ As Assignment Between GreaterThan GreaterThanOrEqual Join LessThan LessThanOrEqual NotEqual NotIn Or Union UnionAll Intersect Except }.each do |name| const_set name, Class.new(Binary) end end end arel-9.0.0/lib/arel/nodes/select_statement.rb0000644000004100000410000000177113272030740021170 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class SelectStatement < Arel::Nodes::Node attr_reader :cores attr_accessor :limit, :orders, :lock, :offset, :with def initialize cores = [SelectCore.new] super() @cores = cores @orders = [] @limit = nil @lock = nil @offset = nil @with = nil end def initialize_copy other super @cores = @cores.map { |x| x.clone } @orders = @orders.map { |x| x.clone } end def hash [@cores, @orders, @limit, @lock, @offset, @with].hash end def eql? other self.class == other.class && self.cores == other.cores && self.orders == other.orders && self.limit == other.limit && self.lock == other.lock && self.offset == other.offset && self.with == other.with end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/false.rb0000644000004100000410000000037013272030740016711 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class False < Arel::Nodes::Node def hash self.class.hash end def eql? other self.class == other.class end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/right_outer_join.rb0000644000004100000410000000017013272030740021167 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class RightOuterJoin < Arel::Nodes::Join end end end arel-9.0.0/lib/arel/nodes/with.rb0000644000004100000410000000025713272030740016576 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class With < Arel::Nodes::Unary alias children expr end class WithRecursive < With; end end end arel-9.0.0/lib/arel/nodes/count.rb0000644000004100000410000000040213272030740016743 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Count < Arel::Nodes::Function include Math def initialize expr, distinct = false, aliaz = nil super(expr, aliaz) @distinct = distinct end end end end arel-9.0.0/lib/arel/nodes/node.rb0000644000004100000410000000301613272030740016544 0ustar www-datawww-data# frozen_string_literal: true require 'arel/collectors/sql_string' module Arel module Nodes ### # Abstract base class for all AST nodes class Node include Arel::FactoryMethods include Enumerable if $DEBUG def _caller @caller end def initialize @caller = caller.dup end end ### # Factory method to create a Nodes::Not node that has the recipient of # the caller as a child. def not Nodes::Not.new self end ### # Factory method to create a Nodes::Grouping node that has an Nodes::Or # node as a child. def or right Nodes::Grouping.new Nodes::Or.new(self, right) end ### # Factory method to create an Nodes::And node. def and right Nodes::And.new [self, right] end # FIXME: this method should go away. I don't like people calling # to_sql on non-head nodes. This forces us to walk the AST until we # can find a node that has a "relation" member. # # Maybe we should just use `Table.engine`? :'( def to_sql engine = Table.engine collector = Arel::Collectors::SQLString.new collector = engine.connection.visitor.accept self, collector collector.value end # Iterate through AST, nodes will be yielded depth-first def each &block return enum_for(:each) unless block_given? ::Arel::Visitors::DepthFirst.new(block).accept self end end end end arel-9.0.0/lib/arel/nodes/string_join.rb0000644000004100000410000000026313272030740020145 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class StringJoin < Arel::Nodes::Join def initialize left, right = nil super end end end end arel-9.0.0/lib/arel/nodes/insert_statement.rb0000644000004100000410000000150613272030740021211 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class InsertStatement < Arel::Nodes::Node attr_accessor :relation, :columns, :values, :select def initialize super() @relation = nil @columns = [] @values = nil @select = nil end def initialize_copy other super @columns = @columns.clone @values = @values.clone if @values @select = @select.clone if @select end def hash [@relation, @columns, @values, @select].hash end def eql? other self.class == other.class && self.relation == other.relation && self.columns == other.columns && self.select == other.select && self.values == other.values end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/equality.rb0000644000004100000410000000031113272030740017447 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Equality < Arel::Nodes::Binary def operator; :== end alias :operand1 :left alias :operand2 :right end end end arel-9.0.0/lib/arel/nodes/unary_operation.rb0000644000004100000410000000100513272030740021031 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class UnaryOperation < Unary include Arel::Expressions include Arel::Predications include Arel::OrderPredications include Arel::AliasPredication include Arel::Math attr_reader :operator def initialize operator, operand super(operand) @operator = operator end end class BitwiseNot < UnaryOperation def initialize operand super(:~, operand) end end end endarel-9.0.0/lib/arel/nodes/window.rb0000644000004100000410000000460213272030740017130 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Window < Arel::Nodes::Node attr_accessor :orders, :framing, :partitions def initialize @orders = [] @partitions = [] @framing = nil end def order *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @orders.concat expr.map { |x| String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x } self end def partition *expr # FIXME: We SHOULD NOT be converting these to SqlLiteral automatically @partitions.concat expr.map { |x| String === x || Symbol === x ? Nodes::SqlLiteral.new(x.to_s) : x } self end def frame(expr) @framing = expr end def rows(expr = nil) if @framing Rows.new(expr) else frame(Rows.new(expr)) end end def range(expr = nil) if @framing Range.new(expr) else frame(Range.new(expr)) end end def initialize_copy other super @orders = @orders.map { |x| x.clone } end def hash [@orders, @framing].hash end def eql? other self.class == other.class && self.orders == other.orders && self.framing == other.framing && self.partitions == other.partitions end alias :== :eql? end class NamedWindow < Window attr_accessor :name def initialize name super() @name = name end def initialize_copy other super @name = other.name.clone end def hash super ^ @name.hash end def eql? other super && self.name == other.name end alias :== :eql? end class Rows < Unary def initialize(expr = nil) super(expr) end end class Range < Unary def initialize(expr = nil) super(expr) end end class CurrentRow < Node def hash self.class.hash end def eql? other self.class == other.class end alias :== :eql? end class Preceding < Unary def initialize(expr = nil) super(expr) end end class Following < Unary def initialize(expr = nil) super(expr) end end end end arel-9.0.0/lib/arel/nodes/grouping.rb0000644000004100000410000000020713272030740017450 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Grouping < Unary include Arel::Predications end end end arel-9.0.0/lib/arel/nodes/unary.rb0000644000004100000410000000123313272030740016754 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Unary < Arel::Nodes::Node attr_accessor :expr alias :value :expr def initialize expr super() @expr = expr end def hash @expr.hash end def eql? other self.class == other.class && self.expr == other.expr end alias :== :eql? end %w{ Bin Cube DistinctOn Group GroupingElement GroupingSet Limit Lock Not Offset On Ordering RollUp Top }.each do |name| const_set(name, Class.new(Unary)) end end end arel-9.0.0/lib/arel/nodes/delete_statement.rb0000644000004100000410000000065213272030740021150 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class DeleteStatement < Arel::Nodes::Binary attr_accessor :limit alias :relation :left alias :relation= :left= alias :wheres :right alias :wheres= :right= def initialize relation = nil, wheres = [] super end def initialize_copy other super @right = @right.clone end end end end arel-9.0.0/lib/arel/nodes/infix_operation.rb0000644000004100000410000000314513272030740021017 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class InfixOperation < Binary include Arel::Expressions include Arel::Predications include Arel::OrderPredications include Arel::AliasPredication include Arel::Math attr_reader :operator def initialize operator, left, right super(left, right) @operator = operator end end class Multiplication < InfixOperation def initialize left, right super(:*, left, right) end end class Division < InfixOperation def initialize left, right super(:/, left, right) end end class Addition < InfixOperation def initialize left, right super(:+, left, right) end end class Subtraction < InfixOperation def initialize left, right super(:-, left, right) end end class Concat < InfixOperation def initialize left, right super('||', left, right) end end class BitwiseAnd < InfixOperation def initialize left, right super(:&, left, right) end end class BitwiseOr < InfixOperation def initialize left, right super(:|, left, right) end end class BitwiseXor < InfixOperation def initialize left, right super(:^, left, right) end end class BitwiseShiftLeft < InfixOperation def initialize left, right super(:<<, left, right) end end class BitwiseShiftRight < InfixOperation def initialize left, right super(:>>, left, right) end end end end arel-9.0.0/lib/arel/nodes/matches.rb0000644000004100000410000000063113272030740017243 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Matches < Binary attr_reader :escape attr_accessor :case_sensitive def initialize(left, right, escape = nil, case_sensitive = false) super(left, right) @escape = escape && Nodes.build_quoted(escape) @case_sensitive = case_sensitive end end class DoesNotMatch < Matches; end end end arel-9.0.0/lib/arel/nodes/function.rb0000644000004100000410000000171213272030740017445 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class Function < Arel::Nodes::Node include Arel::Predications include Arel::WindowPredications include Arel::OrderPredications attr_accessor :expressions, :alias, :distinct def initialize expr, aliaz = nil super() @expressions = expr @alias = aliaz && SqlLiteral.new(aliaz) @distinct = false end def as aliaz self.alias = SqlLiteral.new(aliaz) self end def hash [@expressions, @alias, @distinct].hash end def eql? other self.class == other.class && self.expressions == other.expressions && self.alias == other.alias && self.distinct == other.distinct end alias :== :eql? end %w{ Sum Exists Max Min Avg }.each do |name| const_set(name, Class.new(Function)) end end end arel-9.0.0/lib/arel/nodes/inner_join.rb0000644000004100000410000000016313272030740017751 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class InnerJoin < Arel::Nodes::Join end end end arel-9.0.0/lib/arel/nodes/update_statement.rb0000644000004100000410000000163713272030740021174 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class UpdateStatement < Arel::Nodes::Node attr_accessor :relation, :wheres, :values, :orders, :limit attr_accessor :key def initialize @relation = nil @wheres = [] @values = [] @orders = [] @limit = nil @key = nil end def initialize_copy other super @wheres = @wheres.clone @values = @values.clone end def hash [@relation, @wheres, @values, @orders, @limit, @key].hash end def eql? other self.class == other.class && self.relation == other.relation && self.wheres == other.wheres && self.values == other.values && self.orders == other.orders && self.limit == other.limit && self.key == other.key end alias :== :eql? end end end arel-9.0.0/lib/arel/nodes/full_outer_join.rb0000644000004100000410000000016713272030740021022 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class FullOuterJoin < Arel::Nodes::Join end end end arel-9.0.0/lib/arel/nodes/in.rb0000644000004100000410000000014313272030740016223 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class In < Equality end end end arel-9.0.0/lib/arel/nodes/outer_join.rb0000644000004100000410000000016313272030740017774 0ustar www-datawww-data# frozen_string_literal: true module Arel module Nodes class OuterJoin < Arel::Nodes::Join end end end arel-9.0.0/lib/arel/expressions.rb0000644000004100000410000000065713272030740017101 0ustar www-datawww-data# frozen_string_literal: true module Arel module Expressions def count distinct = false Nodes::Count.new [self], distinct end def sum Nodes::Sum.new [self] end def maximum Nodes::Max.new [self] end def minimum Nodes::Min.new [self] end def average Nodes::Avg.new [self] end def extract field Nodes::Extract.new [self], field end end end arel-9.0.0/lib/arel/errors.rb0000644000004100000410000000020013272030740016013 0ustar www-datawww-data# frozen_string_literal: true module Arel class ArelError < StandardError end class EmptyJoinError < ArelError end end arel-9.0.0/lib/arel/visitors/0000755000004100000410000000000013272030740016044 5ustar www-datawww-dataarel-9.0.0/lib/arel/visitors/dot.rb0000644000004100000410000002036713272030740017167 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class Dot < Arel::Visitors::Visitor class Node # :nodoc: attr_accessor :name, :id, :fields def initialize name, id, fields = [] @name = name @id = id @fields = fields end end class Edge < Struct.new :name, :from, :to # :nodoc: end def initialize super() @nodes = [] @edges = [] @node_stack = [] @edge_stack = [] @seen = {} end def accept object, collector visit object collector << to_dot end private def visit_Arel_Nodes_Ordering o visit_edge o, "expr" end def visit_Arel_Nodes_TableAlias o visit_edge o, "name" visit_edge o, "relation" end def visit_Arel_Nodes_Count o visit_edge o, "expressions" visit_edge o, "distinct" end def visit_Arel_Nodes_Values o visit_edge o, "expressions" end def visit_Arel_Nodes_StringJoin o visit_edge o, "left" end def visit_Arel_Nodes_InnerJoin o visit_edge o, "left" visit_edge o, "right" end alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin def visit_Arel_Nodes_DeleteStatement o visit_edge o, "relation" visit_edge o, "wheres" end def unary o visit_edge o, "expr" end alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Cube :unary alias :visit_Arel_Nodes_RollUp :unary alias :visit_Arel_Nodes_GroupingSet :unary alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary alias :visit_Arel_Nodes_Not :unary alias :visit_Arel_Nodes_Offset :unary alias :visit_Arel_Nodes_On :unary alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary alias :visit_Arel_Nodes_Preceding :unary alias :visit_Arel_Nodes_Following :unary alias :visit_Arel_Nodes_Rows :unary alias :visit_Arel_Nodes_Range :unary def window o visit_edge o, "partitions" visit_edge o, "orders" visit_edge o, "framing" end alias :visit_Arel_Nodes_Window :window def named_window o visit_edge o, "partitions" visit_edge o, "orders" visit_edge o, "framing" visit_edge o, "name" end alias :visit_Arel_Nodes_NamedWindow :named_window def function o visit_edge o, "expressions" visit_edge o, "distinct" visit_edge o, "alias" end alias :visit_Arel_Nodes_Exists :function alias :visit_Arel_Nodes_Min :function alias :visit_Arel_Nodes_Max :function alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Sum :function def extract o visit_edge o, "expressions" visit_edge o, "alias" end alias :visit_Arel_Nodes_Extract :extract def visit_Arel_Nodes_NamedFunction o visit_edge o, "name" visit_edge o, "expressions" visit_edge o, "distinct" visit_edge o, "alias" end def visit_Arel_Nodes_InsertStatement o visit_edge o, "relation" visit_edge o, "columns" visit_edge o, "values" end def visit_Arel_Nodes_SelectCore o visit_edge o, "source" visit_edge o, "projections" visit_edge o, "wheres" visit_edge o, "windows" end def visit_Arel_Nodes_SelectStatement o visit_edge o, "cores" visit_edge o, "limit" visit_edge o, "orders" visit_edge o, "offset" end def visit_Arel_Nodes_UpdateStatement o visit_edge o, "relation" visit_edge o, "wheres" visit_edge o, "values" end def visit_Arel_Table o visit_edge o, "name" end def visit_Arel_Nodes_Casted o visit_edge o, 'val' visit_edge o, 'attribute' end def visit_Arel_Attribute o visit_edge o, "relation" visit_edge o, "name" end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute alias :visit_Arel_Attributes_String :visit_Arel_Attribute alias :visit_Arel_Attributes_Time :visit_Arel_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute def nary o o.children.each_with_index do |x,i| edge(i) { visit x } end end alias :visit_Arel_Nodes_And :nary def binary o visit_edge o, "left" visit_edge o, "right" end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary alias :visit_Arel_Nodes_Concat :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :binary alias :visit_Arel_Nodes_JoinSource :binary alias :visit_Arel_Nodes_LessThan :binary alias :visit_Arel_Nodes_LessThanOrEqual :binary alias :visit_Arel_Nodes_Matches :binary alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_Over :binary def visit_String o @node_stack.last.fields << o end alias :visit_Time :visit_String alias :visit_Date :visit_String alias :visit_DateTime :visit_String alias :visit_NilClass :visit_String alias :visit_TrueClass :visit_String alias :visit_FalseClass :visit_String alias :visit_Integer :visit_String alias :visit_Fixnum :visit_String alias :visit_BigDecimal :visit_String alias :visit_Float :visit_String alias :visit_Symbol :visit_String alias :visit_Arel_Nodes_SqlLiteral :visit_String def visit_Arel_Nodes_BindParam o; end def visit_Hash o o.each_with_index do |pair, i| edge("pair_#{i}") { visit pair } end end def visit_Array o o.each_with_index do |x,i| edge(i) { visit x } end end alias :visit_Set :visit_Array def visit_edge o, method edge(method) { visit o.send(method) } end def visit o if node = @seen[o.object_id] @edge_stack.last.to = node return end node = Node.new(o.class.name, o.object_id) @seen[node.id] = node @nodes << node with_node node do super end end def edge name edge = Edge.new(name, @node_stack.last) @edge_stack.push edge @edges << edge yield @edge_stack.pop end def with_node node if edge = @edge_stack.last edge.to = node end @node_stack.push node yield @node_stack.pop end def quote string string.to_s.gsub('"', '\"') end def to_dot "digraph \"Arel\" {\nnode [width=0.375,height=0.25,shape=record];\n" + @nodes.map { |node| label = "#{node.name}" node.fields.each_with_index do |field, i| label += "|#{quote field}" end "#{node.id} [label=\"#{label}\"];" }.join("\n") + "\n" + @edges.map { |edge| "#{edge.from.id} -> #{edge.to.id} [label=\"#{edge.name}\"];" }.join("\n") + "\n}" end end end end arel-9.0.0/lib/arel/visitors/to_sql.rb0000644000004100000410000005743413272030740017707 0ustar www-datawww-data# frozen_string_literal: true require 'bigdecimal' require 'date' require 'arel/visitors/reduce' module Arel module Visitors class UnsupportedVisitError < StandardError def initialize(object) super "Unsupported argument type: #{object.class.name}. Construct an Arel node instead." end end class ToSql < Arel::Visitors::Reduce ## # This is some roflscale crazy stuff. I'm roflscaling this because # building SQL queries is a hotspot. I will explain the roflscale so that # others will not rm this code. # # In YARV, string literals in a method body will get duped when the byte # code is executed. Let's take a look: # # > puts RubyVM::InstructionSequence.new('def foo; "bar"; end').disasm # # == disasm: >===== # 0000 trace 8 # 0002 trace 1 # 0004 putstring "bar" # 0006 trace 16 # 0008 leave # # The `putstring` bytecode will dup the string and push it on the stack. # In many cases in our SQL visitor, that string is never mutated, so there # is no need to dup the literal. # # If we change to a constant lookup, the string will not be duped, and we # can reduce the objects in our system: # # > puts RubyVM::InstructionSequence.new('BAR = "bar"; def foo; BAR; end').disasm # # == disasm: >======== # 0000 trace 8 # 0002 trace 1 # 0004 getinlinecache 11, # 0007 getconstant :BAR # 0009 setinlinecache # 0011 trace 16 # 0013 leave # # `getconstant` should be a hash lookup, and no object is duped when the # value of the constant is pushed on the stack. Hence the crazy # constants below. # # `matches` and `doesNotMatch` operate case-insensitively via Visitor subclasses # specialized for specific databases when necessary. # WHERE = ' WHERE ' # :nodoc: SPACE = ' ' # :nodoc: COMMA = ', ' # :nodoc: GROUP_BY = ' GROUP BY ' # :nodoc: ORDER_BY = ' ORDER BY ' # :nodoc: WINDOW = ' WINDOW ' # :nodoc: AND = ' AND ' # :nodoc: DISTINCT = 'DISTINCT' # :nodoc: def initialize connection super() @connection = connection end def compile node, &block accept(node, Arel::Collectors::SQLString.new, &block).value end private def visit_Arel_Nodes_DeleteStatement o, collector collector << 'DELETE FROM ' collector = visit o.relation, collector if o.wheres.any? collector << WHERE collector = inject_join o.wheres, collector, AND end maybe_visit o.limit, collector end # FIXME: we should probably have a 2-pass visitor for this def build_subselect key, o stmt = Nodes::SelectStatement.new core = stmt.cores.first core.froms = o.relation core.wheres = o.wheres core.projections = [key] stmt.limit = o.limit stmt.orders = o.orders stmt end def visit_Arel_Nodes_UpdateStatement o, collector if o.orders.empty? && o.limit.nil? wheres = o.wheres else wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])] end collector << "UPDATE " collector = visit o.relation, collector unless o.values.empty? collector << " SET " collector = inject_join o.values, collector, ", " end unless wheres.empty? collector << " WHERE " collector = inject_join wheres, collector, " AND " end collector end def visit_Arel_Nodes_InsertStatement o, collector collector << "INSERT INTO " collector = visit o.relation, collector if o.columns.any? collector << " (#{o.columns.map { |x| quote_column_name x.name }.join ', '})" end if o.values maybe_visit o.values, collector elsif o.select maybe_visit o.select, collector else collector end end def visit_Arel_Nodes_Exists o, collector collector << "EXISTS (" collector = visit(o.expressions, collector) << ")" if o.alias collector << " AS " visit o.alias, collector else collector end end def visit_Arel_Nodes_Casted o, collector collector << quoted(o.val, o.attribute).to_s end def visit_Arel_Nodes_Quoted o, collector collector << quoted(o.expr, nil).to_s end def visit_Arel_Nodes_True o, collector collector << "TRUE" end def visit_Arel_Nodes_False o, collector collector << "FALSE" end def visit_Arel_Nodes_ValuesList o, collector collector << "VALUES " len = o.rows.length - 1 o.rows.each_with_index { |row, i| collector << '(' row_len = row.length - 1 row.each_with_index do |value, k| case value when Nodes::SqlLiteral, Nodes::BindParam collector = visit(value, collector) else collector << quote(value) end collector << COMMA unless k == row_len end collector << ')' collector << COMMA unless i == len } collector end def visit_Arel_Nodes_Values o, collector collector << "VALUES (" len = o.expressions.length - 1 o.expressions.each_with_index { |value, i| case value when Nodes::SqlLiteral, Nodes::BindParam collector = visit value, collector else collector << quote(value).to_s end unless i == len collector << COMMA end } collector << ")" end def visit_Arel_Nodes_SelectStatement o, collector if o.with collector = visit o.with, collector collector << SPACE end collector = o.cores.inject(collector) { |c,x| visit_Arel_Nodes_SelectCore(x, c) } unless o.orders.empty? collector << ORDER_BY len = o.orders.length - 1 o.orders.each_with_index { |x, i| collector = visit(x, collector) collector << COMMA unless len == i } end visit_Arel_Nodes_SelectOptions(o, collector) collector end def visit_Arel_Nodes_SelectOptions o, collector collector = maybe_visit o.limit, collector collector = maybe_visit o.offset, collector collector = maybe_visit o.lock, collector end def visit_Arel_Nodes_SelectCore o, collector collector << "SELECT" collector = maybe_visit o.top, collector collector = maybe_visit o.set_quantifier, collector collect_nodes_for o.projections, collector, SPACE if o.source && !o.source.empty? collector << " FROM " collector = visit o.source, collector end collect_nodes_for o.wheres, collector, WHERE, AND collect_nodes_for o.groups, collector, GROUP_BY unless o.havings.empty? collector << " HAVING " inject_join o.havings, collector, AND end collect_nodes_for o.windows, collector, WINDOW collector end def collect_nodes_for nodes, collector, spacer, connector = COMMA unless nodes.empty? collector << spacer len = nodes.length - 1 nodes.each_with_index do |x, i| collector = visit(x, collector) collector << connector unless len == i end end end def visit_Arel_Nodes_Bin o, collector visit o.expr, collector end def visit_Arel_Nodes_Distinct o, collector collector << DISTINCT end def visit_Arel_Nodes_DistinctOn o, collector raise NotImplementedError, 'DISTINCT ON not implemented for this db' end def visit_Arel_Nodes_With o, collector collector << "WITH " inject_join o.children, collector, COMMA end def visit_Arel_Nodes_WithRecursive o, collector collector << "WITH RECURSIVE " inject_join o.children, collector, COMMA end def visit_Arel_Nodes_Union o, collector collector << "( " infix_value(o, collector, " UNION ") << " )" end def visit_Arel_Nodes_UnionAll o, collector collector << "( " infix_value(o, collector, " UNION ALL ") << " )" end def visit_Arel_Nodes_Intersect o, collector collector << "( " infix_value(o, collector, " INTERSECT ") << " )" end def visit_Arel_Nodes_Except o, collector collector << "( " infix_value(o, collector, " EXCEPT ") << " )" end def visit_Arel_Nodes_NamedWindow o, collector collector << quote_column_name(o.name) collector << " AS " visit_Arel_Nodes_Window o, collector end def visit_Arel_Nodes_Window o, collector collector << "(" if o.partitions.any? collector << "PARTITION BY " collector = inject_join o.partitions, collector, ", " end if o.orders.any? collector << SPACE if o.partitions.any? collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end if o.framing collector << SPACE if o.partitions.any? or o.orders.any? collector = visit o.framing, collector end collector << ")" end def visit_Arel_Nodes_Rows o, collector if o.expr collector << "ROWS " visit o.expr, collector else collector << "ROWS" end end def visit_Arel_Nodes_Range o, collector if o.expr collector << "RANGE " visit o.expr, collector else collector << "RANGE" end end def visit_Arel_Nodes_Preceding o, collector collector = if o.expr visit o.expr, collector else collector << "UNBOUNDED" end collector << " PRECEDING" end def visit_Arel_Nodes_Following o, collector collector = if o.expr visit o.expr, collector else collector << "UNBOUNDED" end collector << " FOLLOWING" end def visit_Arel_Nodes_CurrentRow o, collector collector << "CURRENT ROW" end def visit_Arel_Nodes_Over o, collector case o.right when nil visit(o.left, collector) << " OVER ()" when Arel::Nodes::SqlLiteral infix_value o, collector, " OVER " when String, Symbol visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}" else infix_value o, collector, " OVER " end end def visit_Arel_Nodes_Offset o, collector collector << "OFFSET " visit o.expr, collector end def visit_Arel_Nodes_Limit o, collector collector << "LIMIT " visit o.expr, collector end # FIXME: this does nothing on most databases, but does on MSSQL def visit_Arel_Nodes_Top o, collector collector end def visit_Arel_Nodes_Lock o, collector visit o.expr, collector end def visit_Arel_Nodes_Grouping o, collector if o.expr.is_a? Nodes::Grouping visit(o.expr, collector) else collector << "(" visit(o.expr, collector) << ")" end end def visit_Arel_SelectManager o, collector collector << '(' visit(o.ast, collector) << ')' end def visit_Arel_Nodes_Ascending o, collector visit(o.expr, collector) << " ASC" end def visit_Arel_Nodes_Descending o, collector visit(o.expr, collector) << " DESC" end def visit_Arel_Nodes_Group o, collector visit o.expr, collector end def visit_Arel_Nodes_NamedFunction o, collector collector << o.name collector << "(" collector << "DISTINCT " if o.distinct collector = inject_join(o.expressions, collector, ", ") << ")" if o.alias collector << " AS " visit o.alias, collector else collector end end def visit_Arel_Nodes_Extract o, collector collector << "EXTRACT(#{o.field.to_s.upcase} FROM " visit(o.expr, collector) << ")" end def visit_Arel_Nodes_Count o, collector aggregate "COUNT", o, collector end def visit_Arel_Nodes_Sum o, collector aggregate "SUM", o, collector end def visit_Arel_Nodes_Max o, collector aggregate "MAX", o, collector end def visit_Arel_Nodes_Min o, collector aggregate "MIN", o, collector end def visit_Arel_Nodes_Avg o, collector aggregate "AVG", o, collector end def visit_Arel_Nodes_TableAlias o, collector collector = visit o.relation, collector collector << " " collector << quote_table_name(o.name) end def visit_Arel_Nodes_Between o, collector collector = visit o.left, collector collector << " BETWEEN " visit o.right, collector end def visit_Arel_Nodes_GreaterThanOrEqual o, collector collector = visit o.left, collector collector << " >= " visit o.right, collector end def visit_Arel_Nodes_GreaterThan o, collector collector = visit o.left, collector collector << " > " visit o.right, collector end def visit_Arel_Nodes_LessThanOrEqual o, collector collector = visit o.left, collector collector << " <= " visit o.right, collector end def visit_Arel_Nodes_LessThan o, collector collector = visit o.left, collector collector << " < " visit o.right, collector end def visit_Arel_Nodes_Matches o, collector collector = visit o.left, collector collector << " LIKE " collector = visit o.right, collector if o.escape collector << ' ESCAPE ' visit o.escape, collector else collector end end def visit_Arel_Nodes_DoesNotMatch o, collector collector = visit o.left, collector collector << " NOT LIKE " collector = visit o.right, collector if o.escape collector << ' ESCAPE ' visit o.escape, collector else collector end end def visit_Arel_Nodes_JoinSource o, collector if o.left collector = visit o.left, collector end if o.right.any? collector << SPACE if o.left collector = inject_join o.right, collector, SPACE end collector end def visit_Arel_Nodes_Regexp o, collector raise NotImplementedError, '~ not implemented for this db' end def visit_Arel_Nodes_NotRegexp o, collector raise NotImplementedError, '!~ not implemented for this db' end def visit_Arel_Nodes_StringJoin o, collector visit o.left, collector end def visit_Arel_Nodes_FullOuterJoin o, collector collector << "FULL OUTER JOIN " collector = visit o.left, collector collector << SPACE visit o.right, collector end def visit_Arel_Nodes_OuterJoin o, collector collector << "LEFT OUTER JOIN " collector = visit o.left, collector collector << " " visit o.right, collector end def visit_Arel_Nodes_RightOuterJoin o, collector collector << "RIGHT OUTER JOIN " collector = visit o.left, collector collector << SPACE visit o.right, collector end def visit_Arel_Nodes_InnerJoin o, collector collector << "INNER JOIN " collector = visit o.left, collector if o.right collector << SPACE visit(o.right, collector) else collector end end def visit_Arel_Nodes_On o, collector collector << "ON " visit o.expr, collector end def visit_Arel_Nodes_Not o, collector collector << "NOT (" visit(o.expr, collector) << ")" end def visit_Arel_Table o, collector if o.table_alias collector << "#{quote_table_name o.name} #{quote_table_name o.table_alias}" else collector << quote_table_name(o.name) end end def visit_Arel_Nodes_In o, collector if Array === o.right && o.right.empty? collector << '1=0' else collector = visit o.left, collector collector << " IN (" visit(o.right, collector) << ")" end end def visit_Arel_Nodes_NotIn o, collector if Array === o.right && o.right.empty? collector << '1=1' else collector = visit o.left, collector collector << " NOT IN (" collector = visit o.right, collector collector << ")" end end def visit_Arel_Nodes_And o, collector inject_join o.children, collector, " AND " end def visit_Arel_Nodes_Or o, collector collector = visit o.left, collector collector << " OR " visit o.right, collector end def visit_Arel_Nodes_Assignment o, collector case o.right when Arel::Nodes::UnqualifiedColumn, Arel::Attributes::Attribute, Arel::Nodes::BindParam collector = visit o.left, collector collector << " = " visit o.right, collector else collector = visit o.left, collector collector << " = " collector << quote(o.right).to_s end end def visit_Arel_Nodes_Equality o, collector right = o.right collector = visit o.left, collector if right.nil? collector << " IS NULL" else collector << " = " visit right, collector end end def visit_Arel_Nodes_NotEqual o, collector right = o.right collector = visit o.left, collector if right.nil? collector << " IS NOT NULL" else collector << " != " visit right, collector end end def visit_Arel_Nodes_As o, collector collector = visit o.left, collector collector << " AS " visit o.right, collector end def visit_Arel_Nodes_Case o, collector collector << "CASE " if o.case visit o.case, collector collector << " " end o.conditions.each do |condition| visit condition, collector collector << " " end if o.default visit o.default, collector collector << " " end collector << "END" end def visit_Arel_Nodes_When o, collector collector << "WHEN " visit o.left, collector collector << " THEN " visit o.right, collector end def visit_Arel_Nodes_Else o, collector collector << "ELSE " visit o.expr, collector end def visit_Arel_Nodes_UnqualifiedColumn o, collector collector << "#{quote_column_name o.name}" collector end def visit_Arel_Attributes_Attribute o, collector join_name = o.relation.table_alias || o.relation.name collector << "#{quote_table_name join_name}.#{quote_column_name o.name}" end alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute def literal o, collector; collector << o.to_s; end def visit_Arel_Nodes_BindParam o, collector collector.add_bind(o.value) { "?" } end alias :visit_Arel_Nodes_SqlLiteral :literal alias :visit_Bignum :literal alias :visit_Fixnum :literal alias :visit_Integer :literal def quoted o, a if a && a.able_to_type_cast? quote(a.type_cast_for_database(o)) else quote(o) end end def unsupported o, collector raise UnsupportedVisitError.new(o) end alias :visit_ActiveSupport_Multibyte_Chars :unsupported alias :visit_ActiveSupport_StringInquirer :unsupported alias :visit_BigDecimal :unsupported alias :visit_Class :unsupported alias :visit_Date :unsupported alias :visit_DateTime :unsupported alias :visit_FalseClass :unsupported alias :visit_Float :unsupported alias :visit_Hash :unsupported alias :visit_NilClass :unsupported alias :visit_String :unsupported alias :visit_Symbol :unsupported alias :visit_Time :unsupported alias :visit_TrueClass :unsupported def visit_Arel_Nodes_InfixOperation o, collector collector = visit o.left, collector collector << " #{o.operator} " visit o.right, collector end alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Subtraction :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation def visit_Arel_Nodes_UnaryOperation o, collector collector << " #{o.operator} " visit o.expr, collector end def visit_Array o, collector inject_join o, collector, ", " end alias :visit_Set :visit_Array def quote value return value if Arel::Nodes::SqlLiteral === value @connection.quote value end def quote_table_name name return name if Arel::Nodes::SqlLiteral === name @connection.quote_table_name(name) end def quote_column_name name return name if Arel::Nodes::SqlLiteral === name @connection.quote_column_name(name) end def maybe_visit thing, collector return collector unless thing collector << " " visit thing, collector end def inject_join list, collector, join_str len = list.length - 1 list.each_with_index.inject(collector) { |c, (x,i)| if i == len visit x, c else visit(x, c) << join_str end } end def infix_value o, collector, value collector = visit o.left, collector collector << value visit o.right, collector end def aggregate name, o, collector collector << "#{name}(" if o.distinct collector << "DISTINCT " end collector = inject_join(o.expressions, collector, ", ") << ")" if o.alias collector << " AS " visit o.alias, collector else collector end end end end end arel-9.0.0/lib/arel/visitors/oracle12.rb0000644000004100000410000000336413272030740020007 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class Oracle12 < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o, collector # Oracle does not allow LIMIT clause with select for update if o.limit && o.lock raise ArgumentError, <<-MSG 'Combination of limit and lock is not supported. because generated SQL statements `SELECT FOR UPDATE and FETCH FIRST n ROWS` generates ORA-02014.` MSG end super end def visit_Arel_Nodes_SelectOptions o, collector collector = maybe_visit o.offset, collector collector = maybe_visit o.limit, collector collector = maybe_visit o.lock, collector end def visit_Arel_Nodes_Limit o, collector collector << "FETCH FIRST " collector = visit o.expr, collector collector << " ROWS ONLY" end def visit_Arel_Nodes_Offset o, collector collector << "OFFSET " visit o.expr, collector collector << " ROWS" end def visit_Arel_Nodes_Except o, collector collector << "( " collector = infix_value o, collector, " MINUS " collector << " )" end def visit_Arel_Nodes_UpdateStatement o, collector # Oracle does not allow ORDER BY/LIMIT in UPDATEs. if o.orders.any? && o.limit.nil? # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, # otherwise let the user deal with the error o = o.dup o.orders = [] end super end def visit_Arel_Nodes_BindParam o, collector collector.add_bind(o.value) { |i| ":a#{i}" } end end end end arel-9.0.0/lib/arel/visitors/ibm_db.rb0000644000004100000410000000046113272030740017606 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class IBM_DB < Arel::Visitors::ToSql private def visit_Arel_Nodes_Limit o, collector collector << "FETCH FIRST " collector = visit o.expr, collector collector << " ROWS ONLY" end end end end arel-9.0.0/lib/arel/visitors/mysql.rb0000644000004100000410000000433613272030740017544 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class MySQL < Arel::Visitors::ToSql private def visit_Arel_Nodes_Union o, collector, suppress_parens = false unless suppress_parens collector << "( " end collector = case o.left when Arel::Nodes::Union visit_Arel_Nodes_Union o.left, collector, true else visit o.left, collector end collector << " UNION " collector = case o.right when Arel::Nodes::Union visit_Arel_Nodes_Union o.right, collector, true else visit o.right, collector end if suppress_parens collector else collector << " )" end end def visit_Arel_Nodes_Bin o, collector collector << "BINARY " visit o.expr, collector end ### # :'( # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214 def visit_Arel_Nodes_SelectStatement o, collector if o.offset && !o.limit o.limit = Arel::Nodes::Limit.new(18446744073709551615) end super end def visit_Arel_Nodes_SelectCore o, collector o.froms ||= Arel.sql('DUAL') super end def visit_Arel_Nodes_UpdateStatement o, collector collector << "UPDATE " collector = visit o.relation, collector unless o.values.empty? collector << " SET " collector = inject_join o.values, collector, ', ' end unless o.wheres.empty? collector << " WHERE " collector = inject_join o.wheres, collector, ' AND ' end unless o.orders.empty? collector << " ORDER BY " collector = inject_join o.orders, collector, ', ' end maybe_visit o.limit, collector end def visit_Arel_Nodes_Concat o, collector collector << " CONCAT(" visit o.left, collector collector << ", " visit o.right, collector collector << ") " collector end end end end arel-9.0.0/lib/arel/visitors/sqlite.rb0000644000004100000410000000106313272030740017672 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class SQLite < Arel::Visitors::ToSql private # Locks are not supported in SQLite def visit_Arel_Nodes_Lock o, collector collector end def visit_Arel_Nodes_SelectStatement o, collector o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit super end def visit_Arel_Nodes_True o, collector collector << "1" end def visit_Arel_Nodes_False o, collector collector << "0" end end end end arel-9.0.0/lib/arel/visitors/visitor.rb0000644000004100000410000000172313272030740020073 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class Visitor def initialize @dispatch = get_dispatch_cache end def accept object visit object end private def self.dispatch_cache Hash.new do |hash, klass| hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}" end end def get_dispatch_cache self.class.dispatch_cache end def dispatch @dispatch end def visit object dispatch_method = dispatch[object.class] send dispatch_method, object rescue NoMethodError => e raise e if respond_to?(dispatch_method, true) superklass = object.class.ancestors.find { |klass| respond_to?(dispatch[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass dispatch[object.class] = dispatch[superklass] retry end end end end arel-9.0.0/lib/arel/visitors/where_sql.rb0000644000004100000410000000104313272030740020360 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class WhereSql < Arel::Visitors::ToSql def initialize(inner_visitor, *args, &block) @inner_visitor = inner_visitor super(*args, &block) end private def visit_Arel_Nodes_SelectCore o, collector collector << "WHERE " wheres = o.wheres.map do |where| Nodes::SqlLiteral.new(@inner_visitor.accept(where, collector.class.new).value) end inject_join wheres, collector, ' AND ' end end end end arel-9.0.0/lib/arel/visitors/oracle.rb0000644000004100000410000001103113272030740017632 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class Oracle < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o, collector o = order_hacks(o) # if need to select first records without ORDER BY and GROUP BY and without DISTINCT # then can use simple ROWNUM in WHERE clause if o.limit && o.orders.empty? && o.cores.first.groups.empty? && !o.offset && o.cores.first.set_quantifier.class.to_s !~ /Distinct/ o.cores.last.wheres.push Nodes::LessThanOrEqual.new( Nodes::SqlLiteral.new('ROWNUM'), o.limit.expr ) return super end if o.limit && o.offset o = o.dup limit = o.limit.expr offset = o.offset o.offset = nil collector << " SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (" collector = super(o, collector) if offset.expr.is_a? Nodes::BindParam collector << ') raw_sql_ WHERE rownum <= (' collector = visit offset.expr, collector collector << ' + ' collector = visit limit, collector collector << ") ) WHERE raw_rnum_ > " collector = visit offset.expr, collector return collector else collector << ") raw_sql_ WHERE rownum <= #{offset.expr.to_i + limit} ) WHERE " return visit(offset, collector) end end if o.limit o = o.dup limit = o.limit.expr collector << "SELECT * FROM (" collector = super(o, collector) collector << ") WHERE ROWNUM <= " return visit limit, collector end if o.offset o = o.dup offset = o.offset o.offset = nil collector << "SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM (" collector = super(o, collector) collector << ") raw_sql_ ) WHERE " return visit offset, collector end super end def visit_Arel_Nodes_Limit o, collector collector end def visit_Arel_Nodes_Offset o, collector collector << "raw_rnum_ > " visit o.expr, collector end def visit_Arel_Nodes_Except o, collector collector << "( " collector = infix_value o, collector, " MINUS " collector << " )" end def visit_Arel_Nodes_UpdateStatement o, collector # Oracle does not allow ORDER BY/LIMIT in UPDATEs. if o.orders.any? && o.limit.nil? # However, there is no harm in silently eating the ORDER BY clause if no LIMIT has been provided, # otherwise let the user deal with the error o = o.dup o.orders = [] end super end ### # Hacks for the order clauses specific to Oracle def order_hacks o return o if o.orders.empty? return o unless o.cores.any? do |core| core.projections.any? do |projection| /FIRST_VALUE/ === projection end end # Previous version with join and split broke ORDER BY clause # if it contained functions with several arguments (separated by ','). # # orders = o.orders.map { |x| visit x }.join(', ').split(',') orders = o.orders.map do |x| string = visit(x, Arel::Collectors::SQLString.new).value if string.include?(',') split_order_string(string) else string end end.flatten o.orders = [] orders.each_with_index do |order, i| o.orders << Nodes::SqlLiteral.new("alias_#{i}__#{' DESC' if /\bdesc$/i === order}") end o end # Split string by commas but count opening and closing brackets # and ignore commas inside brackets. def split_order_string(string) array = [] i = 0 string.split(',').each do |part| if array[i] array[i] << ',' << part else # to ensure that array[i] will be String and not Arel::Nodes::SqlLiteral array[i] = part.to_s end i += 1 if array[i].count('(') == array[i].count(')') end array end def visit_Arel_Nodes_BindParam o, collector collector.add_bind(o.value) { |i| ":a#{i}" } end end end end arel-9.0.0/lib/arel/visitors/depth_first.rb0000644000004100000410000001512113272030740020704 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class DepthFirst < Arel::Visitors::Visitor def initialize block = nil @block = block || Proc.new super() end private def visit o super @block.call o end def unary o visit o.expr end alias :visit_Arel_Nodes_Else :unary alias :visit_Arel_Nodes_Group :unary alias :visit_Arel_Nodes_Cube :unary alias :visit_Arel_Nodes_RollUp :unary alias :visit_Arel_Nodes_GroupingSet :unary alias :visit_Arel_Nodes_GroupingElement :unary alias :visit_Arel_Nodes_Grouping :unary alias :visit_Arel_Nodes_Having :unary alias :visit_Arel_Nodes_Limit :unary alias :visit_Arel_Nodes_Not :unary alias :visit_Arel_Nodes_Offset :unary alias :visit_Arel_Nodes_On :unary alias :visit_Arel_Nodes_Ordering :unary alias :visit_Arel_Nodes_Ascending :unary alias :visit_Arel_Nodes_Descending :unary alias :visit_Arel_Nodes_Top :unary alias :visit_Arel_Nodes_UnqualifiedColumn :unary def function o visit o.expressions visit o.alias visit o.distinct end alias :visit_Arel_Nodes_Avg :function alias :visit_Arel_Nodes_Exists :function alias :visit_Arel_Nodes_Max :function alias :visit_Arel_Nodes_Min :function alias :visit_Arel_Nodes_Sum :function def visit_Arel_Nodes_NamedFunction o visit o.name visit o.expressions visit o.distinct visit o.alias end def visit_Arel_Nodes_Count o visit o.expressions visit o.alias visit o.distinct end def visit_Arel_Nodes_Case o visit o.case visit o.conditions visit o.default end def nary o o.children.each { |child| visit child} end alias :visit_Arel_Nodes_And :nary def binary o visit o.left visit o.right end alias :visit_Arel_Nodes_As :binary alias :visit_Arel_Nodes_Assignment :binary alias :visit_Arel_Nodes_Between :binary alias :visit_Arel_Nodes_Concat :binary alias :visit_Arel_Nodes_DeleteStatement :binary alias :visit_Arel_Nodes_DoesNotMatch :binary alias :visit_Arel_Nodes_Equality :binary alias :visit_Arel_Nodes_FullOuterJoin :binary alias :visit_Arel_Nodes_GreaterThan :binary alias :visit_Arel_Nodes_GreaterThanOrEqual :binary alias :visit_Arel_Nodes_In :binary alias :visit_Arel_Nodes_InfixOperation :binary alias :visit_Arel_Nodes_JoinSource :binary alias :visit_Arel_Nodes_InnerJoin :binary alias :visit_Arel_Nodes_LessThan :binary alias :visit_Arel_Nodes_LessThanOrEqual :binary alias :visit_Arel_Nodes_Matches :binary alias :visit_Arel_Nodes_NotEqual :binary alias :visit_Arel_Nodes_NotIn :binary alias :visit_Arel_Nodes_NotRegexp :binary alias :visit_Arel_Nodes_Or :binary alias :visit_Arel_Nodes_OuterJoin :binary alias :visit_Arel_Nodes_Regexp :binary alias :visit_Arel_Nodes_RightOuterJoin :binary alias :visit_Arel_Nodes_TableAlias :binary alias :visit_Arel_Nodes_Values :binary alias :visit_Arel_Nodes_When :binary def visit_Arel_Nodes_StringJoin o visit o.left end def visit_Arel_Attribute o visit o.relation visit o.name end alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute alias :visit_Arel_Attributes_Float :visit_Arel_Attribute alias :visit_Arel_Attributes_String :visit_Arel_Attribute alias :visit_Arel_Attributes_Time :visit_Arel_Attribute alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute alias :visit_Arel_Attributes_Decimal :visit_Arel_Attribute def visit_Arel_Table o visit o.name end def terminal o end alias :visit_ActiveSupport_Multibyte_Chars :terminal alias :visit_ActiveSupport_StringInquirer :terminal alias :visit_Arel_Nodes_Lock :terminal alias :visit_Arel_Nodes_Node :terminal alias :visit_Arel_Nodes_SqlLiteral :terminal alias :visit_Arel_Nodes_BindParam :terminal alias :visit_Arel_Nodes_Window :terminal alias :visit_Arel_Nodes_True :terminal alias :visit_Arel_Nodes_False :terminal alias :visit_BigDecimal :terminal alias :visit_Bignum :terminal alias :visit_Class :terminal alias :visit_Date :terminal alias :visit_DateTime :terminal alias :visit_FalseClass :terminal alias :visit_Fixnum :terminal alias :visit_Float :terminal alias :visit_Integer :terminal alias :visit_NilClass :terminal alias :visit_String :terminal alias :visit_Symbol :terminal alias :visit_Time :terminal alias :visit_TrueClass :terminal def visit_Arel_Nodes_InsertStatement o visit o.relation visit o.columns visit o.values end def visit_Arel_Nodes_SelectCore o visit o.projections visit o.source visit o.wheres visit o.groups visit o.windows visit o.havings end def visit_Arel_Nodes_SelectStatement o visit o.cores visit o.orders visit o.limit visit o.lock visit o.offset end def visit_Arel_Nodes_UpdateStatement o visit o.relation visit o.values visit o.wheres visit o.orders visit o.limit end def visit_Array o o.each { |i| visit i } end alias :visit_Set :visit_Array def visit_Hash o o.each { |k,v| visit(k); visit(v) } end DISPATCH = dispatch_cache def get_dispatch_cache DISPATCH end end end end arel-9.0.0/lib/arel/visitors/informix.rb0000644000004100000410000000303513272030740020225 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class Informix < Arel::Visitors::ToSql private def visit_Arel_Nodes_SelectStatement o, collector collector << "SELECT " collector = maybe_visit o.offset, collector collector = maybe_visit o.limit, collector collector = o.cores.inject(collector) { |c,x| visit_Arel_Nodes_SelectCore x, c } if o.orders.any? collector << "ORDER BY " collector = inject_join o.orders, collector, ", " end collector = maybe_visit o.lock, collector end def visit_Arel_Nodes_SelectCore o, collector collector = inject_join o.projections, collector, ", " if o.source && !o.source.empty? collector << " FROM " collector = visit o.source, collector end if o.wheres.any? collector << " WHERE " collector = inject_join o.wheres, collector, " AND " end if o.groups.any? collector << "GROUP BY " collector = inject_join o.groups, collector, ", " end if o.havings.any? collector << " HAVING " collector = inject_join o.havings, collector, " AND " end collector end def visit_Arel_Nodes_Offset o, collector collector << "SKIP " visit o.expr, collector end def visit_Arel_Nodes_Limit o, collector collector << "FIRST " visit o.expr, collector collector << " " end end end end arel-9.0.0/lib/arel/visitors/reduce.rb0000644000004100000410000000133313272030740017640 0ustar www-datawww-data# frozen_string_literal: true require 'arel/visitors/visitor' module Arel module Visitors class Reduce < Arel::Visitors::Visitor def accept object, collector visit object, collector end private def visit object, collector dispatch_method = dispatch[object.class] send dispatch_method, object, collector rescue NoMethodError => e raise e if respond_to?(dispatch_method, true) superklass = object.class.ancestors.find { |klass| respond_to?(dispatch[klass], true) } raise(TypeError, "Cannot visit #{object.class}") unless superklass dispatch[object.class] = dispatch[superklass] retry end end end end arel-9.0.0/lib/arel/visitors/postgresql.rb0000644000004100000410000000435613272030740020604 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class PostgreSQL < Arel::Visitors::ToSql CUBE = 'CUBE' ROLLUP = 'ROLLUP' GROUPING_SET = 'GROUPING SET' private def visit_Arel_Nodes_Matches o, collector op = o.case_sensitive ? ' LIKE ' : ' ILIKE ' collector = infix_value o, collector, op if o.escape collector << ' ESCAPE ' visit o.escape, collector else collector end end def visit_Arel_Nodes_DoesNotMatch o, collector op = o.case_sensitive ? ' NOT LIKE ' : ' NOT ILIKE ' collector = infix_value o, collector, op if o.escape collector << ' ESCAPE ' visit o.escape, collector else collector end end def visit_Arel_Nodes_Regexp o, collector op = o.case_sensitive ? ' ~ ' : ' ~* ' infix_value o, collector, op end def visit_Arel_Nodes_NotRegexp o, collector op = o.case_sensitive ? ' !~ ' : ' !~* ' infix_value o, collector, op end def visit_Arel_Nodes_DistinctOn o, collector collector << "DISTINCT ON ( " visit(o.expr, collector) << " )" end def visit_Arel_Nodes_BindParam o, collector collector.add_bind(o.value) { |i| "$#{i}" } end def visit_Arel_Nodes_GroupingElement o, collector collector << "( " visit(o.expr, collector) << " )" end def visit_Arel_Nodes_Cube o, collector collector << CUBE grouping_array_or_grouping_element o, collector end def visit_Arel_Nodes_RollUp o, collector collector << ROLLUP grouping_array_or_grouping_element o, collector end def visit_Arel_Nodes_GroupingSet o, collector collector << GROUPING_SET grouping_array_or_grouping_element o, collector end # Utilized by GroupingSet, Cube & RollUp visitors to # handle grouping aggregation semantics def grouping_array_or_grouping_element o, collector if o.expr.is_a? Array collector << "( " visit o.expr, collector collector << " )" else visit o.expr, collector end end end end end arel-9.0.0/lib/arel/visitors/mssql.rb0000644000004100000410000000652113272030740017534 0ustar www-datawww-data# frozen_string_literal: true module Arel module Visitors class MSSQL < Arel::Visitors::ToSql RowNumber = Struct.new :children def initialize(*) @primary_keys = {} super end private # `top` wouldn't really work here. I.e. User.select("distinct first_name").limit(10) would generate # "select top 10 distinct first_name from users", which is invalid query! it should be # "select distinct top 10 first_name from users" def visit_Arel_Nodes_Top o "" end def visit_Arel_Visitors_MSSQL_RowNumber o, collector collector << "ROW_NUMBER() OVER (ORDER BY " inject_join(o.children, collector, ', ') << ") as _row_num" end def visit_Arel_Nodes_SelectStatement o, collector if !o.limit && !o.offset return super end is_select_count = false o.cores.each { |x| core_order_by = row_num_literal determine_order_by(o.orders, x) if select_count? x x.projections = [core_order_by] is_select_count = true else x.projections << core_order_by end } if is_select_count # fixme count distinct wouldn't work with limit or offset collector << "SELECT COUNT(1) as count_id FROM (" end collector << "SELECT _t.* FROM (" collector = o.cores.inject(collector) { |c,x| visit_Arel_Nodes_SelectCore x, c } collector << ") as _t WHERE #{get_offset_limit_clause(o)}" if is_select_count collector << ") AS subquery" else collector end end def get_offset_limit_clause o first_row = o.offset ? o.offset.expr.to_i + 1 : 1 last_row = o.limit ? o.limit.expr.to_i - 1 + first_row : nil if last_row " _row_num BETWEEN #{first_row} AND #{last_row}" else " _row_num >= #{first_row}" end end def visit_Arel_Nodes_DeleteStatement o, collector collector << 'DELETE ' if o.limit collector << 'TOP (' visit o.limit.expr, collector collector << ') ' end collector << 'FROM ' collector = visit o.relation, collector if o.wheres.any? collector << ' WHERE ' inject_join o.wheres, collector, AND else collector end end def determine_order_by orders, x if orders.any? orders elsif x.groups.any? x.groups else pk = find_left_table_pk(x.froms) pk ? [pk] : [] end end def row_num_literal order_by RowNumber.new order_by end def select_count? x x.projections.length == 1 && Arel::Nodes::Count === x.projections.first end # FIXME raise exception of there is no pk? def find_left_table_pk o if o.kind_of?(Arel::Nodes::Join) find_left_table_pk(o.left) elsif o.instance_of?(Arel::Table) find_primary_key(o) end end def find_primary_key(o) @primary_keys[o.name] ||= begin primary_key_name = @connection.primary_key(o.name) # some tables might be without primary key primary_key_name && o[primary_key_name] end end end end end arel-9.0.0/lib/arel/insert_manager.rb0000644000004100000410000000167413272030740017515 0ustar www-datawww-data# frozen_string_literal: true module Arel class InsertManager < Arel::TreeManager def initialize super @ast = Nodes::InsertStatement.new end def into table @ast.relation = table self end def columns; @ast.columns end def values= val; @ast.values = val; end def select select @ast.select = select end def insert fields return if fields.empty? if String === fields @ast.values = Nodes::SqlLiteral.new(fields) else @ast.relation ||= fields.first.first.relation values = [] fields.each do |column, value| @ast.columns << column values << value end @ast.values = create_values values, @ast.columns end self end def create_values values, columns Nodes::Values.new values, columns end def create_values_list(rows) Nodes::ValuesList.new(rows) end end end arel-9.0.0/lib/arel/attributes.rb0000644000004100000410000000120013272030740016666 0ustar www-datawww-data# frozen_string_literal: true require 'arel/attributes/attribute' module Arel module Attributes ### # Factory method to wrap a raw database +column+ to an Arel Attribute. def self.for column case column.type when :string, :text, :binary then String when :integer then Integer when :float then Float when :decimal then Decimal when :date, :datetime, :timestamp, :time then Time when :boolean then Boolean else Undefined end end end end arel-9.0.0/lib/arel/attributes/0000755000004100000410000000000013272030740016350 5ustar www-datawww-dataarel-9.0.0/lib/arel/attributes/attribute.rb0000644000004100000410000000156713272030740020711 0ustar www-datawww-data# frozen_string_literal: true module Arel module Attributes class Attribute < Struct.new :relation, :name include Arel::Expressions include Arel::Predications include Arel::AliasPredication include Arel::OrderPredications include Arel::Math ### # Create a node for lowering this attribute def lower relation.lower self end def type_cast_for_database(value) relation.type_cast_for_database(name, value) end def able_to_type_cast? relation.able_to_type_cast? end end class String < Attribute; end class Time < Attribute; end class Boolean < Attribute; end class Decimal < Attribute; end class Float < Attribute; end class Integer < Attribute; end class Undefined < Attribute; end end Attribute = Attributes::Attribute end arel-9.0.0/lib/arel/delete_manager.rb0000644000004100000410000000065613272030740017452 0ustar www-datawww-data# frozen_string_literal: true module Arel class DeleteManager < Arel::TreeManager def initialize super @ast = Nodes::DeleteStatement.new @ctx = @ast end def from relation @ast.relation = relation self end def take limit @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit self end def wheres= list @ast.wheres = list end end end arel-9.0.0/lib/arel/window_predications.rb0000644000004100000410000000022413272030740020560 0ustar www-datawww-data# frozen_string_literal: true module Arel module WindowPredications def over(expr = nil) Nodes::Over.new(self, expr) end end endarel-9.0.0/lib/arel/table.rb0000644000004100000410000000442213272030740015600 0ustar www-datawww-data# frozen_string_literal: true module Arel class Table include Arel::Crud include Arel::FactoryMethods @engine = nil class << self; attr_accessor :engine; end attr_accessor :name, :table_alias # TableAlias and Table both have a #table_name which is the name of the underlying table alias :table_name :name def initialize(name, as: nil, type_caster: nil) @name = name.to_s @type_caster = type_caster # Sometime AR sends an :as parameter to table, to let the table know # that it is an Alias. We may want to override new, and return a # TableAlias node? if as.to_s == @name as = nil end @table_alias = as end def alias name = "#{self.name}_2" Nodes::TableAlias.new(self, name) end def from SelectManager.new(self) end def join relation, klass = Nodes::InnerJoin return from unless relation case relation when String, Nodes::SqlLiteral raise EmptyJoinError if relation.empty? klass = Nodes::StringJoin end from.join(relation, klass) end def outer_join relation join(relation, Nodes::OuterJoin) end def group *columns from.group(*columns) end def order *expr from.order(*expr) end def where condition from.where condition end def project *things from.project(*things) end def take amount from.take amount end def skip amount from.skip amount end def having expr from.having expr end def [] name ::Arel::Attribute.new self, name end def hash # Perf note: aliases and table alias is excluded from the hash # aliases can have a loop back to this table breaking hashes in parent # relations, for the vast majority of cases @name is unique to a query @name.hash end def eql? other self.class == other.class && self.name == other.name && self.table_alias == other.table_alias end alias :== :eql? def type_cast_for_database(attribute_name, value) type_caster.type_cast_for_database(attribute_name, value) end def able_to_type_cast? !type_caster.nil? end protected attr_reader :type_caster end end arel-9.0.0/lib/arel/visitors.rb0000644000004100000410000000074613272030740016400 0ustar www-datawww-data# frozen_string_literal: true require 'arel/visitors/visitor' require 'arel/visitors/depth_first' require 'arel/visitors/to_sql' require 'arel/visitors/sqlite' require 'arel/visitors/postgresql' require 'arel/visitors/mysql' require 'arel/visitors/mssql' require 'arel/visitors/oracle' require 'arel/visitors/oracle12' require 'arel/visitors/where_sql' require 'arel/visitors/dot' require 'arel/visitors/ibm_db' require 'arel/visitors/informix' module Arel module Visitors end end arel-9.0.0/lib/arel/crud.rb0000644000004100000410000000145513272030740015451 0ustar www-datawww-data# frozen_string_literal: true module Arel ### # FIXME hopefully we can remove this module Crud def compile_update values, pk um = UpdateManager.new if Nodes::SqlLiteral === values relation = @ctx.from else relation = values.first.first.relation end um.key = pk um.table relation um.set values um.take @ast.limit.expr if @ast.limit um.order(*@ast.orders) um.wheres = @ctx.wheres um end def compile_insert values im = create_insert im.insert values im end def create_insert InsertManager.new end def compile_delete dm = DeleteManager.new dm.take @ast.limit.expr if @ast.limit dm.wheres = @ctx.wheres dm.from @ctx.froms dm end end end arel-9.0.0/lib/arel/math.rb0000644000004100000410000000173213272030740015443 0ustar www-datawww-data# frozen_string_literal: true module Arel module Math def *(other) Arel::Nodes::Multiplication.new(self, other) end def +(other) Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new(self, other)) end def -(other) Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other)) end def /(other) Arel::Nodes::Division.new(self, other) end def &(other) Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseAnd.new(self, other)) end def |(other) Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseOr.new(self, other)) end def ^(other) Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseXor.new(self, other)) end def <<(other) Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseShiftLeft.new(self, other)) end def >>(other) Arel::Nodes::Grouping.new(Arel::Nodes::BitwiseShiftRight.new(self, other)) end def ~@ Arel::Nodes::BitwiseNot.new(self) end end end arel-9.0.0/lib/arel/predications.rb0000644000004100000410000001266413272030740017204 0ustar www-datawww-data# frozen_string_literal: true module Arel module Predications def not_eq other Nodes::NotEqual.new self, quoted_node(other) end def not_eq_any others grouping_any :not_eq, others end def not_eq_all others grouping_all :not_eq, others end def eq other Nodes::Equality.new self, quoted_node(other) end def eq_any others grouping_any :eq, others end def eq_all others grouping_all :eq, quoted_array(others) end def between other if equals_quoted?(other.begin, -Float::INFINITY) if equals_quoted?(other.end, Float::INFINITY) not_in([]) elsif other.exclude_end? lt(other.end) else lteq(other.end) end elsif equals_quoted?(other.end, Float::INFINITY) gteq(other.begin) elsif other.exclude_end? gteq(other.begin).and(lt(other.end)) else left = quoted_node(other.begin) right = quoted_node(other.end) Nodes::Between.new(self, left.and(right)) end end def in other case other when Arel::SelectManager Arel::Nodes::In.new(self, other.ast) when Range if $VERBOSE warn <<-eowarn Passing a range to `#in` is deprecated. Call `#between`, instead. eowarn end between(other) when Enumerable Nodes::In.new self, quoted_array(other) else Nodes::In.new self, quoted_node(other) end end def in_any others grouping_any :in, others end def in_all others grouping_all :in, others end def not_between other if equals_quoted?(other.begin, -Float::INFINITY) if equals_quoted?(other.end, Float::INFINITY) self.in([]) elsif other.exclude_end? gteq(other.end) else gt(other.end) end elsif equals_quoted?(other.end, Float::INFINITY) lt(other.begin) else left = lt(other.begin) right = if other.exclude_end? gteq(other.end) else gt(other.end) end left.or(right) end end def not_in other case other when Arel::SelectManager Arel::Nodes::NotIn.new(self, other.ast) when Range if $VERBOSE warn <<-eowarn Passing a range to `#not_in` is deprecated. Call `#not_between`, instead. eowarn end not_between(other) when Enumerable Nodes::NotIn.new self, quoted_array(other) else Nodes::NotIn.new self, quoted_node(other) end end def not_in_any others grouping_any :not_in, others end def not_in_all others grouping_all :not_in, others end def matches other, escape = nil, case_sensitive = false Nodes::Matches.new self, quoted_node(other), escape, case_sensitive end def matches_regexp other, case_sensitive = true Nodes::Regexp.new self, quoted_node(other), case_sensitive end def matches_any others, escape = nil, case_sensitive = false grouping_any :matches, others, escape, case_sensitive end def matches_all others, escape = nil, case_sensitive = false grouping_all :matches, others, escape, case_sensitive end def does_not_match other, escape = nil, case_sensitive = false Nodes::DoesNotMatch.new self, quoted_node(other), escape, case_sensitive end def does_not_match_regexp other, case_sensitive = true Nodes::NotRegexp.new self, quoted_node(other), case_sensitive end def does_not_match_any others, escape = nil grouping_any :does_not_match, others, escape end def does_not_match_all others, escape = nil grouping_all :does_not_match, others, escape end def gteq right Nodes::GreaterThanOrEqual.new self, quoted_node(right) end def gteq_any others grouping_any :gteq, others end def gteq_all others grouping_all :gteq, others end def gt right Nodes::GreaterThan.new self, quoted_node(right) end def gt_any others grouping_any :gt, others end def gt_all others grouping_all :gt, others end def lt right Nodes::LessThan.new self, quoted_node(right) end def lt_any others grouping_any :lt, others end def lt_all others grouping_all :lt, others end def lteq right Nodes::LessThanOrEqual.new self, quoted_node(right) end def lteq_any others grouping_any :lteq, others end def lteq_all others grouping_all :lteq, others end def when right Nodes::Case.new(self).when quoted_node(right) end def concat other Nodes::Concat.new self, other end private def grouping_any method_id, others, *extras nodes = others.map {|expr| send(method_id, expr, *extras)} Nodes::Grouping.new nodes.inject { |memo,node| Nodes::Or.new(memo, node) } end def grouping_all method_id, others, *extras nodes = others.map {|expr| send(method_id, expr, *extras)} Nodes::Grouping.new Nodes::And.new(nodes) end def quoted_node(other) Nodes.build_quoted(other, self) end def quoted_array(others) others.map { |v| quoted_node(v) } end def equals_quoted?(maybe_quoted, value) if maybe_quoted.is_a?(Nodes::Quoted) maybe_quoted.val == value else maybe_quoted == value end end end end arel-9.0.0/lib/arel/compatibility/0000755000004100000410000000000013272030740017033 5ustar www-datawww-dataarel-9.0.0/lib/arel/compatibility/wheres.rb0000644000004100000410000000116413272030740020657 0ustar www-datawww-data# frozen_string_literal: true module Arel module Compatibility # :nodoc: class Wheres # :nodoc: include Enumerable module Value # :nodoc: attr_accessor :visitor def value visitor.accept self end def name super.to_sym end end def initialize engine, collection @engine = engine @collection = collection end def each to_sql = Visitors::ToSql.new @engine @collection.each { |c| c.extend(Value) c.visitor = to_sql yield c } end end end end arel-9.0.0/lib/arel/nodes.rb0000644000004100000410000000314313272030740015620 0ustar www-datawww-data# frozen_string_literal: true # node require 'arel/nodes/node' require 'arel/nodes/select_statement' require 'arel/nodes/select_core' require 'arel/nodes/insert_statement' require 'arel/nodes/update_statement' require 'arel/nodes/bind_param' # terminal require 'arel/nodes/terminal' require 'arel/nodes/true' require 'arel/nodes/false' # unary require 'arel/nodes/unary' require 'arel/nodes/grouping' require 'arel/nodes/ascending' require 'arel/nodes/descending' require 'arel/nodes/unqualified_column' require 'arel/nodes/with' # binary require 'arel/nodes/binary' require 'arel/nodes/equality' require 'arel/nodes/in' # Why is this subclassed from equality? require 'arel/nodes/join_source' require 'arel/nodes/delete_statement' require 'arel/nodes/table_alias' require 'arel/nodes/infix_operation' require 'arel/nodes/unary_operation' require 'arel/nodes/over' require 'arel/nodes/matches' require 'arel/nodes/regexp' # nary require 'arel/nodes/and' # function # FIXME: Function + Alias can be rewritten as a Function and Alias node. # We should make Function a Unary node and deprecate the use of "aliaz" require 'arel/nodes/function' require 'arel/nodes/count' require 'arel/nodes/extract' require 'arel/nodes/values' require 'arel/nodes/values_list' require 'arel/nodes/named_function' # windows require 'arel/nodes/window' # conditional expressions require 'arel/nodes/case' # joins require 'arel/nodes/full_outer_join' require 'arel/nodes/inner_join' require 'arel/nodes/outer_join' require 'arel/nodes/right_outer_join' require 'arel/nodes/string_join' require 'arel/nodes/sql_literal' require 'arel/nodes/casted' arel-9.0.0/lib/arel/collectors/0000755000004100000410000000000013272030740016333 5ustar www-datawww-dataarel-9.0.0/lib/arel/collectors/bind.rb0000644000004100000410000000045513272030740017600 0ustar www-datawww-data# frozen_string_literal: true module Arel module Collectors class Bind def initialize @binds = [] end def << str self end def add_bind bind @binds << bind self end def value @binds end end end end arel-9.0.0/lib/arel/collectors/composite.rb0000644000004100000410000000077513272030740020673 0ustar www-datawww-data# frozen_string_literal: true module Arel module Collectors class Composite def initialize(left, right) @left = left @right = right end def << str left << str right << str self end def add_bind bind, &block left.add_bind bind, &block right.add_bind bind, &block self end def value [left.value, right.value] end protected attr_reader :left, :right end end end arel-9.0.0/lib/arel/collectors/plain_string.rb0000644000004100000410000000040013272030740021343 0ustar www-datawww-data# frozen_string_literal: true module Arel module Collectors class PlainString def initialize @str = ''.dup end def value @str end def << str @str << str self end end end end arel-9.0.0/lib/arel/collectors/substitute_binds.rb0000644000004100000410000000072513272030740022256 0ustar www-datawww-data# frozen_string_literal: true module Arel module Collectors class SubstituteBinds def initialize(quoter, delegate_collector) @quoter = quoter @delegate = delegate_collector end def << str delegate << str self end def add_bind bind self << quoter.quote(bind) end def value delegate.value end protected attr_reader :quoter, :delegate end end end arel-9.0.0/lib/arel/collectors/sql_string.rb0000644000004100000410000000057613272030740021055 0ustar www-datawww-data# frozen_string_literal: true require 'arel/collectors/plain_string' module Arel module Collectors class SQLString < PlainString def initialize(*) super @bind_index = 1 end def add_bind bind self << yield(@bind_index) @bind_index += 1 self end def compile bvs value end end end end arel-9.0.0/lib/arel/update_manager.rb0000644000004100000410000000172413272030740017467 0ustar www-datawww-data# frozen_string_literal: true module Arel class UpdateManager < Arel::TreeManager def initialize super @ast = Nodes::UpdateStatement.new @ctx = @ast end def take limit @ast.limit = Nodes::Limit.new(Nodes.build_quoted(limit)) if limit self end def key= key @ast.key = Nodes.build_quoted(key) end def key @ast.key end def order *expr @ast.orders = expr self end ### # UPDATE +table+ def table table @ast.relation = table self end def wheres= exprs @ast.wheres = exprs end def where expr @ast.wheres << expr self end def set values if String === values @ast.values = [values] else @ast.values = values.map { |column,value| Nodes::Assignment.new( Nodes::UnqualifiedColumn.new(column), value ) } end self end end end arel-9.0.0/lib/arel/alias_predication.rb0000644000004100000410000000023513272030740020161 0ustar www-datawww-data# frozen_string_literal: true module Arel module AliasPredication def as other Nodes::As.new self, Nodes::SqlLiteral.new(other) end end endarel-9.0.0/lib/arel.rb0000644000004100000410000000136013272030740014507 0ustar www-datawww-data# frozen_string_literal: true require 'arel/errors' require 'arel/crud' require 'arel/factory_methods' require 'arel/expressions' require 'arel/predications' require 'arel/window_predications' require 'arel/math' require 'arel/alias_predication' require 'arel/order_predications' require 'arel/table' require 'arel/attributes' require 'arel/compatibility/wheres' require 'arel/visitors' require 'arel/tree_manager' require 'arel/insert_manager' require 'arel/select_manager' require 'arel/update_manager' require 'arel/delete_manager' require 'arel/nodes' module Arel VERSION = '9.0.0' def self.sql raw_sql Arel::Nodes::SqlLiteral.new raw_sql end def self.star sql '*' end ## Convenience Alias Node = Arel::Nodes::Node end arel-9.0.0/arel.gemspec0000644000004100000410000001272713272030740014772 0ustar www-datawww-data######################################################### # This file has been automatically generated by gem2tgz # ######################################################### # -*- encoding: utf-8 -*- # stub: arel 9.0.0 ruby lib Gem::Specification.new do |s| s.name = "arel".freeze s.version = "9.0.0" s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Aaron Patterson".freeze, "Bryan Helmkamp".freeze, "Emilio Tagua".freeze, "Nick Kallen".freeze] s.date = "2017-11-14" s.description = "Arel Really Exasperates Logicians\n\nArel is a SQL AST manager for Ruby. It\n\n1. Simplifies the generation of complex SQL queries\n2. Adapts to various RDBMSes\n\nIt is intended to be a framework framework; that is, you can build your own ORM\nwith it, focusing on innovative object and collection modeling as opposed to\ndatabase compatibility and query generation.".freeze s.email = ["aaron@tenderlovemaking.com".freeze, "bryan@brynary.com".freeze, "miloops@gmail.com".freeze] s.extra_rdoc_files = ["History.txt".freeze, "MIT-LICENSE.txt".freeze, "README.md".freeze] s.files = ["History.txt".freeze, "MIT-LICENSE.txt".freeze, "README.md".freeze, "lib/arel.rb".freeze, "lib/arel/alias_predication.rb".freeze, "lib/arel/attributes.rb".freeze, "lib/arel/attributes/attribute.rb".freeze, "lib/arel/collectors/bind.rb".freeze, "lib/arel/collectors/composite.rb".freeze, "lib/arel/collectors/plain_string.rb".freeze, "lib/arel/collectors/sql_string.rb".freeze, "lib/arel/collectors/substitute_binds.rb".freeze, "lib/arel/compatibility/wheres.rb".freeze, "lib/arel/crud.rb".freeze, "lib/arel/delete_manager.rb".freeze, "lib/arel/errors.rb".freeze, "lib/arel/expressions.rb".freeze, "lib/arel/factory_methods.rb".freeze, "lib/arel/insert_manager.rb".freeze, "lib/arel/math.rb".freeze, "lib/arel/nodes.rb".freeze, "lib/arel/nodes/and.rb".freeze, "lib/arel/nodes/ascending.rb".freeze, "lib/arel/nodes/binary.rb".freeze, "lib/arel/nodes/bind_param.rb".freeze, "lib/arel/nodes/case.rb".freeze, "lib/arel/nodes/casted.rb".freeze, "lib/arel/nodes/count.rb".freeze, "lib/arel/nodes/delete_statement.rb".freeze, "lib/arel/nodes/descending.rb".freeze, "lib/arel/nodes/equality.rb".freeze, "lib/arel/nodes/extract.rb".freeze, "lib/arel/nodes/false.rb".freeze, "lib/arel/nodes/full_outer_join.rb".freeze, "lib/arel/nodes/function.rb".freeze, "lib/arel/nodes/grouping.rb".freeze, "lib/arel/nodes/in.rb".freeze, "lib/arel/nodes/infix_operation.rb".freeze, "lib/arel/nodes/inner_join.rb".freeze, "lib/arel/nodes/insert_statement.rb".freeze, "lib/arel/nodes/join_source.rb".freeze, "lib/arel/nodes/matches.rb".freeze, "lib/arel/nodes/named_function.rb".freeze, "lib/arel/nodes/node.rb".freeze, "lib/arel/nodes/outer_join.rb".freeze, "lib/arel/nodes/over.rb".freeze, "lib/arel/nodes/regexp.rb".freeze, "lib/arel/nodes/right_outer_join.rb".freeze, "lib/arel/nodes/select_core.rb".freeze, "lib/arel/nodes/select_statement.rb".freeze, "lib/arel/nodes/sql_literal.rb".freeze, "lib/arel/nodes/string_join.rb".freeze, "lib/arel/nodes/table_alias.rb".freeze, "lib/arel/nodes/terminal.rb".freeze, "lib/arel/nodes/true.rb".freeze, "lib/arel/nodes/unary.rb".freeze, "lib/arel/nodes/unary_operation.rb".freeze, "lib/arel/nodes/unqualified_column.rb".freeze, "lib/arel/nodes/update_statement.rb".freeze, "lib/arel/nodes/values.rb".freeze, "lib/arel/nodes/values_list.rb".freeze, "lib/arel/nodes/window.rb".freeze, "lib/arel/nodes/with.rb".freeze, "lib/arel/order_predications.rb".freeze, "lib/arel/predications.rb".freeze, "lib/arel/select_manager.rb".freeze, "lib/arel/table.rb".freeze, "lib/arel/tree_manager.rb".freeze, "lib/arel/update_manager.rb".freeze, "lib/arel/visitors.rb".freeze, "lib/arel/visitors/depth_first.rb".freeze, "lib/arel/visitors/dot.rb".freeze, "lib/arel/visitors/ibm_db.rb".freeze, "lib/arel/visitors/informix.rb".freeze, "lib/arel/visitors/mssql.rb".freeze, "lib/arel/visitors/mysql.rb".freeze, "lib/arel/visitors/oracle.rb".freeze, "lib/arel/visitors/oracle12.rb".freeze, "lib/arel/visitors/postgresql.rb".freeze, "lib/arel/visitors/reduce.rb".freeze, "lib/arel/visitors/sqlite.rb".freeze, "lib/arel/visitors/to_sql.rb".freeze, "lib/arel/visitors/visitor.rb".freeze, "lib/arel/visitors/where_sql.rb".freeze, "lib/arel/window_predications.rb".freeze] s.homepage = "https://github.com/rails/arel".freeze s.licenses = ["MIT".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.2.2".freeze) s.rubygems_version = "2.5.2.1".freeze s.summary = "Arel Really Exasperates Logicians Arel is a SQL AST manager for Ruby".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then s.add_development_dependency(%q.freeze, ["~> 1.0"]) s.add_development_dependency(%q.freeze, ["~> 5.4"]) s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 4.0"]) else s.add_dependency(%q.freeze, ["~> 1.0"]) s.add_dependency(%q.freeze, ["~> 5.4"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 4.0"]) end else s.add_dependency(%q.freeze, ["~> 1.0"]) s.add_dependency(%q.freeze, ["~> 5.4"]) s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 4.0"]) end end arel-9.0.0/MIT-LICENSE.txt0000644000004100000410000000212413272030740014742 0ustar www-datawww-dataCopyright (c) 2007-2016 Nick Kallen, Bryan Helmkamp, Emilio Tagua, Aaron Patterson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.