From 5d7c8176f1df8df819dadb1973a202a1c2d9836d Mon Sep 17 00:00:00 2001 From: Josh Susser Date: Sun, 9 Mar 2008 15:40:11 -0700 Subject: change README to README.markdown --- README | 65 ------------------------------------------------------- README.markdown | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 65 deletions(-) delete mode 100644 README create mode 100644 README.markdown diff --git a/README b/README deleted file mode 100644 index d60a4ec0bb..0000000000 --- a/README +++ /dev/null @@ -1,65 +0,0 @@ -== Abstract == - -ActiveRelation is a Relational Algebra for Ruby. It simplifies the generation of both the simplest and the most complex of SQL queries and it transparently adapts to various RDBMS systems. 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. - -== A Gentle Introduction == - -Generating a query with ARel is simple. For example, in order to produce - - SELECT * FROM users - -you construct a table relation and convert it to sql: - - ActiveRelation::Table.new(:users).to_sql - -In fact, you will probably never call `#to_sql`. Let `users = ActiveRelation::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: - - users.each { |user| ... } - -In other words, Arel relations behave implement Ruby's Eunmerable interface. Let's have a look at a concrete example: - - users.first # => {'id' => 10, 'name' => 'bob'} - -As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). - -== Relational Algebra == - -Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: - - users.insert({users[:name] => 'amy'}) # => INSERT INTO users (users.name) VALUES ('amy') - -To delete all users: - - users.delete # => DELETE FROM users - -To update: - - users.update({users[:name] => 'carl'}) # => UPDATE users SET name = 'carl' - -As you can see, the `relation` named `users` does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate SQL queries to do the various CRUD operations. - -=== More Sophisticated Queries Relations === - -Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: - - users.select(users[:name].equals('amy')) # => SELECT * FROM users WHERE users.name = 'amy' - -What would, in SQL, be part of the `SELECT` clause is called here a `projection`: - - users.project(users[:id]) # => SELECT users.id FROM users - -Joins are fairly straightforward: - - users.join(photos).on(users[:id].equals(photos[:user_id])) => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id - -The best property of the Relational is compositionality, or closure under all operations. For example, to select and project: - - users \ - .select(users[:name].equals('amy')) \ - .project(users[:id]) \ - # => SELECT users.id FROM users WHERE users.name = 'amy' -s - -== Contributions == - -I appreciate all contributions to ActiveRelation. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. \ No newline at end of file diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000000..4324b0b128 --- /dev/null +++ b/README.markdown @@ -0,0 +1,67 @@ +ActiveRelation +============== + +## Abstract ## + +ActiveRelation is a Relational Algebra for Ruby. It simplifies the generation of both the simplest and the most complex of SQL queries and it transparently adapts to various RDBMS systems. 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. + +## A Gentle Introduction ## + +Generating a query with ARel is simple. For example, in order to produce + + SELECT * FROM users + +you construct a table relation and convert it to sql: + + ActiveRelation::Table.new(:users).to_sql + +In fact, you will probably never call `#to_sql`. Let `users = ActiveRelation::Table.new(:users)`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: + + users.each { |user| ... } + +In other words, Arel relations behave implement Ruby's Eunmerable interface. Let's have a look at a concrete example: + + users.first # => {'id' => 10, 'name' => 'bob'} + +As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). + +## Relational Algebra ## + +Arel is based on the Relational Algebra, a mathematical model that is also the inspiration for relational databases. ActiveRelation::Relation objects do not represent queries per se (i.e., they are not object-representations of `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements), rather they represent a collection of data that you can select from, insert into, update, and delete. For example, to insert a row into the users table, do the following: + + users.insert({users[:name] => 'amy'}) # => INSERT INTO users (users.name) VALUES ('amy') + +To delete all users: + + users.delete # => DELETE FROM users + +To update: + + users.update({users[:name] => 'carl'}) # => UPDATE users SET name = 'carl' + +As you can see, the `relation` named `users` does not represent an individual query; rather it is an abstraction on a collection of data and it can produce appropriate SQL queries to do the various CRUD operations. + +### More Sophisticated Queries Relations ### + +Following the Relational Algebra, Arel's interface uses some jargon that differs from standard SQL. For example, in order to add a `WHERE` clause to your relations, you use the `select` operation: + + users.select(users[:name].equals('amy')) # => SELECT * FROM users WHERE users.name = 'amy' + +What would, in SQL, be part of the `SELECT` clause is called here a `projection`: + + users.project(users[:id]) # => SELECT users.id FROM users + +Joins are fairly straightforward: + + users.join(photos).on(users[:id].equals(photos[:user_id])) => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id + +The best property of the Relational is compositionality, or closure under all operations. For example, to select and project: + + users \ + .select(users[:name].equals('amy')) \ + .project(users[:id]) \ + # => SELECT users.id FROM users WHERE users.name = 'amy' + +## Contributions ## + +I appreciate all contributions to ActiveRelation. There is only one "unusual" requirement I have concerning code style: all specs should be written without mocks, using concrete examples to elicit testable behavior. This has two benefits: it 1) ensures the tests serve as concrete documentation and 2) suits the functional nature of this library, which emphasizes algebraic transformation rather than decoupled components. -- cgit v1.2.3 From e2661658a083a229975110dcdd03e60068d8851e Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 27 May 2008 21:59:18 -0400 Subject: Update TODO --- doc/TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/TODO b/doc/TODO index 65f9cfbca7..740e5db5fe 100644 --- a/doc/TODO +++ b/doc/TODO @@ -20,6 +20,7 @@ users.delete().where( - rewrite of arecord querycache test in light of this - transactions - scoped writes +- asc/desc for orderings done: - and/or w/ predicates -- cgit v1.2.3 From 5b87e3869e1da533d4d31da64703eac113495662 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 16 May 2009 23:09:59 -0400 Subject: Rename README -> README.markdown --- README | 184 -------------------------------------------------------- README.markdown | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 184 deletions(-) delete mode 100644 README create mode 100644 README.markdown diff --git a/README b/README deleted file mode 100644 index e979dbc2a3..0000000000 --- a/README +++ /dev/null @@ -1,184 +0,0 @@ -## Abstract ## - -Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 2) adapts to various RDBMS systems. 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 ## - -Arel is alpha software, BEWARE. Nevertheless, at this point, many (most?) SELECT queries can be composed, including very very complicated ones. Writes are only experimental for now. - -For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. On the horizon is the use of DataObjects instead. - -The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc. - -## A Gentle Introduction ## - -Generating a query with ARel is simple. For example, in order to produce - - SELECT * FROM users - -you construct a table relation and convert it to sql: - - users = Arel(:users) - users.to_sql - -In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: - - users.each { |user| ... } - -In other words, Arel relations implement Ruby's Enumerable interface. Let's have a look at a concrete example: - - users.first # => { users[:id] => 1, users[:name] => 'bob' } - -As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). - -### More Sophisticated Queries Relations ### - -Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database. - -First is the 'restriction' operator, `where`: - - 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`: - - users.project(users[:id]) # => SELECT users.id FROM users - -Joins resemble SQL strongly: - - users.join(photos).on(users[:id].eq(photos[:user_id])) - # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id - -What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel: - - users.take(5) # => SELECT * FROM users LIMIT 5 - users.skip(4) # => SELECT * FROM users OFFSET 4 - -`GROUP BY` is called `group`: - - users.group(users[:name]) # => SELECT * FROM users GROUP BY name - -The best property of the Relational Algebra is its "composability", or closure under all operations. For example, to select AND project, just "chain" the method invocations: - - 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. - - users.where(users[:name].eq('bob')).where(users[:age].lt(25)) - -Of course, many of the operators take multiple arguments, so the last example can be written more tersely: - - users.where(users[:name].eq('bob'), users[:age].lt(25)) - -The `OR` operator is not yet supported. It will work like this: - - users.where(users[:name].eq('bob').or(users[:age].lt(25))) - -The `AND` operator will behave similarly. - -Finally, most operations take a block form. For example: - - Arel(:users) \ - .where { |u| u[:id].eq(1) } \ - .project { |u| u[:id] } - -This provides a (sometimes) convenient alternative syntax. - -### The Crazy 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). - -#### Complex Joins #### - -Where Arel really shines 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: - - comments = Arel(:comments) - -And this table has the following attributes: - - comments.attributes # => [comments[:id], comments[:body], comments[:parent_id]] - -The `parent_id` column is a foreign key from the `comments` table to itself. Now, joining a table to itself requires aliasing in SQL. In fact, you may alias in Arel as well: - - replies = comments.alias - comments_with_replies = \ - comments.join(replies).on(replies[:parent_id].eq(comments[:id])) - # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id - -The call to `#alias` is actually optional: Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Explicit aliasing is more common, however. When you want to extract specific slices of data, aliased tables are a necessity. For example to get just certain columns from the row, treat a row like a hash: - - comments_with_replies.first[replies[:body]] - -This will return the first comment's reply's body. - -If you don't need to extract the data later (for example, you're simply doing a join to find comments that have replies, you don't care what the content of the replies are), the block form may be preferable: - - comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } - # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id - -Note that you do NOT want to do something like: - - comments.join(comments, comments[:parent_id].eq(comments[:id])) - # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id - -This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous. - -#### Complex Aggregations #### - -My personal favorite feature of Arel, certainly the most difficult to implement, and possibly only of marginal value, is **closure under joining even in the presence of aggregations**. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. Think of this as a preview of the kind of radical functionality that is to come, stuff no other "ORM" is doing. - -The easiest way to introduce this is in SQL. Your task is to get all users and the **count** of their associated photos. Let's start from the inside out: - - SELECT count(*) - FROM photos - GROUP BY user_id - -Now, we'd like to join this with the user table. Naively, you might try to do this: - - SELECT users.*, count(photos.id) - FROM users - LEFT OUTER JOIN photos - ON users.id = photos.id - GROUP BY photos.user_id - -Of course, this has a slightly different meaning than our intended query. This is actually a fairly advanced topic in SQL so let's see why this doesn't work *step by step*. Suppose we have these records in our `users` table: - - mysql> select * from users; - +------+--------+ - | id | name | - +------+--------+ - | 1 | hai | - | 2 | bai | - | 3 | dumpty | - +------+--------+ - -And these in the photos table: - - mysql> select * from photos; - +------+---------+-----------+ - | id | user_id | camera_id | - +------+---------+-----------+ - | 1 | 1 | 1 | - | 2 | 1 | 1 | - | 3 | 1 | 1 | - +------+---------+-----------+ - -If we perform the above, incorrect query, we get the following: - - mysql> select users.*, count(photos.id) from users left outer join photos on users.id = photos.user_id limit 3 group by user_id; - +------+------+------------------+ - | id | name | count(photos.id) | - +------+------+------------------+ - | 2 | bai | 0 | - | 1 | hai | 3 | - +------+------+------------------+ - -As you can see, we're completely missing data for user with id 3. `dumpty` has no photos, neither does `bai`. But strangely `bai` appeared and `dumpty` didn't! The reason is that the `GROUP BY` clause is aggregating on both tables, not just the `photos` table. All users without photos have a `photos.id` of `null` (thanks to the left outer join). These are rolled up together and an arbitrary user wins. In this case, `bai` not `dumpty`. - - SELECT users.*, photos_aggregation.cnt - FROM users - LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation - ON photos_aggregation.user_id = users.id \ No newline at end of file diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000000..e979dbc2a3 --- /dev/null +++ b/README.markdown @@ -0,0 +1,184 @@ +## Abstract ## + +Arel is a Relational Algebra for Ruby. It 1) simplifies the generation complex of SQL queries and it 2) adapts to various RDBMS systems. 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 ## + +Arel is alpha software, BEWARE. Nevertheless, at this point, many (most?) SELECT queries can be composed, including very very complicated ones. Writes are only experimental for now. + +For the moment, Arel uses ActiveRecord's connection adapters to connect to the various engines, connection pooling, perform quoting, and do type conversion. On the horizon is the use of DataObjects instead. + +The long term goal, following both LINQ and DataMapper, is to have Arel adapt to engines beyond RDBMS, including XML, IMAP, YAML, etc. + +## A Gentle Introduction ## + +Generating a query with ARel is simple. For example, in order to produce + + SELECT * FROM users + +you construct a table relation and convert it to sql: + + users = Arel(:users) + users.to_sql + +In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: + + users.each { |user| ... } + +In other words, Arel relations implement Ruby's Enumerable interface. Let's have a look at a concrete example: + + users.first # => { users[:id] => 1, users[:name] => 'bob' } + +As you can see, Arel converts the rows from the database into a hash, the values of which are sublimated to the appropriate Ruby primitive (integers, strings, and so forth). + +### More Sophisticated Queries Relations ### + +Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database. + +First is the 'restriction' operator, `where`: + + 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`: + + users.project(users[:id]) # => SELECT users.id FROM users + +Joins resemble SQL strongly: + + users.join(photos).on(users[:id].eq(photos[:user_id])) + # => SELECT * FROM users INNER JOIN photos ON users.id = photos.user_id + +What are called `LIMIT` and `OFFSET` in SQL are called `take` and `skip` in Arel: + + users.take(5) # => SELECT * FROM users LIMIT 5 + users.skip(4) # => SELECT * FROM users OFFSET 4 + +`GROUP BY` is called `group`: + + users.group(users[:name]) # => SELECT * FROM users GROUP BY name + +The best property of the Relational Algebra is its "composability", or closure under all operations. For example, to select AND project, just "chain" the method invocations: + + 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. + + users.where(users[:name].eq('bob')).where(users[:age].lt(25)) + +Of course, many of the operators take multiple arguments, so the last example can be written more tersely: + + users.where(users[:name].eq('bob'), users[:age].lt(25)) + +The `OR` operator is not yet supported. It will work like this: + + users.where(users[:name].eq('bob').or(users[:age].lt(25))) + +The `AND` operator will behave similarly. + +Finally, most operations take a block form. For example: + + Arel(:users) \ + .where { |u| u[:id].eq(1) } \ + .project { |u| u[:id] } + +This provides a (sometimes) convenient alternative syntax. + +### The Crazy 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). + +#### Complex Joins #### + +Where Arel really shines 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: + + comments = Arel(:comments) + +And this table has the following attributes: + + comments.attributes # => [comments[:id], comments[:body], comments[:parent_id]] + +The `parent_id` column is a foreign key from the `comments` table to itself. Now, joining a table to itself requires aliasing in SQL. In fact, you may alias in Arel as well: + + replies = comments.alias + comments_with_replies = \ + comments.join(replies).on(replies[:parent_id].eq(comments[:id])) + # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id + +The call to `#alias` is actually optional: Arel will always produce a unique name for every table joined in the relation, and it will always do so deterministically to exploit query caching. Explicit aliasing is more common, however. When you want to extract specific slices of data, aliased tables are a necessity. For example to get just certain columns from the row, treat a row like a hash: + + comments_with_replies.first[replies[:body]] + +This will return the first comment's reply's body. + +If you don't need to extract the data later (for example, you're simply doing a join to find comments that have replies, you don't care what the content of the replies are), the block form may be preferable: + + comments.join(comments) { |comments, replies| replies[:parent_id].eq(comments[:id]) } + # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments_2.parent_id = comments.id + +Note that you do NOT want to do something like: + + comments.join(comments, comments[:parent_id].eq(comments[:id])) + # => SELECT * FROM comments INNER JOIN comments AS comments_2 WHERE comments.parent_id = comments.id + +This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous. + +#### Complex Aggregations #### + +My personal favorite feature of Arel, certainly the most difficult to implement, and possibly only of marginal value, is **closure under joining even in the presence of aggregations**. This is a feature where the Relational Algebra is fundamentally easier to use than SQL. Think of this as a preview of the kind of radical functionality that is to come, stuff no other "ORM" is doing. + +The easiest way to introduce this is in SQL. Your task is to get all users and the **count** of their associated photos. Let's start from the inside out: + + SELECT count(*) + FROM photos + GROUP BY user_id + +Now, we'd like to join this with the user table. Naively, you might try to do this: + + SELECT users.*, count(photos.id) + FROM users + LEFT OUTER JOIN photos + ON users.id = photos.id + GROUP BY photos.user_id + +Of course, this has a slightly different meaning than our intended query. This is actually a fairly advanced topic in SQL so let's see why this doesn't work *step by step*. Suppose we have these records in our `users` table: + + mysql> select * from users; + +------+--------+ + | id | name | + +------+--------+ + | 1 | hai | + | 2 | bai | + | 3 | dumpty | + +------+--------+ + +And these in the photos table: + + mysql> select * from photos; + +------+---------+-----------+ + | id | user_id | camera_id | + +------+---------+-----------+ + | 1 | 1 | 1 | + | 2 | 1 | 1 | + | 3 | 1 | 1 | + +------+---------+-----------+ + +If we perform the above, incorrect query, we get the following: + + mysql> select users.*, count(photos.id) from users left outer join photos on users.id = photos.user_id limit 3 group by user_id; + +------+------+------------------+ + | id | name | count(photos.id) | + +------+------+------------------+ + | 2 | bai | 0 | + | 1 | hai | 3 | + +------+------+------------------+ + +As you can see, we're completely missing data for user with id 3. `dumpty` has no photos, neither does `bai`. But strangely `bai` appeared and `dumpty` didn't! The reason is that the `GROUP BY` clause is aggregating on both tables, not just the `photos` table. All users without photos have a `photos.id` of `null` (thanks to the left outer join). These are rolled up together and an arbitrary user wins. In this case, `bai` not `dumpty`. + + SELECT users.*, photos_aggregation.cnt + FROM users + LEFT OUTER JOIN (SELECT user_id, count(*) as cnt FROM photos GROUP BY user_id) AS photos_aggregation + ON photos_aggregation.user_id = users.id \ No newline at end of file -- cgit v1.2.3 From 49d119ae84bbb7cd180ca855cf48997dc731554c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sat, 16 May 2009 21:13:32 -0400 Subject: Adding spec:mysql and spec:sqlite3 tasks --- .gitignore | 1 + Rakefile | 24 +++- spec/arel/integration/joins/with_adjacency_spec.rb | 150 +++++++++++++++------ .../integration/joins/with_aggregations_spec.rb | 150 ++++++++++++++++----- spec/arel/integration/joins/with_compounds_spec.rb | 90 +++++++++---- spec/arel/unit/predicates/binary_spec.rb | 76 +++++++---- spec/arel/unit/predicates/equality_spec.rb | 38 ++++-- spec/arel/unit/predicates/in_spec.rb | 68 +++++++--- spec/arel/unit/predicates/predicates_spec.rb | 36 +++-- spec/arel/unit/primitives/attribute_spec.rb | 62 +++++---- spec/arel/unit/primitives/expression_spec.rb | 10 +- spec/arel/unit/relations/alias_spec.rb | 30 +++-- spec/arel/unit/relations/delete_spec.rb | 57 ++++++-- spec/arel/unit/relations/group_spec.rb | 48 +++++-- spec/arel/unit/relations/insert_spec.rb | 75 ++++++++--- spec/arel/unit/relations/join_spec.rb | 52 +++++-- spec/arel/unit/relations/order_spec.rb | 101 ++++++++++---- spec/arel/unit/relations/project_spec.rb | 89 +++++++++--- spec/arel/unit/relations/skip_spec.rb | 22 ++- spec/arel/unit/relations/table_spec.rb | 41 +++--- spec/arel/unit/relations/take_spec.rb | 22 ++- spec/arel/unit/relations/update_spec.rb | 95 ++++++++++--- spec/arel/unit/relations/where_spec.rb | 44 ++++-- spec/connections/mysql_connection.rb | 13 ++ spec/connections/sqlite3_connection.rb | 22 +++ spec/doubles/database.rb | 51 ------- spec/schemas/mysql_schema.rb | 18 +++ spec/schemas/sqlite3_schema.rb | 18 +++ spec/spec_helper.rb | 19 ++- 29 files changed, 1101 insertions(+), 421 deletions(-) create mode 100644 spec/connections/mysql_connection.rb create mode 100644 spec/connections/sqlite3_connection.rb delete mode 100644 spec/doubles/database.rb create mode 100644 spec/schemas/mysql_schema.rb create mode 100644 spec/schemas/sqlite3_schema.rb diff --git a/.gitignore b/.gitignore index 2bab52ab21..da2f440bad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ coverage/* config/database.yml +spec/fixtures/*database* *.DS_Store diff --git a/Rakefile b/Rakefile index b1fc74a13c..9292ac2533 100644 --- a/Rakefile +++ b/Rakefile @@ -1,15 +1,31 @@ require 'rubygems' require 'spec/rake/spectask' -Spec::Rake::SpecTask.new do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] -end +spec_file_list = FileList['spec/**/*_spec.rb'] +desc "Run specs using RCov (uses mysql database adapter)" Spec::Rake::SpecTask.new(:coverage) do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] + t.spec_files = + ["spec/connections/mysql_connection.rb"] + + spec_file_list t.rcov = true t.rcov_opts = ['-x', 'spec,gems'] end +namespace :spec do + for adapter in %w[mysql sqlite3] + desc "Run specs with the #{adapter} database adapter" + Spec::Rake::SpecTask.new(adapter) do |t| + t.spec_files = + ["spec/connections/#{adapter}_connection.rb"] + + ["spec/schemas/#{adapter}_schema.rb"] + + spec_file_list + end + end +end + +desc "Run specs with mysql and sqlite3 database adapters (default)" +task :spec => ["spec:sqlite3", "spec:mysql"] + desc "Default task is to run specs" task :default => :spec \ No newline at end of file diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index 559b5bbe1a..fbac723e10 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -11,39 +11,79 @@ module Arel describe 'when joining a relation to itself' do describe '#to_sql' do it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do - @relation1.join(@relation2).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - ") - end + sql = @relation1.join(@relation2).on(@predicate).to_sql - describe 'when joining with a where on the same relation' do - it 'manufactures sql aliasing the tables properly' do - @relation1 \ - .join(@relation2.where(@relation2[:id].eq(1))) \ - .on(@predicate) \ - .to_sql.should be_like(" + adapter_is :mysql do + sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` FROM `users` INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 - ") + ON `users`.`id` = `users_2`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + }) + end + end + + describe 'when joining with a where on the same relation' do + it 'manufactures sql aliasing the tables properly' do + sql = @relation1 \ + .join(@relation2.where(@relation2[:id].eq(1))) \ + .on(@predicate) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1 + }) + end end describe 'when the where occurs before the alias' do it 'manufactures sql aliasing the predicates properly' do relation2 = @relation1.where(@relation1[:id].eq(1)).alias - @relation1 \ + + sql = @relation1 \ .join(relation2) \ .on(relation2[:id].eq(@relation1[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1 + }) + end end end end @@ -55,35 +95,65 @@ module Arel describe 'when joining left-associatively' do it 'manufactures sql aliasing the tables properly' do - @relation1 \ + sql = @relation1 \ .join(@relation2 \ .join(@relation3) \ .on(@relation2[:id].eq(@relation3[:id]))) \ .on(@relation1[:id].eq(@relation2[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + INNER JOIN "users" AS "users_3" + ON "users_2"."id" = "users_3"."id" + }) + end end end describe 'when joining right-associatively' do it 'manufactures sql aliasing the tables properly' do - @relation1 \ + sql = @relation1 \ .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + INNER JOIN "users" AS "users_3" + ON "users_2"."id" = "users_3"."id" + }) + end end end end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 2b21dcaa1e..41978c0a5a 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -18,68 +18,146 @@ module Arel describe '#to_sql' do # CLEANUP it '' do - @relation1.join(@relation2.take(3)).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` - FROM `users` - INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @relation1.join(@relation2.take(3)).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` + FROM `users` + INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" + FROM "users" + INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end end describe 'with the aggregation on the right' do it 'manufactures sql joining the left table to a derived table' do - @relation1.join(@aggregation).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @relation1.join(@aggregation).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" + FROM "users" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end end end describe 'with the aggregation on the left' do it 'manufactures sql joining the right table to a derived table' do - @aggregation.join(@relation1).on(@predicate).to_sql.should be_like(" - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @aggregation.join(@relation1).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN `users` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN "users" + ON "users"."id" = "photos_external"."user_id" + }) + end end end describe 'with the aggregation on both sides' do it 'it properly aliases the aggregations' do aggregation2 = @aggregation.alias - @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql.should be_like(" - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` - ON `photos_external_2`.`user_id` = `photos_external`.`user_id` - ") + sql = @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` + ON `photos_external_2`.`user_id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external_2" + ON "photos_external_2"."user_id" = "photos_external"."user_id" + }) + end end end describe 'when the aggration has a where' do describe 'with the aggregation on the left' do it "manufactures sql keeping wheres on the aggregation within the derived table" do - @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" + FROM "users" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end end end describe 'with the aggregation on the right' do it "manufactures sql keeping wheres on the aggregation within the derived table" do - @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql.should be_like(" - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - ") + sql = @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN `users` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN "users" + ON "users"."id" = "photos_external"."user_id" + }) + end end end end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 95fadc23d6..7582c5fc83 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -12,15 +12,28 @@ module Arel describe 'when the join contains a where' do describe 'and the where is given a string' do it 'does not escape the string' do - @relation1 \ + sql = @relation1 \ .join(@relation2.where("asdf")) \ .on(@predicate) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` AND asdf - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` AND asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" AND asdf + }) + end end end end @@ -28,35 +41,64 @@ module Arel describe 'when a compound contains a join' do describe 'and the compound is a where' do it 'manufactures sql disambiguating the tables' do - @relation1 \ + sql = @relation1 \ .where(@relation1[:id].eq(1)) \ .join(@relation2) \ .on(@predicate) \ .where(@relation1[:id].eq(1)) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - WHERE `users`.`id` = 1 - AND `users`.`id` = 1 - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + WHERE `users`.`id` = 1 + AND `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" + WHERE "users"."id" = 1 + AND "users"."id" = 1 + }) + end end end describe 'and the compound is a group' do it 'manufactures sql disambiguating the tables' do - @relation1 \ + sql = @relation1 \ .join(@relation2) \ .on(@predicate) \ .group(@relation1[:id]) \ - .to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - GROUP BY `users`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + GROUP BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" + GROUP BY "users"."id" + }) + end end end end diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb index 56fcf2d8ad..2d0c67e006 100644 --- a/spec/arel/unit/predicates/binary_spec.rb +++ b/spec/arel/unit/predicates/binary_spec.rb @@ -18,13 +18,19 @@ module Arel @operand1 = ConcreteBinary.new(@attribute1, 1) @operand2 = ConcreteBinary.new(@attribute2, "name") end - + describe Or do describe "#to_sql" do it "manufactures sql with an OR operation" do - Or.new(@operand1, @operand2).to_sql.should be_like(" - (`users`.`id` <=> 1 OR `users`.`name` <=> 'name') - ") + sql = Or.new(@operand1, @operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) + end end end end @@ -32,58 +38,82 @@ module Arel describe And do describe "#to_sql" do it "manufactures sql with an AND operation" do - And.new(@operand1, @operand2).to_sql.should be_like(" - (`users`.`id` <=> 1 AND `users`.`name` <=> 'name') - ") + sql = And.new(@operand1, @operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) + end end end end end - + describe '#to_sql' do describe 'when relating two attributes' do it 'manufactures sql with a binary operation' do - ConcreteBinary.new(@attribute1, @attribute2).to_sql.should be_like(" - `users`.`id` <=> `users`.`name` - ") + sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> "users"."name"}) + end end end - + describe 'when relating an attribute and a value' do before do @value = "1-asdf" end - + describe 'when relating to an integer attribute' do it 'formats values as integers' do - ConcreteBinary.new(@attribute1, @value).to_sql.should be_like(" - `users`.`id` <=> 1 - ") + sql = ConcreteBinary.new(@attribute1, @value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> 1}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> 1}) + end end end - + describe 'when relating to a string attribute' do it 'formats values as strings' do - ConcreteBinary.new(@attribute2, @value).to_sql.should be_like(" - `users`.`name` <=> '1-asdf' - ") + sql = ConcreteBinary.new(@attribute2, @value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) + end end end end end - + describe '#bind' do before do @another_relation = @relation.alias end - + describe 'when both operands are attributes' do it "manufactures an expression with the attributes bound to the relation" do ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) end end - + describe 'when an operand is a value' do it "manufactures an expression with unmodified values" do ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ diff --git a/spec/arel/unit/predicates/equality_spec.rb b/spec/arel/unit/predicates/equality_spec.rb index 8a58ba3096..b595cdd247 100644 --- a/spec/arel/unit/predicates/equality_spec.rb +++ b/spec/arel/unit/predicates/equality_spec.rb @@ -8,40 +8,52 @@ module Arel @attribute1 = @relation1[:id] @attribute2 = @relation2[:user_id] end - - describe '==' do + + describe '==' do it "obtains if attribute1 and attribute2 are identical" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) end - + it "obtains if the concrete type of the predicates are identical" do Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) end - + it "is commutative on the attributes" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) end end - + describe '#to_sql' do describe 'when relating to a non-nil value' do it "manufactures an equality predicate" do - Equality.new(@attribute1, @attribute2).to_sql.should be_like(" - `users`.`id` = `photos`.`user_id` - ") + sql = Equality.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) + end end end - + describe 'when relation to a nil value' do before do @nil = nil end - + it "manufactures an is null predicate" do - Equality.new(@attribute1, @nil).to_sql.should be_like(" - `users`.`id` IS NULL - ") + sql = Equality.new(@attribute1, @nil).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NULL}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IS NULL}) + end end end end diff --git a/spec/arel/unit/predicates/in_spec.rb b/spec/arel/unit/predicates/in_spec.rb index 797798a77f..9107da9d4b 100644 --- a/spec/arel/unit/predicates/in_spec.rb +++ b/spec/arel/unit/predicates/in_spec.rb @@ -6,51 +6,79 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - - describe '#to_sql' do + + describe '#to_sql' do describe 'when relating to an array' do describe 'when the array\'s elements are the same type as the attribute' do before do @array = [1, 2, 3] end - + it 'manufactures sql with a comma separated list' do - In.new(@attribute, @array).to_sql.should be_like(" - `users`.`id` IN (1, 2, 3) - ") + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end end end - + describe 'when the array\'s elements are not same type as the attribute' do before do @array = ['1-asdf', 2, 3] end - + it 'formats values in the array as the type of the attribute' do - In.new(@attribute, @array).to_sql.should be_like(" - `users`.`id` IN (1, 2, 3) - ") + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end end end end - + describe 'when relating to a range' do before do @range = 1..2 end - + it 'manufactures sql with a between' do - In.new(@attribute, @range).to_sql.should be_like(" - `users`.`id` BETWEEN 1 AND 2 - ") + sql = In.new(@attribute, @range).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) + end end end - + describe 'when relating to a relation' do it 'manufactures sql with a subselect' do - In.new(@attribute, @relation).to_sql.should be_like(" - `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) - ") + sql = In.new(@attribute, @relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") + }) + end end end end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb index d11637cabe..8f9cec5376 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -9,23 +9,43 @@ module Arel @operand1 = Equality.new(@attribute1, 1) @operand2 = Equality.new(@attribute2, "name") end - + describe "when being combined with another predicate with AND logic" do describe "#to_sql" do it "manufactures sql with an AND operation" do - @operand1.and(@operand2).to_sql.should be_like(" - (`users`.`id` = 1 AND `users`.`name` = 'name') - ") + sql = @operand1.and(@operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 AND `users`.`name` = 'name') + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = 'name') + }) + end end end end - + describe "when being combined with another predicate with OR logic" do describe "#to_sql" do it "manufactures sql with an OR operation" do - @operand1.or(@operand2).to_sql.should be_like(" - (`users`.`id` = 1 OR `users`.`name` = 'name') - ") + sql = @operand1.or(@operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 OR `users`.`name` = 'name') + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = 'name') + }) + end end end end diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index b341c6f88e..6d0f146a39 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -6,57 +6,57 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) end end - + describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end - + it "returns self if the substituting to the same relation" do @attribute.bind(@relation).should == @attribute end end - + describe '#to_attribute' do it "returns self" do @attribute.to_attribute.should == @attribute end end end - + describe '#column' do it "returns the corresponding column in the relation" do @attribute.column.should == @relation.column_for(@attribute) end end - + describe '#engine' do it "delegates to its relation" do Attribute.new(@relation, :id).engine.should == @relation.engine end end - + describe Attribute::Congruence do describe '/' do before do @aliased_relation = @relation.alias @doubly_aliased_relation = @aliased_relation.alias end - + describe 'when dividing two unrelated attributes' do it "returns 0.0" do (@relation[:id] / @relation[:name]).should == 0.0 end end - + describe 'when dividing two matching attributes' do it 'returns a the highest score for the most similar attributes' do (@aliased_relation[:id] / @relation[:id]) \ @@ -67,97 +67,105 @@ module Arel end end end - + describe '#to_sql' do describe 'for a simple attribute' do it "manufactures sql with an alias" do - @attribute.to_sql.should be_like("`users`.`id`") + sql = @attribute.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id"}) + end end end end - + describe Attribute::Predications do before do @attribute = Attribute.new(@relation, :name) end - + describe '#eq' do it "manufactures an equality predicate" do @attribute.eq('name').should == Equality.new(@attribute, 'name') end end - + describe '#lt' do it "manufactures a less-than predicate" do @attribute.lt(10).should == LessThan.new(@attribute, 10) end end - + describe '#lteq' do it "manufactures a less-than or equal-to predicate" do @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) end end - + describe '#gt' do it "manufactures a greater-than predicate" do @attribute.gt(10).should == GreaterThan.new(@attribute, 10) end end - + describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end - + describe '#matches' do it "manufactures a match predicate" do @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end - + describe '#in' do it "manufactures an in predicate" do @attribute.in(1..30).should == In.new(@attribute, (1..30)) end end end - + describe Attribute::Expressions do before do - @attribute = Attribute.new(@relation, :name) + @attribute = Attribute.new(@relation, :name) end - + describe '#count' do it "manufactures a count Expression" do @attribute.count.should == Expression.new(@attribute, "COUNT") end end - + describe '#sum' do it "manufactures a sum Expression" do @attribute.sum.should == Expression.new(@attribute, "SUM") end end - + describe '#maximum' do it "manufactures a maximum Expression" do @attribute.maximum.should == Expression.new(@attribute, "MAX") end end - + describe '#minimum' do it "manufactures a minimum Expression" do @attribute.minimum.should == Expression.new(@attribute, "MIN") end end - + describe '#average' do it "manufactures an average Expression" do @attribute.average.should == Expression.new(@attribute, "AVG") end - end + end end end end \ No newline at end of file diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index 4943f4ef33..ebde55ff90 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -38,7 +38,15 @@ module Arel describe '#to_sql' do it "manufactures sql with the expression and alias" do - Expression.new(@attribute, "COUNT", :alias).to_sql.should == "COUNT(`users`.`id`) AS `alias`" + sql = Expression.new(@attribute, "COUNT", :alias).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{COUNT("users"."id") AS "alias"}) + end end end end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 460a0ed0df..570f315892 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -16,19 +16,33 @@ module Arel describe '#to_sql' do describe 'when there is no ambiguity' do it 'does not alias table names anywhere a table name can appear' do - @relation \ + sql = @relation \ .where(@relation[:id].eq(1)) \ .order(@relation[:id]) \ .project(@relation[:id]) \ .group(@relation[:id]) \ .alias \ - .to_sql.should be_like(" - SELECT `users`.`id` - FROM `users` - WHERE `users`.`id` = 1 - GROUP BY `users`.`id` - ORDER BY `users`.`id` - ") + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id` + FROM `users` + WHERE `users`.`id` = 1 + GROUP BY `users`.`id` + ORDER BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + GROUP BY "users"."id" + ORDER BY "users"."id" + }) + end end end end diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/unit/relations/delete_spec.rb index fa887d20fd..3798178ccc 100644 --- a/spec/arel/unit/relations/delete_spec.rb +++ b/spec/arel/unit/relations/delete_spec.rb @@ -8,26 +8,55 @@ module Arel describe '#to_sql' do it 'manufactures sql deleting a table relation' do - Deletion.new(@relation).to_sql.should be_like(" - DELETE - FROM `users` - ") + sql = Deletion.new(@relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{DELETE FROM `users`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{DELETE FROM "users"}) + end end it 'manufactures sql deleting a where relation' do - Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql.should be_like(" - DELETE - FROM `users` - WHERE `users`.`id` = 1 - ") + sql = Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + DELETE + FROM `users` + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + DELETE + FROM "users" + WHERE "users"."id" = 1 + }) + end end it "manufactures sql deleting a ranged relation" do - Deletion.new(@relation.take(1)).to_sql.should be_like(" - DELETE - FROM `users` - LIMIT 1 - ") + sql = Deletion.new(@relation.take(1)).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + DELETE + FROM `users` + LIMIT 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + DELETE + FROM "users" + LIMIT 1 + }) + end end end diff --git a/spec/arel/unit/relations/group_spec.rb b/spec/arel/unit/relations/group_spec.rb index a0147b9416..658c0ad406 100644 --- a/spec/arel/unit/relations/group_spec.rb +++ b/spec/arel/unit/relations/group_spec.rb @@ -6,25 +6,49 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - Group.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY `users`.`id` - ") + sql = Group.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + GROUP BY "users"."id" + }) + end end end - + describe 'when given a string' do it "passes the string through to the where clause" do - Group.new(@relation, 'asdf').to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY asdf - ") + sql = Group.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + GROUP BY asdf + }) + end end end end diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb index 441c97b290..2fd07dd96c 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -8,24 +8,35 @@ module Arel describe '#to_sql' do it 'manufactures sql inserting data when given multiple rows' do - pending 'it should insert multiple rows' - @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) + pending 'it should insert multiple rows' do + @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`name`) VALUES ('nick'), ('bryan') - ") + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`name`) VALUES ('nick'), ('bryan') + ") + end end it 'manufactures sql inserting data when given multiple values' do @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`id`, `name`) VALUES (1, 'nick') - ") + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`id`, `name`) VALUES (1, 'nick') + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id", "name") VALUES (1, 'nick') + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -34,11 +45,21 @@ module Arel end it 'manufactures sql inserting data' do - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`name`) VALUES ('nick') - ") + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`name`) VALUES ('nick') + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("name") VALUES ('nick') + }) + end end end @@ -48,11 +69,21 @@ module Arel end it 'manufactures sql inserting data' do - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`id`) VALUES (1) - ") + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`id`) VALUES (1) + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id") VALUES (1) + }) + end end end end diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index 1698bf9647..fa6bbbe216 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -7,20 +7,20 @@ module Arel @relation2 = Table.new(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - + describe 'hashing' do it 'implements hash equality' do Join.new("INNER JOIN", @relation1, @relation2, @predicate) \ .should hash_the_same_as(Join.new("INNER JOIN", @relation1, @relation2, @predicate)) end end - + describe '#engine' do it "delegates to a relation's engine" do Join.new("INNER JOIN", @relation1, @relation2, @predicate).engine.should == @relation1.engine end end - + describe '#attributes' do it 'combines the attributes of the two relations' do join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) @@ -32,21 +32,45 @@ module Arel describe '#to_sql' do describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` - ") + sql = Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" ON "users"."id" = "photos"."user_id" + }) + end end end - + describe 'when joining with a string' do it "passes the string through to the where clause" do - Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - INNER JOIN asdf ON fdsa - ") + sql = Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + INNER JOIN asdf ON fdsa + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + INNER JOIN asdf ON fdsa + }) + end end end end diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb index d373a8ba12..31014ddd39 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -10,57 +10,104 @@ module Arel describe '#to_sql' do describe "when given an attribute" do it "manufactures sql with an order clause populated by the attribute" do - Order.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` - ") + sql = Order.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."id" + }) + end end end - + describe "when given multiple attributes" do before do @another_attribute = @relation[:name] end - + it "manufactures sql with an order clause populated by comma-separated attributes" do - Order.new(@relation, @attribute, @another_attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id`, `users`.`name` - ") + sql = Order.new(@relation, @attribute, @another_attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id`, `users`.`name` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."id", "users"."name" + }) + end end end - + describe "when given a string" do before do @string = "asdf" end - + it "passes the string through to the order clause" do - Order.new(@relation, @string).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY asdf - ") + sql = Order.new(@relation, @string).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY asdf + }) + end end end - + describe "when ordering an ordered relation" do before do @ordered_relation = Order.new(@relation, @attribute) @another_attribute = @relation[:name] end - + it "manufactures sql with the order clause of the last ordering preceding the first ordering" do - Order.new(@ordered_relation, @another_attribute).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`name`, `users`.`id` - ") + sql = Order.new(@ordered_relation, @another_attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`name`, `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."name", "users"."id" + }) + end end end end end end - \ No newline at end of file diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/unit/relations/project_spec.rb index f389b18c54..d2d1fb3873 100644 --- a/spec/arel/unit/relations/project_spec.rb +++ b/spec/arel/unit/relations/project_spec.rb @@ -20,10 +20,21 @@ module Arel describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do - Project.new(@relation, @attribute).to_sql.should be_like(" - SELECT `users`.`id` - FROM `users` - ") + sql = Project.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id" + FROM "users" + }) + end end end @@ -33,33 +44,75 @@ module Arel end it "manufactures sql with scalar selects" do - Project.new(@relation, @scalar_relation).to_sql.should be_like(" - SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` - ") + sql = Project.new(@relation, @scalar_relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users" + }) + end end end describe 'when given a string' do it "passes the string through to the select clause" do - Project.new(@relation, 'asdf').to_sql.should be_like(" - SELECT asdf FROM `users` - ") + sql = Project.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT asdf FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT asdf FROM "users" + }) + end end end describe 'when given an expression' do it 'manufactures sql with expressions' do - @relation.project(@attribute.count).to_sql.should be_like(" - SELECT COUNT(`users`.`id`) AS count_id - FROM `users` - ") + sql = @relation.project(@attribute.count).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(`users`.`id`) AS count_id + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT COUNT("users"."id") AS count_id + FROM "users" + }) + end end it 'manufactures sql with distinct expressions' do - @relation.project(@attribute.count(true)).to_sql.should be_like(" - SELECT COUNT(DISTINCT `users`.`id`) AS count_id - FROM `users` - ") + sql = @relation.project(@attribute.count(true)).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT `users`.`id`) AS count_id + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT "users"."id") AS count_id + FROM "users" + }) + end end end end diff --git a/spec/arel/unit/relations/skip_spec.rb b/spec/arel/unit/relations/skip_spec.rb index d83c969aa8..0653d795b1 100644 --- a/spec/arel/unit/relations/skip_spec.rb +++ b/spec/arel/unit/relations/skip_spec.rb @@ -9,11 +9,23 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - Skip.new(@relation, @skipped).to_s.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - OFFSET #{@skipped} - ") + sql = Skip.new(@relation, @skipped).to_s + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + OFFSET 4 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + OFFSET 4 + }) + end end end end diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index 54520bf3b6..08486c7b6c 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do @@ -18,39 +18,50 @@ module Arel it "returns the attribute if the attribute is within the relation" do @relation[@relation[:id]].should == @relation[:id] end - + it "returns nil if the attribtue is not within the relation" do another_relation = Table.new(:photos) @relation[another_relation[:id]].should be_nil end end - + describe 'when given an', Expression do before do @expression = @relation[:id].count end - + it "returns the Expression if the Expression is within the relation" do @relation[@expression].should be_nil end end end - + describe '#to_sql' do it "manufactures a simple select query" do - @relation.to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - ") + sql = @relation.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + }) + end end end - + describe '#column_for' do it "returns the column corresponding to the attribute" do @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } end end - + describe '#attributes' do it 'manufactures attributes corresponding to columns in the table' do @relation.attributes.should == [ @@ -58,7 +69,7 @@ module Arel Attribute.new(@relation, :name) ] end - + describe '#reset' do it "reloads columns from the database" do lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } @@ -66,20 +77,20 @@ module Arel end end end - + describe 'hashing' do it "implements hash equality" do Table.new(:users).should hash_the_same_as(Table.new(:users)) Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) end end - + describe '#engine' do it "defaults to global engine" do Table.engine = engine = Engine.new Table.new(:users).engine.should == engine end - + it "can be specified" do Table.new(:users, engine = Engine.new).engine.should == engine end diff --git a/spec/arel/unit/relations/take_spec.rb b/spec/arel/unit/relations/take_spec.rb index dca7806057..911b84e01e 100644 --- a/spec/arel/unit/relations/take_spec.rb +++ b/spec/arel/unit/relations/take_spec.rb @@ -9,11 +9,23 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - Take.new(@relation, @taken).to_s.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - LIMIT #{@taken} - ") + sql = Take.new(@relation, @taken).to_s + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + LIMIT 4 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + LIMIT 4 + }) + end end end end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index b67369251f..0bbc9113c6 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -8,18 +8,41 @@ module Arel describe '#to_sql' do it "manufactures sql updating attributes when given multiple attributes" do - Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql.should be_like(" - UPDATE `users` - SET `id` = 1, `name` = 'nick' - ") + sql = Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + UPDATE `users` + SET `id` = 1, `name` = 'nick' + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1, "name" = 'nick' + }) + end end it "manufactures sql updating attributes when given a ranged relation" do - Update.new(@relation.take(1), @relation[:name] => "nick").to_sql.should be_like(" - UPDATE `users` - SET `name` = 'nick' - LIMIT 1 - ") + sql = Update.new(@relation.take(1), @relation[:name] => "nick").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + LIMIT 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + LIMIT 1 + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -28,10 +51,19 @@ module Arel end it 'manufactures sql updating attributes' do - @update.to_sql.should be_like(" - UPDATE `users` - SET `name` = 'nick' - ") + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + }) + end end end @@ -41,10 +73,19 @@ module Arel end it 'manufactures sql updating attributes' do - @update.to_sql.should be_like(" - UPDATE `users` - SET `id` = 1 - ") + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `id` = 1 + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1 + }) + end end end @@ -57,11 +98,21 @@ module Arel end it 'manufactures sql updating a where relation' do - @update.to_sql.should be_like(" - UPDATE `users` - SET `name` = 'nick' - WHERE `users`.`id` = 1 - ") + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + WHERE "users"."id" = 1 + }) + end end end end diff --git a/spec/arel/unit/relations/where_spec.rb b/spec/arel/unit/relations/where_spec.rb index 8ef4d54b63..64f97c8135 100644 --- a/spec/arel/unit/relations/where_spec.rb +++ b/spec/arel/unit/relations/where_spec.rb @@ -18,21 +18,45 @@ module Arel describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do - Where.new(@relation, @predicate).to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE `users`.`id` = 1 - ") + sql = Where.new(@relation, @predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + WHERE "users"."id" = 1 + }) + end end end describe 'when given a string' do it "passes the string through to the where clause" do - Where.new(@relation, 'asdf').to_sql.should be_like(" - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE asdf - ") + sql = Where.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + WHERE asdf + }) + end end end end diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb new file mode 100644 index 0000000000..789628b95d --- /dev/null +++ b/spec/connections/mysql_connection.rb @@ -0,0 +1,13 @@ +require "activerecord" +puts "Using native MySQL" + +ActiveRecord::Base.configurations = { + 'unit' => { + :adapter => 'mysql', + :username => 'rails', + :encoding => 'utf8', + :database => 'arel_unit', + } +} + +ActiveRecord::Base.establish_connection 'unit' \ No newline at end of file diff --git a/spec/connections/sqlite3_connection.rb b/spec/connections/sqlite3_connection.rb new file mode 100644 index 0000000000..bae077711d --- /dev/null +++ b/spec/connections/sqlite3_connection.rb @@ -0,0 +1,22 @@ +require "activerecord" +puts "Using native SQLite3" + +db_file = "spec/fixtures/fixture_database.sqlite3" + +ActiveRecord::Base.configurations = { + "unit" => { + :adapter => 'sqlite3', + :database => db_file, + :timeout => 5000 + } +} + +unless File.exist?(db_file) + puts "SQLite3 database not found at #{db_file}. Rebuilding it." + FileUtils.mkdir_p(File.dirname(db_file)) + sqlite_command = %Q{sqlite3 "#{db_file}" "create table a (a integer); drop table a;"} + puts "Executing '#{sqlite_command}'" + raise "Seems that there is no sqlite3 executable available" unless system(sqlite_command) +end + +ActiveRecord::Base.establish_connection("unit") diff --git a/spec/doubles/database.rb b/spec/doubles/database.rb deleted file mode 100644 index f8a4b38e17..0000000000 --- a/spec/doubles/database.rb +++ /dev/null @@ -1,51 +0,0 @@ -module Fake - class Engine - def connection - @conn ||= Connection.new - end - end - - class Connection - include ActiveRecord::ConnectionAdapters::Quoting - - def columns(table_name, comment) - { "users" => - [ - Column.new("id", :integer), - Column.new("name", :string) - ], - "photos" => - [ - Column.new("id", :integer), - Column.new("user_id", :integer), - Column.new("camera_id", :integer) - ] - }[table_name] - end - - def execute(*args) - [] - end - - def quote_column_name(column_name) - "`#{column_name}`" - end - - def quote_table_name(table_name) - "`#{table_name}`" - end - - def supports_count_distinct? - true - end - end - - class Column - attr_reader :name, :type - - def initialize(name, type) - @name = name - @type = type - end - end -end diff --git a/spec/schemas/mysql_schema.rb b/spec/schemas/mysql_schema.rb new file mode 100644 index 0000000000..1123f4582e --- /dev/null +++ b/spec/schemas/mysql_schema.rb @@ -0,0 +1,18 @@ +sql = <<-SQL + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL + ); + + DROP TABLE IF EXISTS photos; + CREATE TABLE photos ( + id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, + user_id INTEGER NOT NULL, + camera_id INTEGER NOT NULL + ); +SQL + +sql.split(/;/).select(&:present?).each do |sql_statement| + ActiveRecord::Base.connection.execute sql_statement +end \ No newline at end of file diff --git a/spec/schemas/sqlite3_schema.rb b/spec/schemas/sqlite3_schema.rb new file mode 100644 index 0000000000..6c98a4f934 --- /dev/null +++ b/spec/schemas/sqlite3_schema.rb @@ -0,0 +1,18 @@ +sql = <<-SQL + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id INTEGER NOT NULL PRIMARY KEY, + name VARCHAR(255) NOT NULL + ); + + DROP TABLE IF EXISTS photos; + CREATE TABLE photos ( + id INTEGER NOT NULL PRIMARY KEY, + user_id INTEGER NOT NULL, + camera_id INTEGER NOT NULL + ); +SQL + +sql.split(/;/).select(&:present?).each do |sql_statement| + ActiveRecord::Base.connection.execute sql_statement +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce539b6ffa..8d515d66f1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -11,10 +11,25 @@ require 'arel' Dir["#{dir}/#{helper}/*"].each { |m| require "#{dir}/#{helper}/#{File.basename(m)}" } end +module AdapterGuards + def adapter_is(name) + yield if name.to_s == adapter_name + end + + def adapter_is_not(name) + yield if name.to_s != adapter_name + end + + def adapter_name + Arel::Table.engine.connection.class.name.underscore.split("/").last.gsub(/_adapter/, '') + end +end + Spec::Runner.configure do |config| - config.include(BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher) + config.include BeLikeMatcher, HashTheSameAsMatcher, DisambiguateAttributesMatcher + config.include AdapterGuards config.mock_with :rr config.before do - Arel::Table.engine = Arel::Engine.new(Fake::Engine.new) + Arel::Table.engine = Arel::Engine.new(ActiveRecord::Base) end end -- cgit v1.2.3 From 2bbf8ca9d2af3ea959a21c3729b4894bc31f088b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 13:58:29 -0400 Subject: reorganized call Conflicts: doc/TODO lib/arel/relations/relation.rb lib/arel/relations/writes/delete.rb lib/arel/relations/writes/insert.rb lib/arel/relations/writes/update.rb lib/arel/session.rb spec/arel/unit/relations/delete_spec.rb spec/arel/unit/relations/insert_spec.rb spec/arel/unit/relations/relation_spec.rb spec/arel/unit/relations/update_spec.rb spec/arel/unit/session/session_spec.rb --- doc/TODO | 16 +++++++--------- lib/arel/engine.rb | 24 ++++++++++++++++++++++++ lib/arel/relations.rb | 4 +--- lib/arel/relations/array.rb | 19 +++++++++++++++++++ lib/arel/relations/relation.rb | 9 ++------- lib/arel/relations/writes/delete.rb | 4 ++-- lib/arel/relations/writes/insert.rb | 4 ++-- lib/arel/relations/writes/update.rb | 4 ++-- lib/arel/session.rb | 8 ++++---- spec/arel/unit/relations/array_spec.rb | 27 +++++++++++++++++++++++++++ spec/arel/unit/relations/delete_spec.rb | 8 -------- spec/arel/unit/relations/insert_spec.rb | 11 ----------- spec/arel/unit/relations/relation_spec.rb | 7 ------- spec/arel/unit/relations/update_spec.rb | 11 ----------- spec/arel/unit/session/session_spec.rb | 10 +++++----- 15 files changed, 95 insertions(+), 71 deletions(-) create mode 100644 lib/arel/relations/array.rb create mode 100644 spec/arel/unit/relations/array_spec.rb diff --git a/doc/TODO b/doc/TODO index 740e5db5fe..ad12640881 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,19 +1,16 @@ todo: -- joining with LIMIT is like aggregations!! +- refactor adapter pattern +- implement in memory adapter +- implement mnesia adapter +- joins become subselects in writes: users.delete().where( addresses.c.user_id== select([users.c.id]). where(users.c.name=='jack') ) - - SELECT id, name, - (select count(*) FROM addresses WHERE - user_id=users.id) - FROM users - - SELECT users.*, (SELECT count(id) FROM addresses WHERE - addresses.user_id=users.id) FROM users +- rename externalize to derived. +- and/or w/ predicates - blocks for all operations - result sets to attr correlation too - cache expiry on write @@ -85,6 +82,7 @@ done: - test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class. - rename select to where - rename all ion classes +- joining with LIMIT is like aggregations!! icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/engine.rb b/lib/arel/engine.rb index 5a5ef06878..2bb4bbbd90 100644 --- a/lib/arel/engine.rb +++ b/lib/arel/engine.rb @@ -14,5 +14,29 @@ module Arel def method_missing(method, *args, &block) @ar.connection.send(method, *args, &block) end + + module CRUD + def create(relation) + connection.insert(relation.to_sql) + end + + def read(relation) + results = connection.execute(relation.to_sql) + rows = [] + results.each do |row| + rows << attributes.zip(row).to_hash + end + rows + end + + def update(relation) + connection.update(relation.to_sql) + end + + def delete(relation) + connection.delete(relation.to_sql) + end + end + include CRUD end end diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index 3394fac7cb..fd758ed15d 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -1,8 +1,6 @@ require 'arel/relations/relation' - require 'arel/relations/utilities' - require 'arel/relations/table' - +require 'arel/relations/array' require 'arel/relations/writes' require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/array.rb b/lib/arel/relations/array.rb new file mode 100644 index 0000000000..dac65abbc2 --- /dev/null +++ b/lib/arel/relations/array.rb @@ -0,0 +1,19 @@ +module Arel + class Array < Relation + include Recursion::BaseCase + + def initialize(array, attribute_names) + @array, @attribute_names = array, attribute_names + end + + def attributes + @attributes ||= @attribute_names.collect do |name| + Attribute.new(self, name.to_sym) + end + end + + def call(connection = nil) + @array.collect { |row| attributes.zip(row).to_hash } + end + end +end \ No newline at end of file diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index 5d2c336a15..ef295dfdd7 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -32,13 +32,8 @@ module Arel "IN" end - def call(connection = engine) - results = connection.execute(to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash - end - rows + def call + engine.read(self) end def bind(relation) diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index b1ff3bef27..0a04454e7f 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -12,8 +12,8 @@ module Arel ].compact.join("\n") end - def call(connection = engine) - connection.delete(to_sql) + def call + engine.delete(self) end end end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb index d579ad06d0..d05bd9cdc8 100644 --- a/lib/arel/relations/writes/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -16,8 +16,8 @@ module Arel ].join("\n") end - def call(connection = engine) - connection.insert(to_sql) + def call + engine.create(self) end end end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index 2e90de3a52..fd0aadb479 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -18,8 +18,8 @@ module Arel ].join("\n") end - def call(connection = engine) - connection.update(to_sql) + def call + engine.update(self) end end end diff --git a/lib/arel/session.rb b/lib/arel/session.rb index d9a6e4b5e4..9c2ddc535b 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -25,21 +25,21 @@ module Arel module CRUD def create(insert) - insert.call(insert.engine) + insert.call end def read(select) (@read ||= Hash.new do |hash, select| - hash[select] = select.call(select.engine) + hash[select] = select.call end)[select] end def update(update) - update.call(update.engine) + update.call end def delete(delete) - delete.call(delete.engine) + delete.call end end include CRUD diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb new file mode 100644 index 0000000000..1330f0f205 --- /dev/null +++ b/spec/arel/unit/relations/array_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') + +module Arel + describe Array do + before do + @relation = Array.new([[1], [2], [3]], [:id]) + end + + describe '#attributes' do + it 'manufactures attributes corresponding to the names given on construction' do + @relation.attributes.should == [ + Attribute.new(@relation, :id) + ] + end + end + + describe '#call' do + it "manufactures an array of hashes of attributes to values" do + @relation.call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 }, + { @relation[:id] => 3 } + ] + end + end + end +end \ No newline at end of file diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/unit/relations/delete_spec.rb index 3798178ccc..23aca563f7 100644 --- a/spec/arel/unit/relations/delete_spec.rb +++ b/spec/arel/unit/relations/delete_spec.rb @@ -59,13 +59,5 @@ module Arel end end end - - describe '#call' do - it 'executes a delete on the connection' do - deletion = Deletion.new(@relation) - mock(connection = Object.new).delete(deletion.to_sql) - deletion.call(connection) - end - end end end diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb index 2fd07dd96c..5ab3ef1299 100644 --- a/spec/arel/unit/relations/insert_spec.rb +++ b/spec/arel/unit/relations/insert_spec.rb @@ -87,16 +87,5 @@ module Arel end end end - - describe '#call' do - before do - @insertion = Insert.new(@relation, @relation[:name] => "nick") - end - - it 'executes an insert on the connection' do - mock(connection = Object.new).insert(@insertion.to_sql) - @insertion.call(connection) - end - end end end diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index a3bfa67353..7df10be59c 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -165,12 +165,5 @@ module Arel @relation.first.should == @relation.session.read(@relation).first end end - - describe '#call' do - it 'executes a select_all on the connection' do - mock(connection = Object.new).execute(@relation.to_sql) { [] } - @relation.call(connection) - end - end end end diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb index 0bbc9113c6..e0d7ddd295 100644 --- a/spec/arel/unit/relations/update_spec.rb +++ b/spec/arel/unit/relations/update_spec.rb @@ -117,16 +117,5 @@ module Arel end end - describe '#call' do - before do - @update = Update.new(@relation, @relation[:name] => "nick") - end - - it 'executes an update on the connection' do - mock(connection = Object.new).update(@update.to_sql) - @update.call(connection) - end - end - end end diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb index 6e73d74f2d..c30ba6195f 100644 --- a/spec/arel/unit/session/session_spec.rb +++ b/spec/arel/unit/session/session_spec.rb @@ -40,19 +40,19 @@ module Arel describe '#create' do it "executes an insertion on the connection" do - mock(@insert).call(@insert.engine) + mock(@insert).call @session.create(@insert) end end describe '#read' do it "executes an selection on the connection" do - mock(@read).call(@read.engine) + mock(@read).call @session.read(@read) end it "is memoized" do - mock(@read).call(@read.engine).once + mock(@read).call.once @session.read(@read) @session.read(@read) end @@ -60,14 +60,14 @@ module Arel describe '#update' do it "executes an update on the connection" do - mock(@update).call(@update.engine) + mock(@update).call @session.update(@update) end end describe '#delete' do it "executes a delete on the connection" do - mock(@delete).call(@delete.engine) + mock(@delete).call @session.delete(@delete) end end -- cgit v1.2.3 From bdca9ed42ffea10aa6989ea3ecebedb424fa01ed Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:20:29 -0400 Subject: moved sql related code to its own engine area Conflicts: lib/arel/engine.rb lib/arel/extensions/object.rb lib/arel/predicates.rb lib/arel/primitives/attribute.rb lib/arel/primitives/expression.rb lib/arel/primitives/value.rb lib/arel/relations/operations/join.rb lib/arel/relations/relation.rb lib/arel/relations/utilities/externalization.rb lib/arel/relations/utilities/nil.rb lib/arel/relations/writes/delete.rb lib/arel/relations/writes/insert.rb lib/arel/relations/writes/update.rb spec/arel/unit/relations/skip_spec.rb spec/arel/unit/relations/take_spec.rb spec/spec_helper.rb --- doc/TODO | 2 +- lib/arel.rb | 3 +- lib/arel/engine.rb | 42 ------- lib/arel/engines.rb | 2 + lib/arel/engines/array/array.rb | 1 + lib/arel/engines/array/relations/array.rb | 19 ++++ lib/arel/engines/sql/christener.rb | 13 +++ lib/arel/engines/sql/engine.rb | 41 +++++++ lib/arel/engines/sql/extensions.rb | 4 + lib/arel/engines/sql/extensions/array.rb | 9 ++ lib/arel/engines/sql/extensions/nil_class.rb | 5 + lib/arel/engines/sql/extensions/object.rb | 9 ++ lib/arel/engines/sql/extensions/range.rb | 9 ++ lib/arel/engines/sql/formatters.rb | 121 +++++++++++++++++++++ lib/arel/engines/sql/predicates.rb | 37 +++++++ lib/arel/engines/sql/primitives.rb | 3 + lib/arel/engines/sql/primitives/attribute.rb | 17 +++ lib/arel/engines/sql/primitives/expression.rb | 7 ++ lib/arel/engines/sql/primitives/value.rb | 11 ++ lib/arel/engines/sql/relations.rb | 5 + lib/arel/engines/sql/relations/operations.rb | 2 + lib/arel/engines/sql/relations/operations/alias.rb | 5 + lib/arel/engines/sql/relations/operations/join.rb | 19 ++++ lib/arel/engines/sql/relations/relation.rb | 28 +++++ lib/arel/engines/sql/relations/table.rb | 36 ++++++ lib/arel/engines/sql/relations/utilities.rb | 3 + .../sql/relations/utilities/externalization.rb | 14 +++ lib/arel/engines/sql/relations/utilities/nil.rb | 6 + .../engines/sql/relations/utilities/recursion.rb | 13 +++ lib/arel/engines/sql/relations/writes.rb | 3 + lib/arel/engines/sql/relations/writes/delete.rb | 12 ++ lib/arel/engines/sql/relations/writes/insert.rb | 12 ++ lib/arel/engines/sql/relations/writes/update.rb | 14 +++ lib/arel/engines/sql/sql.rb | 7 ++ lib/arel/extensions.rb | 2 - lib/arel/extensions/array.rb | 8 -- lib/arel/extensions/nil_class.rb | 5 - lib/arel/extensions/object.rb | 8 -- lib/arel/extensions/range.rb | 9 -- lib/arel/predicates.rb | 15 --- lib/arel/primitives/attribute.rb | 12 -- lib/arel/primitives/expression.rb | 4 - lib/arel/primitives/value.rb | 13 --- lib/arel/relations.rb | 2 - lib/arel/relations/array.rb | 19 ---- lib/arel/relations/operations/alias.rb | 1 - lib/arel/relations/operations/join.rb | 16 --- lib/arel/relations/relation.rb | 32 +----- lib/arel/relations/table.rb | 36 ------ lib/arel/relations/utilities.rb | 2 - lib/arel/relations/utilities/externalization.rb | 10 -- lib/arel/relations/utilities/nil.rb | 3 - lib/arel/relations/utilities/recursion.rb | 13 --- lib/arel/relations/writes/delete.rb | 9 -- lib/arel/relations/writes/insert.rb | 9 -- lib/arel/relations/writes/update.rb | 11 -- lib/arel/sql.rb | 2 - lib/arel/sql/christener.rb | 13 --- lib/arel/sql/formatters.rb | 121 --------------------- spec/arel/unit/relations/skip_spec.rb | 2 +- spec/arel/unit/relations/table_spec.rb | 4 +- spec/arel/unit/relations/take_spec.rb | 2 +- spec/spec_helper.rb | 2 +- 63 files changed, 495 insertions(+), 424 deletions(-) delete mode 100644 lib/arel/engine.rb create mode 100644 lib/arel/engines.rb create mode 100644 lib/arel/engines/array/array.rb create mode 100644 lib/arel/engines/array/relations/array.rb create mode 100644 lib/arel/engines/sql/christener.rb create mode 100644 lib/arel/engines/sql/engine.rb create mode 100644 lib/arel/engines/sql/extensions.rb create mode 100644 lib/arel/engines/sql/extensions/array.rb create mode 100644 lib/arel/engines/sql/extensions/nil_class.rb create mode 100644 lib/arel/engines/sql/extensions/object.rb create mode 100644 lib/arel/engines/sql/extensions/range.rb create mode 100644 lib/arel/engines/sql/formatters.rb create mode 100644 lib/arel/engines/sql/predicates.rb create mode 100644 lib/arel/engines/sql/primitives.rb create mode 100644 lib/arel/engines/sql/primitives/attribute.rb create mode 100644 lib/arel/engines/sql/primitives/expression.rb create mode 100644 lib/arel/engines/sql/primitives/value.rb create mode 100644 lib/arel/engines/sql/relations.rb create mode 100644 lib/arel/engines/sql/relations/operations.rb create mode 100644 lib/arel/engines/sql/relations/operations/alias.rb create mode 100644 lib/arel/engines/sql/relations/operations/join.rb create mode 100644 lib/arel/engines/sql/relations/relation.rb create mode 100644 lib/arel/engines/sql/relations/table.rb create mode 100644 lib/arel/engines/sql/relations/utilities.rb create mode 100644 lib/arel/engines/sql/relations/utilities/externalization.rb create mode 100644 lib/arel/engines/sql/relations/utilities/nil.rb create mode 100644 lib/arel/engines/sql/relations/utilities/recursion.rb create mode 100644 lib/arel/engines/sql/relations/writes.rb create mode 100644 lib/arel/engines/sql/relations/writes/delete.rb create mode 100644 lib/arel/engines/sql/relations/writes/insert.rb create mode 100644 lib/arel/engines/sql/relations/writes/update.rb create mode 100644 lib/arel/engines/sql/sql.rb delete mode 100644 lib/arel/extensions/nil_class.rb delete mode 100644 lib/arel/extensions/range.rb delete mode 100644 lib/arel/relations/array.rb delete mode 100644 lib/arel/relations/table.rb delete mode 100644 lib/arel/relations/utilities/recursion.rb delete mode 100644 lib/arel/sql.rb delete mode 100644 lib/arel/sql/christener.rb delete mode 100644 lib/arel/sql/formatters.rb diff --git a/doc/TODO b/doc/TODO index ad12640881..8a8dcf5380 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,5 +1,5 @@ todo: - +- expressions should be class-based, and joins too, anything _sql should be renamed - refactor adapter pattern - implement in memory adapter - implement mnesia adapter diff --git a/lib/arel.rb b/lib/arel.rb index 00bfa1e292..f22287fcc5 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -7,9 +7,8 @@ require 'active_record/connection_adapters/abstract/quoting' require 'arel/arel' require 'arel/extensions' -require 'arel/sql' require 'arel/predicates' require 'arel/relations' -require 'arel/engine' +require 'arel/engines' require 'arel/session' require 'arel/primitives' diff --git a/lib/arel/engine.rb b/lib/arel/engine.rb deleted file mode 100644 index 2bb4bbbd90..0000000000 --- a/lib/arel/engine.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Arel - # this file is currently just a hack to adapt between activerecord::base which holds the connection specification - # and active relation. ultimately, this file should be in effect what the connection specification is in active record; - # that is: a spec of the database (url, password, etc.), a quoting adapter layer, and a connection pool. - class Engine - def initialize(ar = nil) - @ar = ar - end - - def connection - @ar.connection - end - - def method_missing(method, *args, &block) - @ar.connection.send(method, *args, &block) - end - - module CRUD - def create(relation) - connection.insert(relation.to_sql) - end - - def read(relation) - results = connection.execute(relation.to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash - end - rows - end - - def update(relation) - connection.update(relation.to_sql) - end - - def delete(relation) - connection.delete(relation.to_sql) - end - end - include CRUD - end -end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb new file mode 100644 index 0000000000..63a929528f --- /dev/null +++ b/lib/arel/engines.rb @@ -0,0 +1,2 @@ +require 'arel/engines/sql/sql' +require 'arel/engines/array/array' \ No newline at end of file diff --git a/lib/arel/engines/array/array.rb b/lib/arel/engines/array/array.rb new file mode 100644 index 0000000000..3a3a47308a --- /dev/null +++ b/lib/arel/engines/array/array.rb @@ -0,0 +1 @@ +require 'arel/engines/array/relations/array' \ No newline at end of file diff --git a/lib/arel/engines/array/relations/array.rb b/lib/arel/engines/array/relations/array.rb new file mode 100644 index 0000000000..dac65abbc2 --- /dev/null +++ b/lib/arel/engines/array/relations/array.rb @@ -0,0 +1,19 @@ +module Arel + class Array < Relation + include Recursion::BaseCase + + def initialize(array, attribute_names) + @array, @attribute_names = array, attribute_names + end + + def attributes + @attributes ||= @attribute_names.collect do |name| + Attribute.new(self, name.to_sym) + end + end + + def call(connection = nil) + @array.collect { |row| attributes.zip(row).to_hash } + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb new file mode 100644 index 0000000000..5883a75f41 --- /dev/null +++ b/lib/arel/engines/sql/christener.rb @@ -0,0 +1,13 @@ +module Arel + module Sql + class Christener + def name_for(relation) + @used_names ||= Hash.new(0) + (@relation_names ||= Hash.new do |hash, relation| + @used_names[name = relation.name] += 1 + hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') + end)[relation.table] + end + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb new file mode 100644 index 0000000000..e5d1a8b0ca --- /dev/null +++ b/lib/arel/engines/sql/engine.rb @@ -0,0 +1,41 @@ +module Arel + module Sql + class Engine + def initialize(ar = nil) + @ar = ar + end + + def connection + @ar.connection + end + + def method_missing(method, *args, &block) + @ar.connection.send(method, *args, &block) + end + + module CRUD + def create(relation) + connection.insert(relation.to_sql) + end + + def read(relation) + results = connection.execute(relation.to_sql) + rows = [] + results.each do |row| + rows << attributes.zip(row).to_hash + end + rows + end + + def update(relation) + connection.update(relation.to_sql) + end + + def delete(relation) + connection.delete(relation.to_sql) + end + end + include CRUD + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions.rb b/lib/arel/engines/sql/extensions.rb new file mode 100644 index 0000000000..6f4ad32148 --- /dev/null +++ b/lib/arel/engines/sql/extensions.rb @@ -0,0 +1,4 @@ +require 'arel/engines/sql/extensions/object' +require 'arel/engines/sql/extensions/array' +require 'arel/engines/sql/extensions/range' +require 'arel/engines/sql/extensions/nil_class' \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb new file mode 100644 index 0000000000..1daa5abca7 --- /dev/null +++ b/lib/arel/engines/sql/extensions/array.rb @@ -0,0 +1,9 @@ +class Array + def to_sql(formatter = nil) + "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" + end + + def inclusion_predicate_sql + "IN" + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb new file mode 100644 index 0000000000..729c4cada7 --- /dev/null +++ b/lib/arel/engines/sql/extensions/nil_class.rb @@ -0,0 +1,5 @@ +class NilClass + def equality_predicate_sql + 'IS' + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb new file mode 100644 index 0000000000..ef990eee2f --- /dev/null +++ b/lib/arel/engines/sql/extensions/object.rb @@ -0,0 +1,9 @@ +class Object + def to_sql(formatter) + formatter.scalar self + end + + def equality_predicate_sql + '=' + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb new file mode 100644 index 0000000000..d7329efe34 --- /dev/null +++ b/lib/arel/engines/sql/extensions/range.rb @@ -0,0 +1,9 @@ +class Range + def to_sql(formatter = nil) + formatter.range self.begin, self.end + end + + def inclusion_predicate_sql + "BETWEEN" + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb new file mode 100644 index 0000000000..f82ddf631f --- /dev/null +++ b/lib/arel/engines/sql/formatters.rb @@ -0,0 +1,121 @@ +module Arel + module Sql + class Formatter + attr_reader :environment + delegate :christener, :engine, :to => :environment + delegate :name_for, :to => :christener + delegate :quote_table_name, :quote_column_name, :quote, :to => :engine + + def initialize(environment) + @environment = environment + end + end + + class SelectClause < Formatter + def attribute(attribute) + # FIXME this should check that the column exists + if attribute.name.to_s =~ /^\w*$/ + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") + else + attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") + end + end + + def expression(expression) + if expression.function_sql == "DISTINCT" + "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + else + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") + end + end + + def select(select_sql, table) + "(#{select_sql}) AS #{quote_table_name(name_for(table))}" + end + + def value(value) + value + end + end + + class PassThrough < Formatter + def value(value) + value + end + end + + class WhereClause < PassThrough + end + + class OrderClause < PassThrough + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + end + end + + class GroupClause < PassThrough + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + end + end + + class WhereCondition < Formatter + def attribute(attribute) + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + end + + def expression(expression) + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + end + + def value(value) + value.to_sql(self) + end + + def scalar(value, column = nil) + quote(value, column) + end + + def select(select_sql, table) + "(#{select_sql})" + end + end + + class SelectStatement < Formatter + def select(select_sql, table) + select_sql + end + end + + class TableReference < Formatter + def select(select_sql, table) + "(#{select_sql}) AS #{quote_table_name(name_for(table))}" + end + + def table(table) + if table.name =~ /^(\w|-)*$/ + quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') + else + table.name + (table.name != name_for(table) ? " AS " + (name_for(table)) : '') + end + end + end + + class Attribute < WhereCondition + def scalar(scalar) + quote(scalar, environment.column) + end + + def array(array) + "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" + end + + def range(left, right) + "#{left} AND #{right}" + end + end + + class Value < WhereCondition + end + end +end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb new file mode 100644 index 0000000000..dfeddb2de1 --- /dev/null +++ b/lib/arel/engines/sql/predicates.rb @@ -0,0 +1,37 @@ +module Arel + class Binary < Predicate + def to_sql(formatter = nil) + "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" + end + end + + class Equality < Binary + def predicate_sql + operand2.equality_predicate_sql + end + end + + class GreaterThanOrEqualTo < Binary + def predicate_sql; '>=' end + end + + class GreaterThan < Binary + def predicate_sql; '>' end + end + + class LessThanOrEqualTo < Binary + def predicate_sql; '<=' end + end + + class LessThan < Binary + def predicate_sql; '<' end + end + + class Match < Binary + def predicate_sql; 'LIKE' end + end + + class In < Binary + def predicate_sql; operand2.inclusion_predicate_sql end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb new file mode 100644 index 0000000000..405b1ca803 --- /dev/null +++ b/lib/arel/engines/sql/primitives.rb @@ -0,0 +1,3 @@ +require 'arel/engines/sql/primitives/attribute' +require 'arel/engines/sql/primitives/value' +require 'arel/engines/sql/primitives/expression' \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/attribute.rb b/lib/arel/engines/sql/primitives/attribute.rb new file mode 100644 index 0000000000..48de690b6f --- /dev/null +++ b/lib/arel/engines/sql/primitives/attribute.rb @@ -0,0 +1,17 @@ +require 'set' + +module Arel + class Attribute + def column + original_relation.column_for(self) + end + + def format(object) + object.to_sql(Sql::Attribute.new(self)) + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/expression.rb b/lib/arel/engines/sql/primitives/expression.rb new file mode 100644 index 0000000000..24f6879848 --- /dev/null +++ b/lib/arel/engines/sql/primitives/expression.rb @@ -0,0 +1,7 @@ +module Arel + class Expression < Attribute + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/value.rb b/lib/arel/engines/sql/primitives/value.rb new file mode 100644 index 0000000000..a44acc26e0 --- /dev/null +++ b/lib/arel/engines/sql/primitives/value.rb @@ -0,0 +1,11 @@ +module Arel + class Value + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.value value + end + + def format(object) + object.to_sql(Sql::Value.new(relation)) + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb new file mode 100644 index 0000000000..4de01b2691 --- /dev/null +++ b/lib/arel/engines/sql/relations.rb @@ -0,0 +1,5 @@ +require 'arel/engines/sql/relations/utilities' +require 'arel/engines/sql/relations/relation' +require 'arel/engines/sql/relations/operations' +require 'arel/engines/sql/relations/writes' +require 'arel/engines/sql/relations/table' \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/operations.rb b/lib/arel/engines/sql/relations/operations.rb new file mode 100644 index 0000000000..ff33fc6bc3 --- /dev/null +++ b/lib/arel/engines/sql/relations/operations.rb @@ -0,0 +1,2 @@ +require 'arel/engines/sql/relations/operations/alias' +require 'arel/engines/sql/relations/operations/join' diff --git a/lib/arel/engines/sql/relations/operations/alias.rb b/lib/arel/engines/sql/relations/operations/alias.rb new file mode 100644 index 0000000000..32c9911a69 --- /dev/null +++ b/lib/arel/engines/sql/relations/operations/alias.rb @@ -0,0 +1,5 @@ +module Arel + class Alias < Compound + include Recursion::BaseCase + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb new file mode 100644 index 0000000000..be21119bc9 --- /dev/null +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -0,0 +1,19 @@ +module Arel + class Join < Relation + def table_sql(formatter = Sql::TableReference.new(self)) + relation1.externalize.table_sql(formatter) + end + + def joins(environment, formatter = Sql::TableReference.new(environment)) + @joins ||= begin + this_join = [ + join_sql, + relation2.externalize.table_sql(formatter), + ("ON" unless predicates.blank?), + (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') + ].compact.join(" ") + [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") + end + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb new file mode 100644 index 0000000000..5fd4121176 --- /dev/null +++ b/lib/arel/engines/sql/relations/relation.rb @@ -0,0 +1,28 @@ +module Arel + class Relation + def to_sql(formatter = Sql::SelectStatement.new(self)) + formatter.select select_sql, self + end + + def select_sql + [ + "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "FROM #{table_sql(Sql::TableReference.new(self))}", + (joins(self) unless joins(self).blank? ), + ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), + ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), + ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) + ].compact.join("\n") + end + + def inclusion_predicate_sql + "IN" + end + + def christener + @christener ||= Sql::Christener.new + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb new file mode 100644 index 0000000000..0433abbbb2 --- /dev/null +++ b/lib/arel/engines/sql/relations/table.rb @@ -0,0 +1,36 @@ +module Arel + class Table < Relation + include Recursion::BaseCase + + cattr_accessor :engine + attr_reader :name, :engine + hash_on :name + + def initialize(name, engine = Table.engine) + @name, @engine = name.to_s, engine + end + + def attributes + @attributes ||= columns.collect do |column| + Attribute.new(self, column.name.to_sym) + end + end + + def column_for(attribute) + has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } + end + + def columns + @columns ||= engine.columns(name, "#{name} Columns") + end + + def reset + @attributes = @columns = nil + end + + def ==(other) + Table === other and + name == other.name + end + end +end diff --git a/lib/arel/engines/sql/relations/utilities.rb b/lib/arel/engines/sql/relations/utilities.rb new file mode 100644 index 0000000000..a1451ed448 --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities.rb @@ -0,0 +1,3 @@ +require 'arel/engines/sql/relations/utilities/recursion' +require 'arel/engines/sql/relations/utilities/externalization' +require 'arel/engines/sql/relations/utilities/nil' diff --git a/lib/arel/engines/sql/relations/utilities/externalization.rb b/lib/arel/engines/sql/relations/utilities/externalization.rb new file mode 100644 index 0000000000..1ac6f2de8e --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/externalization.rb @@ -0,0 +1,14 @@ +module Arel + class Externalization < Compound + include Recursion::BaseCase + + def table_sql(formatter = Sql::TableReference.new(relation)) + formatter.select relation.select_sql, self + end + + # REMOVEME + def name + relation.name + '_external' + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/utilities/nil.rb b/lib/arel/engines/sql/relations/utilities/nil.rb new file mode 100644 index 0000000000..77534b25ad --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/nil.rb @@ -0,0 +1,6 @@ +module Arel + class Nil < Relation + def table_sql(formatter = nil); '' end + def name; '' end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/utilities/recursion.rb b/lib/arel/engines/sql/relations/utilities/recursion.rb new file mode 100644 index 0000000000..848b059507 --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/recursion.rb @@ -0,0 +1,13 @@ +module Arel + module Recursion + module BaseCase + def table + self + end + + def table_sql(formatter = Sql::TableReference.new(self)) + formatter.table self + end + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb new file mode 100644 index 0000000000..dcadc326d9 --- /dev/null +++ b/lib/arel/engines/sql/relations/writes.rb @@ -0,0 +1,3 @@ +require 'arel/engines/sql/relations/writes/delete' +require 'arel/engines/sql/relations/writes/insert' +require 'arel/engines/sql/relations/writes/update' diff --git a/lib/arel/engines/sql/relations/writes/delete.rb b/lib/arel/engines/sql/relations/writes/delete.rb new file mode 100644 index 0000000000..b22ee51e24 --- /dev/null +++ b/lib/arel/engines/sql/relations/writes/delete.rb @@ -0,0 +1,12 @@ +module Arel + class Deletion < Compound + def to_sql(formatter = nil) + [ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ].compact.join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/insert.rb b/lib/arel/engines/sql/relations/writes/insert.rb new file mode 100644 index 0000000000..aac9c87a5b --- /dev/null +++ b/lib/arel/engines/sql/relations/writes/insert.rb @@ -0,0 +1,12 @@ +module Arel + class Insert < Compound + def to_sql(formatter = nil) + [ + "INSERT", + "INTO #{table_sql}", + "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", + "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + ].join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/update.rb b/lib/arel/engines/sql/relations/writes/update.rb new file mode 100644 index 0000000000..3e35a0d5cc --- /dev/null +++ b/lib/arel/engines/sql/relations/writes/update.rb @@ -0,0 +1,14 @@ +module Arel + class Update < Compound + def to_sql(formatter = nil) + [ + "UPDATE #{table_sql} SET", + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n"), + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) + ].join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/sql.rb b/lib/arel/engines/sql/sql.rb new file mode 100644 index 0000000000..aed1fd861e --- /dev/null +++ b/lib/arel/engines/sql/sql.rb @@ -0,0 +1,7 @@ +require 'arel/engines/sql/engine' +require 'arel/engines/sql/relations' +require 'arel/engines/sql/primitives' +require 'arel/engines/sql/predicates' +require 'arel/engines/sql/formatters' +require 'arel/engines/sql/extensions' +require 'arel/engines/sql/christener' \ No newline at end of file diff --git a/lib/arel/extensions.rb b/lib/arel/extensions.rb index 160cf36e5b..299ba0631c 100644 --- a/lib/arel/extensions.rb +++ b/lib/arel/extensions.rb @@ -2,5 +2,3 @@ require 'arel/extensions/object' require 'arel/extensions/class' require 'arel/extensions/array' require 'arel/extensions/hash' -require 'arel/extensions/range' -require 'arel/extensions/nil_class' \ No newline at end of file diff --git a/lib/arel/extensions/array.rb b/lib/arel/extensions/array.rb index 793c06aad8..5b6d6d6abd 100644 --- a/lib/arel/extensions/array.rb +++ b/lib/arel/extensions/array.rb @@ -2,12 +2,4 @@ class Array def to_hash Hash[*flatten] end - - def to_sql(formatter = nil) - "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" - end - - def inclusion_predicate_sql - "IN" - end end \ No newline at end of file diff --git a/lib/arel/extensions/nil_class.rb b/lib/arel/extensions/nil_class.rb deleted file mode 100644 index 729c4cada7..0000000000 --- a/lib/arel/extensions/nil_class.rb +++ /dev/null @@ -1,5 +0,0 @@ -class NilClass - def equality_predicate_sql - 'IS' - end -end \ No newline at end of file diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb index 14e2f82ce5..d626407dcb 100644 --- a/lib/arel/extensions/object.rb +++ b/lib/arel/extensions/object.rb @@ -7,14 +7,6 @@ class Object bind(relation) end - def to_sql(formatter) - formatter.scalar self - end - - def equality_predicate_sql - '=' - end - def metaclass class << self self diff --git a/lib/arel/extensions/range.rb b/lib/arel/extensions/range.rb deleted file mode 100644 index d7329efe34..0000000000 --- a/lib/arel/extensions/range.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Range - def to_sql(formatter = nil) - formatter.range self.begin, self.end - end - - def inclusion_predicate_sql - "BETWEEN" - end -end \ No newline at end of file diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb index b639022b4e..aa206d4e96 100644 --- a/lib/arel/predicates.rb +++ b/lib/arel/predicates.rb @@ -22,11 +22,6 @@ module Arel def bind(relation) self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) end - - def to_sql(formatter = nil) - "#{operand1.to_sql} #{predicate_sql} #{operand1.format(operand2)}" - end - alias_method :to_s, :to_sql end class CompoundPredicate < Binary @@ -49,33 +44,23 @@ module Arel ((operand1 == other.operand1 and operand2 == other.operand2) or (operand1 == other.operand2 and operand2 == other.operand1)) end - - def predicate_sql - operand2.equality_predicate_sql - end end class GreaterThanOrEqualTo < Binary - def predicate_sql; '>=' end end class GreaterThan < Binary - def predicate_sql; '>' end end class LessThanOrEqualTo < Binary - def predicate_sql; '<=' end end class LessThan < Binary - def predicate_sql; '<' end end class Match < Binary - def predicate_sql; 'LIKE' end end class In < Binary - def predicate_sql; operand2.inclusion_predicate_sql end end end diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb index 6cb558d8ce..5e216770e4 100644 --- a/lib/arel/primitives/attribute.rb +++ b/lib/arel/primitives/attribute.rb @@ -18,18 +18,6 @@ module Arel false end - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - module Transformations def self.included(klass) klass.send :alias_method, :eql?, :== diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb index 836f014745..b67a5e1f8e 100644 --- a/lib/arel/primitives/expression.rb +++ b/lib/arel/primitives/expression.rb @@ -9,10 +9,6 @@ module Arel @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor end - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - def aggregation? true end diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb index 9c6e518a95..91c4045507 100644 --- a/lib/arel/primitives/value.rb +++ b/lib/arel/primitives/value.rb @@ -4,19 +4,6 @@ module Arel deriving :initialize, :== delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - if value =~ /^\(.*\)$/ - value - else - formatter.value value - end - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - def bind(relation) Value.new(value, relation) end diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb index fd758ed15d..f97c35e56e 100644 --- a/lib/arel/relations.rb +++ b/lib/arel/relations.rb @@ -1,6 +1,4 @@ require 'arel/relations/relation' require 'arel/relations/utilities' -require 'arel/relations/table' -require 'arel/relations/array' require 'arel/relations/writes' require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/array.rb b/lib/arel/relations/array.rb deleted file mode 100644 index dac65abbc2..0000000000 --- a/lib/arel/relations/array.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Array < Relation - include Recursion::BaseCase - - def initialize(array, attribute_names) - @array, @attribute_names = array, attribute_names - end - - def attributes - @attributes ||= @attribute_names.collect do |name| - Attribute.new(self, name.to_sym) - end - end - - def call(connection = nil) - @array.collect { |row| attributes.zip(row).to_hash } - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/alias.rb b/lib/arel/relations/operations/alias.rb index 8ed33fc597..67837f6a75 100644 --- a/lib/arel/relations/operations/alias.rb +++ b/lib/arel/relations/operations/alias.rb @@ -1,6 +1,5 @@ module Arel class Alias < Compound - include Recursion::BaseCase attributes :relation deriving :initialize alias_method :==, :equal? diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb index 8fe89358d8..8e19254378 100644 --- a/lib/arel/relations/operations/join.rb +++ b/lib/arel/relations/operations/join.rb @@ -9,22 +9,6 @@ module Arel @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates end - def table_sql(formatter = Sql::TableReference.new(self)) - relation1.externalize.table_sql(formatter) - end - - def joins(environment, formatter = Sql::TableReference.new(environment)) - @joins ||= begin - this_join = [ - join_sql, - relation2.externalize.table_sql(formatter), - ("ON" unless predicates.blank?), - (ons + relation2.externalize.wheres).collect { |p| p.bind(environment).to_sql(Sql::WhereClause.new(environment)) }.join(' AND ') - ].compact.join(" ") - [relation1.joins(environment), this_join, relation2.joins(environment)].compact.join(" ") - end - end - def attributes @attributes ||= (relation1.externalize.attributes + relation2.externalize.attributes).collect { |a| a.bind(self) } diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb index ef295dfdd7..20badaf165 100644 --- a/lib/arel/relations/relation.rb +++ b/lib/arel/relations/relation.rb @@ -6,32 +6,6 @@ module Arel Session.new end - def count - @count = "COUNT(*) AS count_all" - end - - def to_sql(formatter = Sql::SelectStatement.new(self)) - formatter.select select_sql, self - end - alias_method :to_s, :to_sql - - def select_sql - [ - "SELECT #{@count} #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ') unless @count}", - "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), - ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n") - end - - def inclusion_predicate_sql - "IN" - end - def call engine.read(self) end @@ -44,10 +18,6 @@ module Arel self end - def christener - @christener ||= Sql::Christener.new - end - module Enumerable include ::Enumerable @@ -155,7 +125,7 @@ module Arel def orders; [] end def inserts; [] end def groupings; [] end - def joins(formatter = nil); nil end + def joins(formatter = nil); nil end # FIXME def taken; nil end def skipped; nil end end diff --git a/lib/arel/relations/table.rb b/lib/arel/relations/table.rb deleted file mode 100644 index 0433abbbb2..0000000000 --- a/lib/arel/relations/table.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Arel - class Table < Relation - include Recursion::BaseCase - - cattr_accessor :engine - attr_reader :name, :engine - hash_on :name - - def initialize(name, engine = Table.engine) - @name, @engine = name.to_s, engine - end - - def attributes - @attributes ||= columns.collect do |column| - Attribute.new(self, column.name.to_sym) - end - end - - def column_for(attribute) - has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } - end - - def columns - @columns ||= engine.columns(name, "#{name} Columns") - end - - def reset - @attributes = @columns = nil - end - - def ==(other) - Table === other and - name == other.name - end - end -end diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb index 454d455359..fbd949ef0c 100644 --- a/lib/arel/relations/utilities.rb +++ b/lib/arel/relations/utilities.rb @@ -1,5 +1,3 @@ require 'arel/relations/utilities/compound' -require 'arel/relations/utilities/recursion' require 'arel/relations/utilities/nil' require 'arel/relations/utilities/externalization' -require 'arel/relations/utilities/recursion' \ No newline at end of file diff --git a/lib/arel/relations/utilities/externalization.rb b/lib/arel/relations/utilities/externalization.rb index 3b9b2296dc..bd067f2304 100644 --- a/lib/arel/relations/utilities/externalization.rb +++ b/lib/arel/relations/utilities/externalization.rb @@ -2,24 +2,14 @@ module Arel class Externalization < Compound attributes :relation deriving :initialize, :== - include Recursion::BaseCase def wheres [] end - def table_sql(formatter = Sql::TableReference.new(relation)) - formatter.select relation.select_sql, self - end - def attributes @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } end - - # REMOVEME - def name - relation.name + '_external' - end end class Relation diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/relations/utilities/nil.rb index 56cf395d2c..6a9d678c45 100644 --- a/lib/arel/relations/utilities/nil.rb +++ b/lib/arel/relations/utilities/nil.rb @@ -3,8 +3,5 @@ require 'singleton' module Arel class Nil < Relation include Singleton - - def table_sql(formatter = nil); '' end - def name; '' end end end diff --git a/lib/arel/relations/utilities/recursion.rb b/lib/arel/relations/utilities/recursion.rb deleted file mode 100644 index 848b059507..0000000000 --- a/lib/arel/relations/utilities/recursion.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Recursion - module BaseCase - def table - self - end - - def table_sql(formatter = Sql::TableReference.new(self)) - formatter.table self - end - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb index 0a04454e7f..a94067c7fa 100644 --- a/lib/arel/relations/writes/delete.rb +++ b/lib/arel/relations/writes/delete.rb @@ -3,15 +3,6 @@ module Arel attributes :relation deriving :initialize, :== - def to_sql(formatter = nil) - [ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") - end - def call engine.delete(self) end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb index d05bd9cdc8..6d85e9769a 100644 --- a/lib/arel/relations/writes/insert.rb +++ b/lib/arel/relations/writes/insert.rb @@ -7,15 +7,6 @@ module Arel @relation, @record = relation, record.bind(relation) end - def to_sql(formatter = nil) - [ - "INSERT", - "INTO #{table_sql}", - "(#{record.keys.map { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.map { |key, value| key.format(value) }.join(', ')})" - ].join("\n") - end - def call engine.create(self) end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb index fd0aadb479..e647218a80 100644 --- a/lib/arel/relations/writes/update.rb +++ b/lib/arel/relations/writes/update.rb @@ -7,17 +7,6 @@ module Arel @relation, @assignments = relation, assignments end - def to_sql(formatter = nil) - [ - "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), - ("WHERE #{wheres.map(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") - end - def call engine.update(self) end diff --git a/lib/arel/sql.rb b/lib/arel/sql.rb deleted file mode 100644 index 7e7dd0a80f..0000000000 --- a/lib/arel/sql.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/sql/formatters' -require 'arel/sql/christener' \ No newline at end of file diff --git a/lib/arel/sql/christener.rb b/lib/arel/sql/christener.rb deleted file mode 100644 index 5883a75f41..0000000000 --- a/lib/arel/sql/christener.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Arel - module Sql - class Christener - def name_for(relation) - @used_names ||= Hash.new(0) - (@relation_names ||= Hash.new do |hash, relation| - @used_names[name = relation.name] += 1 - hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') - end)[relation.table] - end - end - end -end \ No newline at end of file diff --git a/lib/arel/sql/formatters.rb b/lib/arel/sql/formatters.rb deleted file mode 100644 index f82ddf631f..0000000000 --- a/lib/arel/sql/formatters.rb +++ /dev/null @@ -1,121 +0,0 @@ -module Arel - module Sql - class Formatter - attr_reader :environment - delegate :christener, :engine, :to => :environment - delegate :name_for, :to => :christener - delegate :quote_table_name, :quote_column_name, :quote, :to => :engine - - def initialize(environment) - @environment = environment - end - end - - class SelectClause < Formatter - def attribute(attribute) - # FIXME this should check that the column exists - if attribute.name.to_s =~ /^\w*$/ - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - else - attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - end - end - - def expression(expression) - if expression.function_sql == "DISTINCT" - "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') - else - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") - end - end - - def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(name_for(table))}" - end - - def value(value) - value - end - end - - class PassThrough < Formatter - def value(value) - value - end - end - - class WhereClause < PassThrough - end - - class OrderClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - end - - class GroupClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - end - - class WhereCondition < Formatter - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" - end - - def expression(expression) - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" - end - - def value(value) - value.to_sql(self) - end - - def scalar(value, column = nil) - quote(value, column) - end - - def select(select_sql, table) - "(#{select_sql})" - end - end - - class SelectStatement < Formatter - def select(select_sql, table) - select_sql - end - end - - class TableReference < Formatter - def select(select_sql, table) - "(#{select_sql}) AS #{quote_table_name(name_for(table))}" - end - - def table(table) - if table.name =~ /^(\w|-)*$/ - quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') - else - table.name + (table.name != name_for(table) ? " AS " + (name_for(table)) : '') - end - end - end - - class Attribute < WhereCondition - def scalar(scalar) - quote(scalar, environment.column) - end - - def array(array) - "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" - end - - def range(left, right) - "#{left} AND #{right}" - end - end - - class Value < WhereCondition - end - end -end diff --git a/spec/arel/unit/relations/skip_spec.rb b/spec/arel/unit/relations/skip_spec.rb index 0653d795b1..2c8f6ccadb 100644 --- a/spec/arel/unit/relations/skip_spec.rb +++ b/spec/arel/unit/relations/skip_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - sql = Skip.new(@relation, @skipped).to_s + sql = Skip.new(@relation, @skipped).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index 08486c7b6c..211e6921f8 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -87,12 +87,12 @@ module Arel describe '#engine' do it "defaults to global engine" do - Table.engine = engine = Engine.new + Table.engine = engine = Sql::Engine.new Table.new(:users).engine.should == engine end it "can be specified" do - Table.new(:users, engine = Engine.new).engine.should == engine + Table.new(:users, engine = Sql::Engine.new).engine.should == engine end end end diff --git a/spec/arel/unit/relations/take_spec.rb b/spec/arel/unit/relations/take_spec.rb index 911b84e01e..d6442fc9d1 100644 --- a/spec/arel/unit/relations/take_spec.rb +++ b/spec/arel/unit/relations/take_spec.rb @@ -9,7 +9,7 @@ module Arel describe '#to_sql' do it "manufactures sql with limit and offset" do - sql = Take.new(@relation, @taken).to_s + sql = Take.new(@relation, @taken).to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8d515d66f1..6a9a2ef23c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -30,6 +30,6 @@ Spec::Runner.configure do |config| config.include AdapterGuards config.mock_with :rr config.before do - Arel::Table.engine = Arel::Engine.new(ActiveRecord::Base) + Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) end end -- cgit v1.2.3 From 7032a50297fce4d7724d1735e81e5df5fd919e71 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:31:04 -0400 Subject: reorganized file structures Conflicts: lib/arel.rb lib/arel/arel.rb lib/arel/engines/memory/predicates.rb lib/arel/engines/memory/relations/array.rb lib/arel/engines/sql/relations/table.rb --- README.markdown | 6 +- lib/arel.rb | 6 +- lib/arel/algebra.rb | 4 + lib/arel/algebra/extensions.rb | 4 + lib/arel/algebra/extensions/array.rb | 5 + lib/arel/algebra/extensions/class.rb | 37 ++++++ lib/arel/algebra/extensions/hash.rb | 7 ++ lib/arel/algebra/extensions/object.rb | 15 +++ lib/arel/algebra/extensions/pathname.rb | 5 + lib/arel/algebra/predicates.rb | 45 +++++++ lib/arel/algebra/primitives.rb | 4 + lib/arel/algebra/primitives/attribute.rb | 133 ++++++++++++++++++++ lib/arel/algebra/primitives/expression.rb | 31 +++++ lib/arel/algebra/primitives/value.rb | 19 +++ lib/arel/algebra/relations.rb | 15 +++ lib/arel/algebra/relations/operations/alias.rb | 7 ++ lib/arel/algebra/relations/operations/group.rb | 15 +++ lib/arel/algebra/relations/operations/join.rb | 41 +++++++ lib/arel/algebra/relations/operations/order.rb | 16 +++ lib/arel/algebra/relations/operations/project.rb | 19 +++ lib/arel/algebra/relations/operations/skip.rb | 10 ++ lib/arel/algebra/relations/operations/take.rb | 10 ++ lib/arel/algebra/relations/operations/where.rb | 16 +++ lib/arel/algebra/relations/relation.rb | 134 +++++++++++++++++++++ lib/arel/algebra/relations/utilities/compound.rb | 18 +++ .../algebra/relations/utilities/externalization.rb | 24 ++++ lib/arel/algebra/relations/utilities/nil.rb | 7 ++ lib/arel/algebra/relations/writes/delete.rb | 10 ++ lib/arel/algebra/relations/writes/insert.rb | 14 +++ lib/arel/algebra/relations/writes/update.rb | 14 +++ lib/arel/arel.rb | 3 - lib/arel/engines.rb | 4 +- lib/arel/engines/array/array.rb | 1 - lib/arel/engines/array/relations/array.rb | 19 --- lib/arel/engines/memory.rb | 4 + lib/arel/engines/memory/engine.rb | 12 ++ lib/arel/engines/memory/predicates.rb | 58 +++++++++ lib/arel/engines/memory/primitives.rb | 2 + lib/arel/engines/memory/primitives/attribute.rb | 7 ++ lib/arel/engines/memory/primitives/value.rb | 7 ++ lib/arel/engines/memory/relations.rb | 2 + lib/arel/engines/memory/relations/array.rb | 21 ++++ .../engines/memory/relations/operations/where.rb | 7 ++ lib/arel/engines/sql.rb | 7 ++ lib/arel/engines/sql/primitives/attribute.rb | 2 - lib/arel/engines/sql/relations.rb | 13 +- lib/arel/engines/sql/relations/operations.rb | 2 - lib/arel/engines/sql/relations/table.rb | 5 + lib/arel/engines/sql/relations/utilities.rb | 3 - lib/arel/engines/sql/relations/writes.rb | 3 - lib/arel/engines/sql/sql.rb | 7 -- lib/arel/extensions.rb | 4 - lib/arel/extensions/array.rb | 5 - lib/arel/extensions/class.rb | 37 ------ lib/arel/extensions/hash.rb | 7 -- lib/arel/extensions/object.rb | 15 --- lib/arel/predicates.rb | 66 ---------- lib/arel/primitives.rb | 4 - lib/arel/primitives/attribute.rb | 133 -------------------- lib/arel/primitives/expression.rb | 31 ----- lib/arel/primitives/value.rb | 19 --- lib/arel/relations.rb | 4 - lib/arel/relations/operations.rb | 8 -- lib/arel/relations/operations/alias.rb | 7 -- lib/arel/relations/operations/group.rb | 15 --- lib/arel/relations/operations/join.rb | 41 ------- lib/arel/relations/operations/order.rb | 16 --- lib/arel/relations/operations/project.rb | 19 --- lib/arel/relations/operations/skip.rb | 10 -- lib/arel/relations/operations/take.rb | 10 -- lib/arel/relations/operations/where.rb | 16 --- lib/arel/relations/relation.rb | 134 --------------------- lib/arel/relations/utilities.rb | 3 - lib/arel/relations/utilities/compound.rb | 18 --- lib/arel/relations/utilities/externalization.rb | 24 ---- lib/arel/relations/utilities/nil.rb | 7 -- lib/arel/relations/writes.rb | 3 - lib/arel/relations/writes/delete.rb | 10 -- lib/arel/relations/writes/insert.rb | 14 --- lib/arel/relations/writes/update.rb | 14 --- lib/arel/session.rb | 2 - spec/arel/integration/joins/with_adjacency_spec.rb | 2 +- .../integration/joins/with_aggregations_spec.rb | 4 +- spec/arel/integration/joins/with_compounds_spec.rb | 4 +- spec/arel/unit/relations/array_spec.rb | 7 ++ 85 files changed, 838 insertions(+), 755 deletions(-) create mode 100644 lib/arel/algebra.rb create mode 100644 lib/arel/algebra/extensions.rb create mode 100644 lib/arel/algebra/extensions/array.rb create mode 100644 lib/arel/algebra/extensions/class.rb create mode 100644 lib/arel/algebra/extensions/hash.rb create mode 100644 lib/arel/algebra/extensions/object.rb create mode 100644 lib/arel/algebra/extensions/pathname.rb create mode 100644 lib/arel/algebra/predicates.rb create mode 100644 lib/arel/algebra/primitives.rb create mode 100644 lib/arel/algebra/primitives/attribute.rb create mode 100644 lib/arel/algebra/primitives/expression.rb create mode 100644 lib/arel/algebra/primitives/value.rb create mode 100644 lib/arel/algebra/relations.rb create mode 100644 lib/arel/algebra/relations/operations/alias.rb create mode 100644 lib/arel/algebra/relations/operations/group.rb create mode 100644 lib/arel/algebra/relations/operations/join.rb create mode 100644 lib/arel/algebra/relations/operations/order.rb create mode 100644 lib/arel/algebra/relations/operations/project.rb create mode 100644 lib/arel/algebra/relations/operations/skip.rb create mode 100644 lib/arel/algebra/relations/operations/take.rb create mode 100644 lib/arel/algebra/relations/operations/where.rb create mode 100644 lib/arel/algebra/relations/relation.rb create mode 100644 lib/arel/algebra/relations/utilities/compound.rb create mode 100644 lib/arel/algebra/relations/utilities/externalization.rb create mode 100644 lib/arel/algebra/relations/utilities/nil.rb create mode 100644 lib/arel/algebra/relations/writes/delete.rb create mode 100644 lib/arel/algebra/relations/writes/insert.rb create mode 100644 lib/arel/algebra/relations/writes/update.rb delete mode 100644 lib/arel/arel.rb delete mode 100644 lib/arel/engines/array/array.rb delete mode 100644 lib/arel/engines/array/relations/array.rb create mode 100644 lib/arel/engines/memory.rb create mode 100644 lib/arel/engines/memory/engine.rb create mode 100644 lib/arel/engines/memory/predicates.rb create mode 100644 lib/arel/engines/memory/primitives.rb create mode 100644 lib/arel/engines/memory/primitives/attribute.rb create mode 100644 lib/arel/engines/memory/primitives/value.rb create mode 100644 lib/arel/engines/memory/relations.rb create mode 100644 lib/arel/engines/memory/relations/array.rb create mode 100644 lib/arel/engines/memory/relations/operations/where.rb create mode 100644 lib/arel/engines/sql.rb delete mode 100644 lib/arel/engines/sql/relations/operations.rb delete mode 100644 lib/arel/engines/sql/relations/utilities.rb delete mode 100644 lib/arel/engines/sql/relations/writes.rb delete mode 100644 lib/arel/engines/sql/sql.rb delete mode 100644 lib/arel/extensions.rb delete mode 100644 lib/arel/extensions/array.rb delete mode 100644 lib/arel/extensions/class.rb delete mode 100644 lib/arel/extensions/hash.rb delete mode 100644 lib/arel/extensions/object.rb delete mode 100644 lib/arel/predicates.rb delete mode 100644 lib/arel/primitives.rb delete mode 100644 lib/arel/primitives/attribute.rb delete mode 100644 lib/arel/primitives/expression.rb delete mode 100644 lib/arel/primitives/value.rb delete mode 100644 lib/arel/relations.rb delete mode 100644 lib/arel/relations/operations.rb delete mode 100644 lib/arel/relations/operations/alias.rb delete mode 100644 lib/arel/relations/operations/group.rb delete mode 100644 lib/arel/relations/operations/join.rb delete mode 100644 lib/arel/relations/operations/order.rb delete mode 100644 lib/arel/relations/operations/project.rb delete mode 100644 lib/arel/relations/operations/skip.rb delete mode 100644 lib/arel/relations/operations/take.rb delete mode 100644 lib/arel/relations/operations/where.rb delete mode 100644 lib/arel/relations/relation.rb delete mode 100644 lib/arel/relations/utilities.rb delete mode 100644 lib/arel/relations/utilities/compound.rb delete mode 100644 lib/arel/relations/utilities/externalization.rb delete mode 100644 lib/arel/relations/utilities/nil.rb delete mode 100644 lib/arel/relations/writes.rb delete mode 100644 lib/arel/relations/writes/delete.rb delete mode 100644 lib/arel/relations/writes/insert.rb delete mode 100644 lib/arel/relations/writes/update.rb diff --git a/README.markdown b/README.markdown index e979dbc2a3..4d95234423 100644 --- a/README.markdown +++ b/README.markdown @@ -18,7 +18,7 @@ Generating a query with ARel is simple. For example, in order to produce you construct a table relation and convert it to sql: - users = Arel(:users) + users = Table(:users) users.to_sql In fact, you will probably never call `#to_sql`. Rather, you'll work with data from the table directly. You can iterate through all rows in the `users` table like this: @@ -81,7 +81,7 @@ The `AND` operator will behave similarly. Finally, most operations take a block form. For example: - Arel(:users) \ + Table(:users) \ .where { |u| u[:id].eq(1) } \ .project { |u| u[:id] } @@ -95,7 +95,7 @@ The examples above are fairly simple and other libraries match or come close to Where Arel really shines 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: - comments = Arel(:comments) + comments = Table(:comments) And this table has the following attributes: diff --git a/lib/arel.rb b/lib/arel.rb index f22287fcc5..fcca60758e 100644 --- a/lib/arel.rb +++ b/lib/arel.rb @@ -5,10 +5,6 @@ require 'activesupport' require 'activerecord' require 'active_record/connection_adapters/abstract/quoting' -require 'arel/arel' -require 'arel/extensions' -require 'arel/predicates' -require 'arel/relations' +require 'arel/algebra' require 'arel/engines' require 'arel/session' -require 'arel/primitives' diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb new file mode 100644 index 0000000000..f27882a343 --- /dev/null +++ b/lib/arel/algebra.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/extensions' +require 'arel/algebra/predicates' +require 'arel/algebra/relations' +require 'arel/algebra/primitives' \ No newline at end of file diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb new file mode 100644 index 0000000000..5338fee989 --- /dev/null +++ b/lib/arel/algebra/extensions.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/extensions/object' +require 'arel/algebra/extensions/class' +require 'arel/algebra/extensions/array' +require 'arel/algebra/extensions/hash' diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb new file mode 100644 index 0000000000..5b6d6d6abd --- /dev/null +++ b/lib/arel/algebra/extensions/array.rb @@ -0,0 +1,5 @@ +class Array + def to_hash + Hash[*flatten] + end +end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb new file mode 100644 index 0000000000..f37898e7d7 --- /dev/null +++ b/lib/arel/algebra/extensions/class.rb @@ -0,0 +1,37 @@ +class Class + def attributes(*attrs) + @attributes = attrs + attr_reader *attrs + end + + def deriving(*methods) + methods.each { |m| derive m } + end + + def derive(method_name) + methods = { + :initialize => " + def #{method_name}(#{@attributes.join(',')}) + #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} + end + ", + :== => " + def ==(other) + #{name} === other && + #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} + end + " + } + class_eval methods[method_name], __FILE__, __LINE__ + end + + def hash_on(delegatee) + define_method :eql? do |other| + self == other + end + + define_method :hash do + @hash ||= delegatee.hash + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb new file mode 100644 index 0000000000..7472b5aa73 --- /dev/null +++ b/lib/arel/algebra/extensions/hash.rb @@ -0,0 +1,7 @@ +class Hash + def bind(relation) + inject({}) do |bound, (key, value)| + bound.merge(key.bind(relation) => value.bind(relation)) + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb new file mode 100644 index 0000000000..d626407dcb --- /dev/null +++ b/lib/arel/algebra/extensions/object.rb @@ -0,0 +1,15 @@ +class Object + def bind(relation) + Arel::Value.new(self, relation) + end + + def find_correlate_in(relation) + bind(relation) + end + + def metaclass + class << self + self + end + end +end diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb new file mode 100644 index 0000000000..2f7e2733e7 --- /dev/null +++ b/lib/arel/algebra/extensions/pathname.rb @@ -0,0 +1,5 @@ +class Pathname + def /(path) + (self + path).expand_path + end +end \ No newline at end of file diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb new file mode 100644 index 0000000000..f83101306e --- /dev/null +++ b/lib/arel/algebra/predicates.rb @@ -0,0 +1,45 @@ +module Arel + class Predicate + end + + class Binary < Predicate + attributes :operand1, :operand2 + deriving :initialize + + def ==(other) + self.class === other and + @operand1 == other.operand1 and + @operand2 == other.operand2 + end + + def bind(relation) + self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) + end + end + + class Equality < Binary + def ==(other) + Equality === other and + ((operand1 == other.operand1 and operand2 == other.operand2) or + (operand1 == other.operand2 and operand2 == other.operand1)) + end + end + + class GreaterThanOrEqualTo < Binary + end + + class GreaterThan < Binary + end + + class LessThanOrEqualTo < Binary + end + + class LessThan < Binary + end + + class Match < Binary + end + + class In < Binary + end +end \ No newline at end of file diff --git a/lib/arel/algebra/primitives.rb b/lib/arel/algebra/primitives.rb new file mode 100644 index 0000000000..a4c3169e0b --- /dev/null +++ b/lib/arel/algebra/primitives.rb @@ -0,0 +1,4 @@ +require 'arel/algebra/primitives/attribute' +require 'arel/algebra/primitives/value' +require 'arel/algebra/primitives/expression' + diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb new file mode 100644 index 0000000000..5e216770e4 --- /dev/null +++ b/lib/arel/algebra/primitives/attribute.rb @@ -0,0 +1,133 @@ +require 'set' + +module Arel + class Attribute + attributes :relation, :name, :alias, :ancestor + deriving :== + delegate :engine, :christener, :to => :relation + + def initialize(relation, name, options = {}) + @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] + end + + def named?(hypothetical_name) + (@alias || name).to_s == hypothetical_name.to_s + end + + def aggregation? + false + end + + module Transformations + def self.included(klass) + klass.send :alias_method, :eql?, :== + end + + def hash + @hash ||= history.size + name.hash + relation.hash + end + + def as(aliaz = nil) + Attribute.new(relation, name, :alias => aliaz, :ancestor => self) + end + + def bind(new_relation) + relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) + end + + def to_attribute + self + end + end + include Transformations + + module Congruence + def history + @history ||= [self] + (ancestor ? ancestor.history : []) + end + + def join? + relation.join? + end + + def root + history.last + end + + def original_relation + @original_relation ||= original_attribute.relation + end + + def original_attribute + @original_attribute ||= history.detect { |a| !a.join? } + end + + def find_correlate_in(relation) + relation[self] || self + end + + def descends_from?(other) + history.include?(other) + end + + def /(other) + other ? (history & other.history).size : 0 + end + end + include Congruence + + module Predications + def eq(other) + Equality.new(self, other) + end + + def lt(other) + LessThan.new(self, other) + end + + def lteq(other) + LessThanOrEqualTo.new(self, other) + end + + def gt(other) + GreaterThan.new(self, other) + end + + def gteq(other) + GreaterThanOrEqualTo.new(self, other) + end + + def matches(regexp) + Match.new(self, regexp) + end + + def in(array) + In.new(self, array) + end + end + include Predications + + module Expressions + def count(distinct = false) + distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT") + end + + def sum + Expression.new(self, "SUM") + end + + def maximum + Expression.new(self, "MAX") + end + + def minimum + Expression.new(self, "MIN") + end + + def average + Expression.new(self, "AVG") + end + end + include Expressions + end +end diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb new file mode 100644 index 0000000000..b67a5e1f8e --- /dev/null +++ b/lib/arel/algebra/primitives/expression.rb @@ -0,0 +1,31 @@ +module Arel + class Expression < Attribute + attributes :attribute, :function_sql, :alias, :ancestor + deriving :== + delegate :relation, :to => :attribute + alias_method :name, :alias + + def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) + @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor + end + + def aggregation? + true + end + + module Transformations + def as(aliaz) + Expression.new(attribute, function_sql, aliaz, self) + end + + def bind(new_relation) + new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + end + + def to_attribute + Attribute.new(relation, @alias, :ancestor => self) + end + end + include Transformations + end +end diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/primitives/value.rb new file mode 100644 index 0000000000..91c4045507 --- /dev/null +++ b/lib/arel/algebra/primitives/value.rb @@ -0,0 +1,19 @@ +module Arel + class Value + attributes :value, :relation + deriving :initialize, :== + delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value + + def bind(relation) + Value.new(value, relation) + end + + def aggregation? + false + end + + def to_attribute + value + end + end +end diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb new file mode 100644 index 0000000000..03f04d2459 --- /dev/null +++ b/lib/arel/algebra/relations.rb @@ -0,0 +1,15 @@ +require 'arel/algebra/relations/relation' +require 'arel/algebra/relations/utilities/compound' +require 'arel/algebra/relations/utilities/nil' +require 'arel/algebra/relations/utilities/externalization' +require 'arel/algebra/relations/writes/delete' +require 'arel/algebra/relations/writes/update' +require 'arel/algebra/relations/writes/insert' +require 'arel/algebra/relations/operations/alias' +require 'arel/algebra/relations/operations/group' +require 'arel/algebra/relations/operations/join' +require 'arel/algebra/relations/operations/order' +require 'arel/algebra/relations/operations/project' +require 'arel/algebra/relations/operations/where' +require 'arel/algebra/relations/operations/skip' +require 'arel/algebra/relations/operations/take' \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb new file mode 100644 index 0000000000..67837f6a75 --- /dev/null +++ b/lib/arel/algebra/relations/operations/alias.rb @@ -0,0 +1,7 @@ +module Arel + class Alias < Compound + attributes :relation + deriving :initialize + alias_method :==, :equal? + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb new file mode 100644 index 0000000000..04fd9fea62 --- /dev/null +++ b/lib/arel/algebra/relations/operations/group.rb @@ -0,0 +1,15 @@ +module Arel + class Group < Compound + attributes :relation, :groupings + deriving :== + + def initialize(relation, *groupings, &block) + @relation = relation + @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) } + end + + def externalizable? + true + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb new file mode 100644 index 0000000000..8e19254378 --- /dev/null +++ b/lib/arel/algebra/relations/operations/join.rb @@ -0,0 +1,41 @@ +module Arel + class Join < Relation + attributes :join_sql, :relation1, :relation2, :predicates + deriving :== + delegate :engine, :name, :to => :relation1 + hash_on :relation1 + + def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) + @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + end + + def attributes + @attributes ||= (relation1.externalize.attributes + + relation2.externalize.attributes).collect { |a| a.bind(self) } + end + + def wheres + # TESTME bind to self? + relation1.externalize.wheres + end + + def ons + @ons ||= @predicates.collect { |p| p.bind(self) } + end + + # TESTME + def externalizable? + relation1.externalizable? or relation2.externalizable? + end + + def join? + true + end + end + + class Relation + def join? + false + end + end +end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb new file mode 100644 index 0000000000..05af3fde4d --- /dev/null +++ b/lib/arel/algebra/relations/operations/order.rb @@ -0,0 +1,16 @@ +module Arel + class Order < Compound + attributes :relation, :orderings + deriving :== + + def initialize(relation, *orderings, &block) + @relation = relation + @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) } + end + + # TESTME + def orders + (orderings + relation.orders).collect { |o| o.bind(self) } + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb new file mode 100644 index 0000000000..5507ea3163 --- /dev/null +++ b/lib/arel/algebra/relations/operations/project.rb @@ -0,0 +1,19 @@ +module Arel + class Project < Compound + attributes :relation, :projections + deriving :== + + def initialize(relation, *projections, &block) + @relation = relation + @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } + end + + def attributes + @attributes ||= projections.collect { |p| p.bind(self) } + end + + def externalizable? + attributes.any?(&:aggregation?) or relation.externalizable? + end + end +end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb new file mode 100644 index 0000000000..930e4c94ea --- /dev/null +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -0,0 +1,10 @@ +module Arel + class Skip < Compound + attributes :relation, :skipped + deriving :initialize, :== + + def externalizable? + true + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb new file mode 100644 index 0000000000..2fd3fdf635 --- /dev/null +++ b/lib/arel/algebra/relations/operations/take.rb @@ -0,0 +1,10 @@ +module Arel + class Take < Compound + attributes :relation, :taken + deriving :initialize, :== + + def externalizable? + true + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/where.rb b/lib/arel/algebra/relations/operations/where.rb new file mode 100644 index 0000000000..608aaeb4b7 --- /dev/null +++ b/lib/arel/algebra/relations/operations/where.rb @@ -0,0 +1,16 @@ +module Arel + class Where < Compound + attributes :relation, :predicate + deriving :== + + def initialize(relation, *predicates, &block) + predicate = block_given?? yield(relation) : predicates.shift + @relation = predicates.empty?? relation : Where.new(relation, *predicates) + @predicate = predicate.bind(@relation) + end + + def wheres + @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } + end + end +end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb new file mode 100644 index 0000000000..20badaf165 --- /dev/null +++ b/lib/arel/algebra/relations/relation.rb @@ -0,0 +1,134 @@ +module Arel + class Relation + attr_reader :count + + def session + Session.new + end + + def call + engine.read(self) + end + + def bind(relation) + self + end + + def root + self + end + + module Enumerable + include ::Enumerable + + def each(&block) + session.read(self).each(&block) + end + + def first + session.read(self).first + end + end + include Enumerable + + module Operable + def join(other_relation = nil, join_type = "INNER JOIN") + case other_relation + when String + Join.new(other_relation, self) + when Relation + JoinOperation.new(join_type, self, other_relation) + else + self + end + end + + def outer_join(other_relation = nil) + join(other_relation, "LEFT OUTER JOIN") + end + + [:where, :project, :order, :take, :skip, :group].each do |operation_name| + operation = <<-OPERATION + def #{operation_name}(*arguments, &block) + arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) + end + OPERATION + class_eval operation, __FILE__, __LINE__ + end + + def alias + Alias.new(self) + end + + module Writable + def insert(record) + session.create Insert.new(self, record); self + end + + def update(assignments) + session.update Update.new(self, assignments) + end + + def delete + session.delete Deletion.new(self) + end + end + include Writable + + JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do + def on(*predicates) + Join.new(join_sql, relation1, relation2, *predicates) + end + end + end + include Operable + + module AttributeAccessable + def [](index) + case index + when Symbol, String + find_attribute_matching_name(index) + when Attribute, Expression + find_attribute_matching_attribute(index) + when Array + index.collect { |i| self[i] } + end + end + + def find_attribute_matching_name(name) + attributes.detect { |a| a.named?(name) } + end + + def find_attribute_matching_attribute(attribute) + matching_attributes(attribute).max do |a1, a2| + (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) + end + end + + private + def matching_attributes(attribute) + (@matching_attributes ||= attributes.inject({}) do |hash, a| + (hash[a.root] ||= []) << a + hash + end)[attribute.root] || [] + end + + def has_attribute?(attribute) + !matching_attributes(attribute).empty? + end + end + include AttributeAccessable + + module DefaultOperations + def attributes; [] end + def wheres; [] end + def orders; [] end + def inserts; [] end + def groupings; [] end + def joins(formatter = nil); nil end # FIXME + def taken; nil end + def skipped; nil end + end + include DefaultOperations + end +end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb new file mode 100644 index 0000000000..e33b8dbf14 --- /dev/null +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -0,0 +1,18 @@ +module Arel + class Compound < Relation + attr_reader :relation + hash_on :relation + delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, + :column_for, :engine, :table, :table_sql, :array, + :to => :relation + + [:attributes, :wheres, :groupings, :orders].each do |operation_name| + operation = <<-OPERATION + def #{operation_name} + @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } + end + OPERATION + class_eval operation, __FILE__, __LINE__ + end + end +end diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb new file mode 100644 index 0000000000..bd067f2304 --- /dev/null +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -0,0 +1,24 @@ +module Arel + class Externalization < Compound + attributes :relation + deriving :initialize, :== + + def wheres + [] + end + + def attributes + @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } + end + end + + class Relation + def externalize + @externalized ||= externalizable?? Externalization.new(self) : self + end + + def externalizable? + false + end + end +end diff --git a/lib/arel/algebra/relations/utilities/nil.rb b/lib/arel/algebra/relations/utilities/nil.rb new file mode 100644 index 0000000000..6a9d678c45 --- /dev/null +++ b/lib/arel/algebra/relations/utilities/nil.rb @@ -0,0 +1,7 @@ +require 'singleton' + +module Arel + class Nil < Relation + include Singleton + end +end diff --git a/lib/arel/algebra/relations/writes/delete.rb b/lib/arel/algebra/relations/writes/delete.rb new file mode 100644 index 0000000000..a94067c7fa --- /dev/null +++ b/lib/arel/algebra/relations/writes/delete.rb @@ -0,0 +1,10 @@ +module Arel + class Deletion < Compound + attributes :relation + deriving :initialize, :== + + def call + engine.delete(self) + end + end +end diff --git a/lib/arel/algebra/relations/writes/insert.rb b/lib/arel/algebra/relations/writes/insert.rb new file mode 100644 index 0000000000..6d85e9769a --- /dev/null +++ b/lib/arel/algebra/relations/writes/insert.rb @@ -0,0 +1,14 @@ +module Arel + class Insert < Compound + attributes :relation, :record + deriving :== + + def initialize(relation, record) + @relation, @record = relation, record.bind(relation) + end + + def call + engine.create(self) + end + end +end diff --git a/lib/arel/algebra/relations/writes/update.rb b/lib/arel/algebra/relations/writes/update.rb new file mode 100644 index 0000000000..e647218a80 --- /dev/null +++ b/lib/arel/algebra/relations/writes/update.rb @@ -0,0 +1,14 @@ +module Arel + class Update < Compound + attributes :relation, :assignments + deriving :== + + def initialize(relation, assignments) + @relation, @assignments = relation, assignments + end + + def call + engine.update(self) + end + end +end diff --git a/lib/arel/arel.rb b/lib/arel/arel.rb deleted file mode 100644 index 7780d45e25..0000000000 --- a/lib/arel/arel.rb +++ /dev/null @@ -1,3 +0,0 @@ -def Arel(name, engine = (Arel::Table.engine || ActiveRecord::Base.connection)) - Arel::Table.new(name, engine) -end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb index 63a929528f..3f854edf90 100644 --- a/lib/arel/engines.rb +++ b/lib/arel/engines.rb @@ -1,2 +1,2 @@ -require 'arel/engines/sql/sql' -require 'arel/engines/array/array' \ No newline at end of file +require 'arel/engines/sql' +require 'arel/engines/memory' \ No newline at end of file diff --git a/lib/arel/engines/array/array.rb b/lib/arel/engines/array/array.rb deleted file mode 100644 index 3a3a47308a..0000000000 --- a/lib/arel/engines/array/array.rb +++ /dev/null @@ -1 +0,0 @@ -require 'arel/engines/array/relations/array' \ No newline at end of file diff --git a/lib/arel/engines/array/relations/array.rb b/lib/arel/engines/array/relations/array.rb deleted file mode 100644 index dac65abbc2..0000000000 --- a/lib/arel/engines/array/relations/array.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Array < Relation - include Recursion::BaseCase - - def initialize(array, attribute_names) - @array, @attribute_names = array, attribute_names - end - - def attributes - @attributes ||= @attribute_names.collect do |name| - Attribute.new(self, name.to_sym) - end - end - - def call(connection = nil) - @array.collect { |row| attributes.zip(row).to_hash } - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb new file mode 100644 index 0000000000..df6f6f3d48 --- /dev/null +++ b/lib/arel/engines/memory.rb @@ -0,0 +1,4 @@ +require 'arel/engines/memory/relations' +require 'arel/engines/memory/primitives' +require 'arel/engines/memory/engine' +require 'arel/engines/memory/predicates' \ No newline at end of file diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb new file mode 100644 index 0000000000..67a084f2cd --- /dev/null +++ b/lib/arel/engines/memory/engine.rb @@ -0,0 +1,12 @@ +module Arel + module Memory + class Engine + module CRUD + def read(relation) + relation.eval + end + end + include CRUD + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb new file mode 100644 index 0000000000..3522ea3ffa --- /dev/null +++ b/lib/arel/engines/memory/predicates.rb @@ -0,0 +1,58 @@ +module Arel + class Predicate + def or(other_predicate) + Or.new(self, other_predicate) + end + + def and(other_predicate) + And.new(self, other_predicate) + end + end + + class Binary < Predicate + def eval(row) + operand1.eval(row).send(operator, operand2.eval(row)) + end + end + + class CompoundPredicate < Binary + def to_sql(formatter = nil) + "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + end + end + + class Or < CompoundPredicate + def predicate_sql; "OR" end + end + + class And < CompoundPredicate + def predicate_sql; "AND" end + end + + class Equality < Binary + def ==(other) + Equality === other and + ((operand1 == other.operand1 and operand2 == other.operand2) or + (operand1 == other.operand2 and operand2 == other.operand1)) + end + end + + class GreaterThanOrEqualTo < Binary + end + + class GreaterThan < Binary + end + + class LessThanOrEqualTo < Binary + end + + class LessThan < Binary + def operator; :< end + end + + class Match < Binary + end + + class In < Binary + end +end diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb new file mode 100644 index 0000000000..4d5c76e956 --- /dev/null +++ b/lib/arel/engines/memory/primitives.rb @@ -0,0 +1,2 @@ +require 'arel/engines/memory/primitives/attribute' +require 'arel/engines/memory/primitives/value' diff --git a/lib/arel/engines/memory/primitives/attribute.rb b/lib/arel/engines/memory/primitives/attribute.rb new file mode 100644 index 0000000000..9864feadc2 --- /dev/null +++ b/lib/arel/engines/memory/primitives/attribute.rb @@ -0,0 +1,7 @@ +module Arel + class Attribute + def eval(row) + row[self] + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives/value.rb b/lib/arel/engines/memory/primitives/value.rb new file mode 100644 index 0000000000..b83cd02e57 --- /dev/null +++ b/lib/arel/engines/memory/primitives/value.rb @@ -0,0 +1,7 @@ +module Arel + class Value + def eval(row) + value + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb new file mode 100644 index 0000000000..6361d7c9d7 --- /dev/null +++ b/lib/arel/engines/memory/relations.rb @@ -0,0 +1,2 @@ +require 'arel/engines/memory/relations/array' +require 'arel/engines/memory/relations/operations/where' diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb new file mode 100644 index 0000000000..c02c62891b --- /dev/null +++ b/lib/arel/engines/memory/relations/array.rb @@ -0,0 +1,21 @@ +module Arel + class Array < Relation + attributes :array, :attribute_names + deriving :initialize + include Recursion::BaseCase + + def engine + @engine ||= Memory::Engine.new + end + + def attributes + @attributes ||= @attribute_names.collect do |name| + Attribute.new(self, name.to_sym) + end + end + + def eval + @array.collect { |row| attributes.zip(row).to_hash } + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations/operations/where.rb b/lib/arel/engines/memory/relations/operations/where.rb new file mode 100644 index 0000000000..eb11fb55fd --- /dev/null +++ b/lib/arel/engines/memory/relations/operations/where.rb @@ -0,0 +1,7 @@ +module Arel + class Where < Compound + def eval + relation.eval.select { |row| predicate.eval(row) } + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb new file mode 100644 index 0000000000..aed1fd861e --- /dev/null +++ b/lib/arel/engines/sql.rb @@ -0,0 +1,7 @@ +require 'arel/engines/sql/engine' +require 'arel/engines/sql/relations' +require 'arel/engines/sql/primitives' +require 'arel/engines/sql/predicates' +require 'arel/engines/sql/formatters' +require 'arel/engines/sql/extensions' +require 'arel/engines/sql/christener' \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/attribute.rb b/lib/arel/engines/sql/primitives/attribute.rb index 48de690b6f..ad78a9ec5b 100644 --- a/lib/arel/engines/sql/primitives/attribute.rb +++ b/lib/arel/engines/sql/primitives/attribute.rb @@ -1,5 +1,3 @@ -require 'set' - module Arel class Attribute def column diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 4de01b2691..39ef8852a1 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -1,5 +1,10 @@ -require 'arel/engines/sql/relations/utilities' +require 'arel/engines/sql/relations/utilities/recursion' +require 'arel/engines/sql/relations/utilities/externalization' +require 'arel/engines/sql/relations/utilities/nil' require 'arel/engines/sql/relations/relation' -require 'arel/engines/sql/relations/operations' -require 'arel/engines/sql/relations/writes' -require 'arel/engines/sql/relations/table' \ No newline at end of file +require 'arel/engines/sql/relations/table' +require 'arel/engines/sql/relations/operations/join' +require 'arel/engines/sql/relations/operations/alias' +require 'arel/engines/sql/relations/writes/delete' +require 'arel/engines/sql/relations/writes/insert' +require 'arel/engines/sql/relations/writes/update' \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/operations.rb b/lib/arel/engines/sql/relations/operations.rb deleted file mode 100644 index ff33fc6bc3..0000000000 --- a/lib/arel/engines/sql/relations/operations.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'arel/engines/sql/relations/operations/alias' -require 'arel/engines/sql/relations/operations/join' diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 0433abbbb2..2653744149 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -34,3 +34,8 @@ module Arel end end end + +def Table(name, engine = Arel::Table.engine) + Arel::Table.new(name, engine) +end + diff --git a/lib/arel/engines/sql/relations/utilities.rb b/lib/arel/engines/sql/relations/utilities.rb deleted file mode 100644 index a1451ed448..0000000000 --- a/lib/arel/engines/sql/relations/utilities.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/engines/sql/relations/utilities/recursion' -require 'arel/engines/sql/relations/utilities/externalization' -require 'arel/engines/sql/relations/utilities/nil' diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb deleted file mode 100644 index dcadc326d9..0000000000 --- a/lib/arel/engines/sql/relations/writes.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/engines/sql/relations/writes/delete' -require 'arel/engines/sql/relations/writes/insert' -require 'arel/engines/sql/relations/writes/update' diff --git a/lib/arel/engines/sql/sql.rb b/lib/arel/engines/sql/sql.rb deleted file mode 100644 index aed1fd861e..0000000000 --- a/lib/arel/engines/sql/sql.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'arel/engines/sql/engine' -require 'arel/engines/sql/relations' -require 'arel/engines/sql/primitives' -require 'arel/engines/sql/predicates' -require 'arel/engines/sql/formatters' -require 'arel/engines/sql/extensions' -require 'arel/engines/sql/christener' \ No newline at end of file diff --git a/lib/arel/extensions.rb b/lib/arel/extensions.rb deleted file mode 100644 index 299ba0631c..0000000000 --- a/lib/arel/extensions.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/extensions/object' -require 'arel/extensions/class' -require 'arel/extensions/array' -require 'arel/extensions/hash' diff --git a/lib/arel/extensions/array.rb b/lib/arel/extensions/array.rb deleted file mode 100644 index 5b6d6d6abd..0000000000 --- a/lib/arel/extensions/array.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Array - def to_hash - Hash[*flatten] - end -end \ No newline at end of file diff --git a/lib/arel/extensions/class.rb b/lib/arel/extensions/class.rb deleted file mode 100644 index f37898e7d7..0000000000 --- a/lib/arel/extensions/class.rb +++ /dev/null @@ -1,37 +0,0 @@ -class Class - def attributes(*attrs) - @attributes = attrs - attr_reader *attrs - end - - def deriving(*methods) - methods.each { |m| derive m } - end - - def derive(method_name) - methods = { - :initialize => " - def #{method_name}(#{@attributes.join(',')}) - #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} - end - ", - :== => " - def ==(other) - #{name} === other && - #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} - end - " - } - class_eval methods[method_name], __FILE__, __LINE__ - end - - def hash_on(delegatee) - define_method :eql? do |other| - self == other - end - - define_method :hash do - @hash ||= delegatee.hash - end - end -end \ No newline at end of file diff --git a/lib/arel/extensions/hash.rb b/lib/arel/extensions/hash.rb deleted file mode 100644 index 7472b5aa73..0000000000 --- a/lib/arel/extensions/hash.rb +++ /dev/null @@ -1,7 +0,0 @@ -class Hash - def bind(relation) - inject({}) do |bound, (key, value)| - bound.merge(key.bind(relation) => value.bind(relation)) - end - end -end \ No newline at end of file diff --git a/lib/arel/extensions/object.rb b/lib/arel/extensions/object.rb deleted file mode 100644 index d626407dcb..0000000000 --- a/lib/arel/extensions/object.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Object - def bind(relation) - Arel::Value.new(self, relation) - end - - def find_correlate_in(relation) - bind(relation) - end - - def metaclass - class << self - self - end - end -end diff --git a/lib/arel/predicates.rb b/lib/arel/predicates.rb deleted file mode 100644 index aa206d4e96..0000000000 --- a/lib/arel/predicates.rb +++ /dev/null @@ -1,66 +0,0 @@ -module Arel - class Predicate - def or(other_predicate) - Or.new(self, other_predicate) - end - - def and(other_predicate) - And.new(self, other_predicate) - end - end - - class Binary < Predicate - attributes :operand1, :operand2 - deriving :initialize - - def ==(other) - self.class === other and - @operand1 == other.operand1 and - @operand2 == other.operand2 - end - - def bind(relation) - self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation)) - end - end - - class CompoundPredicate < Binary - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" - end - end - - class Or < CompoundPredicate - def predicate_sql; "OR" end - end - - class And < CompoundPredicate - def predicate_sql; "AND" end - end - - class Equality < Binary - def ==(other) - Equality === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) - end - end - - class GreaterThanOrEqualTo < Binary - end - - class GreaterThan < Binary - end - - class LessThanOrEqualTo < Binary - end - - class LessThan < Binary - end - - class Match < Binary - end - - class In < Binary - end -end diff --git a/lib/arel/primitives.rb b/lib/arel/primitives.rb deleted file mode 100644 index d84713d3d5..0000000000 --- a/lib/arel/primitives.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/primitives/attribute' -require 'arel/primitives/value' -require 'arel/primitives/expression' - diff --git a/lib/arel/primitives/attribute.rb b/lib/arel/primitives/attribute.rb deleted file mode 100644 index 5e216770e4..0000000000 --- a/lib/arel/primitives/attribute.rb +++ /dev/null @@ -1,133 +0,0 @@ -require 'set' - -module Arel - class Attribute - attributes :relation, :name, :alias, :ancestor - deriving :== - delegate :engine, :christener, :to => :relation - - def initialize(relation, name, options = {}) - @relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor] - end - - def named?(hypothetical_name) - (@alias || name).to_s == hypothetical_name.to_s - end - - def aggregation? - false - end - - module Transformations - def self.included(klass) - klass.send :alias_method, :eql?, :== - end - - def hash - @hash ||= history.size + name.hash + relation.hash - end - - def as(aliaz = nil) - Attribute.new(relation, name, :alias => aliaz, :ancestor => self) - end - - def bind(new_relation) - relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) - end - - def to_attribute - self - end - end - include Transformations - - module Congruence - def history - @history ||= [self] + (ancestor ? ancestor.history : []) - end - - def join? - relation.join? - end - - def root - history.last - end - - def original_relation - @original_relation ||= original_attribute.relation - end - - def original_attribute - @original_attribute ||= history.detect { |a| !a.join? } - end - - def find_correlate_in(relation) - relation[self] || self - end - - def descends_from?(other) - history.include?(other) - end - - def /(other) - other ? (history & other.history).size : 0 - end - end - include Congruence - - module Predications - def eq(other) - Equality.new(self, other) - end - - def lt(other) - LessThan.new(self, other) - end - - def lteq(other) - LessThanOrEqualTo.new(self, other) - end - - def gt(other) - GreaterThan.new(self, other) - end - - def gteq(other) - GreaterThanOrEqualTo.new(self, other) - end - - def matches(regexp) - Match.new(self, regexp) - end - - def in(array) - In.new(self, array) - end - end - include Predications - - module Expressions - def count(distinct = false) - distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT") - end - - def sum - Expression.new(self, "SUM") - end - - def maximum - Expression.new(self, "MAX") - end - - def minimum - Expression.new(self, "MIN") - end - - def average - Expression.new(self, "AVG") - end - end - include Expressions - end -end diff --git a/lib/arel/primitives/expression.rb b/lib/arel/primitives/expression.rb deleted file mode 100644 index b67a5e1f8e..0000000000 --- a/lib/arel/primitives/expression.rb +++ /dev/null @@ -1,31 +0,0 @@ -module Arel - class Expression < Attribute - attributes :attribute, :function_sql, :alias, :ancestor - deriving :== - delegate :relation, :to => :attribute - alias_method :name, :alias - - def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) - @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor - end - - def aggregation? - true - end - - module Transformations - def as(aliaz) - Expression.new(attribute, function_sql, aliaz, self) - end - - def bind(new_relation) - new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) - end - - def to_attribute - Attribute.new(relation, @alias, :ancestor => self) - end - end - include Transformations - end -end diff --git a/lib/arel/primitives/value.rb b/lib/arel/primitives/value.rb deleted file mode 100644 index 91c4045507..0000000000 --- a/lib/arel/primitives/value.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Value - attributes :value, :relation - deriving :initialize, :== - delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value - - def bind(relation) - Value.new(value, relation) - end - - def aggregation? - false - end - - def to_attribute - value - end - end -end diff --git a/lib/arel/relations.rb b/lib/arel/relations.rb deleted file mode 100644 index f97c35e56e..0000000000 --- a/lib/arel/relations.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'arel/relations/relation' -require 'arel/relations/utilities' -require 'arel/relations/writes' -require 'arel/relations/operations' \ No newline at end of file diff --git a/lib/arel/relations/operations.rb b/lib/arel/relations/operations.rb deleted file mode 100644 index c598c7fcc9..0000000000 --- a/lib/arel/relations/operations.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'arel/relations/operations/alias' -require 'arel/relations/operations/group' -require 'arel/relations/operations/join' -require 'arel/relations/operations/order' -require 'arel/relations/operations/project' -require 'arel/relations/operations/where' -require 'arel/relations/operations/skip' -require 'arel/relations/operations/take' \ No newline at end of file diff --git a/lib/arel/relations/operations/alias.rb b/lib/arel/relations/operations/alias.rb deleted file mode 100644 index 67837f6a75..0000000000 --- a/lib/arel/relations/operations/alias.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Alias < Compound - attributes :relation - deriving :initialize - alias_method :==, :equal? - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/group.rb b/lib/arel/relations/operations/group.rb deleted file mode 100644 index 04fd9fea62..0000000000 --- a/lib/arel/relations/operations/group.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Arel - class Group < Compound - attributes :relation, :groupings - deriving :== - - def initialize(relation, *groupings, &block) - @relation = relation - @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) } - end - - def externalizable? - true - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/join.rb b/lib/arel/relations/operations/join.rb deleted file mode 100644 index 8e19254378..0000000000 --- a/lib/arel/relations/operations/join.rb +++ /dev/null @@ -1,41 +0,0 @@ -module Arel - class Join < Relation - attributes :join_sql, :relation1, :relation2, :predicates - deriving :== - delegate :engine, :name, :to => :relation1 - hash_on :relation1 - - def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates - end - - def attributes - @attributes ||= (relation1.externalize.attributes + - relation2.externalize.attributes).collect { |a| a.bind(self) } - end - - def wheres - # TESTME bind to self? - relation1.externalize.wheres - end - - def ons - @ons ||= @predicates.collect { |p| p.bind(self) } - end - - # TESTME - def externalizable? - relation1.externalizable? or relation2.externalizable? - end - - def join? - true - end - end - - class Relation - def join? - false - end - end -end diff --git a/lib/arel/relations/operations/order.rb b/lib/arel/relations/operations/order.rb deleted file mode 100644 index 05af3fde4d..0000000000 --- a/lib/arel/relations/operations/order.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Arel - class Order < Compound - attributes :relation, :orderings - deriving :== - - def initialize(relation, *orderings, &block) - @relation = relation - @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) } - end - - # TESTME - def orders - (orderings + relation.orders).collect { |o| o.bind(self) } - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/project.rb b/lib/arel/relations/operations/project.rb deleted file mode 100644 index 5507ea3163..0000000000 --- a/lib/arel/relations/operations/project.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Arel - class Project < Compound - attributes :relation, :projections - deriving :== - - def initialize(relation, *projections, &block) - @relation = relation - @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } - end - - def attributes - @attributes ||= projections.collect { |p| p.bind(self) } - end - - def externalizable? - attributes.any?(&:aggregation?) or relation.externalizable? - end - end -end diff --git a/lib/arel/relations/operations/skip.rb b/lib/arel/relations/operations/skip.rb deleted file mode 100644 index 930e4c94ea..0000000000 --- a/lib/arel/relations/operations/skip.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Skip < Compound - attributes :relation, :skipped - deriving :initialize, :== - - def externalizable? - true - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/take.rb b/lib/arel/relations/operations/take.rb deleted file mode 100644 index 2fd3fdf635..0000000000 --- a/lib/arel/relations/operations/take.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Take < Compound - attributes :relation, :taken - deriving :initialize, :== - - def externalizable? - true - end - end -end \ No newline at end of file diff --git a/lib/arel/relations/operations/where.rb b/lib/arel/relations/operations/where.rb deleted file mode 100644 index 608aaeb4b7..0000000000 --- a/lib/arel/relations/operations/where.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Arel - class Where < Compound - attributes :relation, :predicate - deriving :== - - def initialize(relation, *predicates, &block) - predicate = block_given?? yield(relation) : predicates.shift - @relation = predicates.empty?? relation : Where.new(relation, *predicates) - @predicate = predicate.bind(@relation) - end - - def wheres - @wheres ||= (relation.wheres + [predicate]).collect { |p| p.bind(self) } - end - end -end diff --git a/lib/arel/relations/relation.rb b/lib/arel/relations/relation.rb deleted file mode 100644 index 20badaf165..0000000000 --- a/lib/arel/relations/relation.rb +++ /dev/null @@ -1,134 +0,0 @@ -module Arel - class Relation - attr_reader :count - - def session - Session.new - end - - def call - engine.read(self) - end - - def bind(relation) - self - end - - def root - self - end - - module Enumerable - include ::Enumerable - - def each(&block) - session.read(self).each(&block) - end - - def first - session.read(self).first - end - end - include Enumerable - - module Operable - def join(other_relation = nil, join_type = "INNER JOIN") - case other_relation - when String - Join.new(other_relation, self) - when Relation - JoinOperation.new(join_type, self, other_relation) - else - self - end - end - - def outer_join(other_relation = nil) - join(other_relation, "LEFT OUTER JOIN") - end - - [:where, :project, :order, :take, :skip, :group].each do |operation_name| - operation = <<-OPERATION - def #{operation_name}(*arguments, &block) - arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) - end - OPERATION - class_eval operation, __FILE__, __LINE__ - end - - def alias - Alias.new(self) - end - - module Writable - def insert(record) - session.create Insert.new(self, record); self - end - - def update(assignments) - session.update Update.new(self, assignments) - end - - def delete - session.delete Deletion.new(self) - end - end - include Writable - - JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do - def on(*predicates) - Join.new(join_sql, relation1, relation2, *predicates) - end - end - end - include Operable - - module AttributeAccessable - def [](index) - case index - when Symbol, String - find_attribute_matching_name(index) - when Attribute, Expression - find_attribute_matching_attribute(index) - when Array - index.collect { |i| self[i] } - end - end - - def find_attribute_matching_name(name) - attributes.detect { |a| a.named?(name) } - end - - def find_attribute_matching_attribute(attribute) - matching_attributes(attribute).max do |a1, a2| - (a1.original_attribute / attribute) <=> (a2.original_attribute / attribute) - end - end - - private - def matching_attributes(attribute) - (@matching_attributes ||= attributes.inject({}) do |hash, a| - (hash[a.root] ||= []) << a - hash - end)[attribute.root] || [] - end - - def has_attribute?(attribute) - !matching_attributes(attribute).empty? - end - end - include AttributeAccessable - - module DefaultOperations - def attributes; [] end - def wheres; [] end - def orders; [] end - def inserts; [] end - def groupings; [] end - def joins(formatter = nil); nil end # FIXME - def taken; nil end - def skipped; nil end - end - include DefaultOperations - end -end diff --git a/lib/arel/relations/utilities.rb b/lib/arel/relations/utilities.rb deleted file mode 100644 index fbd949ef0c..0000000000 --- a/lib/arel/relations/utilities.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/relations/utilities/compound' -require 'arel/relations/utilities/nil' -require 'arel/relations/utilities/externalization' diff --git a/lib/arel/relations/utilities/compound.rb b/lib/arel/relations/utilities/compound.rb deleted file mode 100644 index b1e8054d4d..0000000000 --- a/lib/arel/relations/utilities/compound.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Arel - class Compound < Relation - attr_reader :relation - hash_on :relation - delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :table, :table_sql, - :to => :relation - - [:attributes, :wheres, :groupings, :orders].each do |operation_name| - operation = <<-OPERATION - def #{operation_name} - @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } - end - OPERATION - class_eval operation, __FILE__, __LINE__ - end - end -end diff --git a/lib/arel/relations/utilities/externalization.rb b/lib/arel/relations/utilities/externalization.rb deleted file mode 100644 index bd067f2304..0000000000 --- a/lib/arel/relations/utilities/externalization.rb +++ /dev/null @@ -1,24 +0,0 @@ -module Arel - class Externalization < Compound - attributes :relation - deriving :initialize, :== - - def wheres - [] - end - - def attributes - @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } - end - end - - class Relation - def externalize - @externalized ||= externalizable?? Externalization.new(self) : self - end - - def externalizable? - false - end - end -end diff --git a/lib/arel/relations/utilities/nil.rb b/lib/arel/relations/utilities/nil.rb deleted file mode 100644 index 6a9d678c45..0000000000 --- a/lib/arel/relations/utilities/nil.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'singleton' - -module Arel - class Nil < Relation - include Singleton - end -end diff --git a/lib/arel/relations/writes.rb b/lib/arel/relations/writes.rb deleted file mode 100644 index 1495d9c857..0000000000 --- a/lib/arel/relations/writes.rb +++ /dev/null @@ -1,3 +0,0 @@ -require 'arel/relations/writes/delete' -require 'arel/relations/writes/update' -require 'arel/relations/writes/insert' \ No newline at end of file diff --git a/lib/arel/relations/writes/delete.rb b/lib/arel/relations/writes/delete.rb deleted file mode 100644 index a94067c7fa..0000000000 --- a/lib/arel/relations/writes/delete.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Deletion < Compound - attributes :relation - deriving :initialize, :== - - def call - engine.delete(self) - end - end -end diff --git a/lib/arel/relations/writes/insert.rb b/lib/arel/relations/writes/insert.rb deleted file mode 100644 index 6d85e9769a..0000000000 --- a/lib/arel/relations/writes/insert.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Insert < Compound - attributes :relation, :record - deriving :== - - def initialize(relation, record) - @relation, @record = relation, record.bind(relation) - end - - def call - engine.create(self) - end - end -end diff --git a/lib/arel/relations/writes/update.rb b/lib/arel/relations/writes/update.rb deleted file mode 100644 index e647218a80..0000000000 --- a/lib/arel/relations/writes/update.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Update < Compound - attributes :relation, :assignments - deriving :== - - def initialize(relation, assignments) - @relation, @assignments = relation, assignments - end - - def call - engine.update(self) - end - end -end diff --git a/lib/arel/session.rb b/lib/arel/session.rb index 9c2ddc535b..cf04e8a93a 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -1,5 +1,3 @@ -require 'singleton' - module Arel class Session class << self diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb index fbac723e10..ffd6498749 100644 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ b/spec/arel/integration/joins/with_adjacency_spec.rb @@ -3,7 +3,7 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel describe Join do before do - @relation1 = Arel(:users) + @relation1 = Table(:users) @relation2 = @relation1.alias @predicate = @relation1[:id].eq(@relation2[:id]) end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb index 41978c0a5a..4aba005d51 100644 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ b/spec/arel/integration/joins/with_aggregations_spec.rb @@ -3,8 +3,8 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel describe Join do before do - @relation1 = Arel(:users) - @relation2 = Arel(:photos) + @relation1 = Table(:users) + @relation2 = Table(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb index 7582c5fc83..41f04349b8 100644 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ b/spec/arel/integration/joins/with_compounds_spec.rb @@ -3,8 +3,8 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel describe Join do before do - @relation1 = Arel(:users) - @relation2 = Arel(:photos) + @relation1 = Table(:users) + @relation2 = Table(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb index 1330f0f205..c90843cd7d 100644 --- a/spec/arel/unit/relations/array_spec.rb +++ b/spec/arel/unit/relations/array_spec.rb @@ -22,6 +22,13 @@ module Arel { @relation[:id] => 3 } ] end + + it '' do + @relation.where(@relation[:id].lt(3)).call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 } + ] + end end end end \ No newline at end of file -- cgit v1.2.3 From b0a45d52fdb7d8ce564f4dc2013bc790f98f1da3 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:38:09 -0400 Subject: consolidated files Conflicts: lib/arel/algebra/predicates.rb lib/arel/algebra/relations/writes/delete.rb lib/arel/algebra/relations/writes/insert.rb lib/arel/algebra/relations/writes/update.rb lib/arel/engines/memory/predicates.rb lib/arel/engines/memory/relations.rb lib/arel/engines/sql/primitives/attribute.rb lib/arel/engines/sql/relations/writes/insert.rb lib/arel/engines/sql/relations/writes/update.rb --- lib/arel/algebra/predicates.rb | 30 ++++++++---------- lib/arel/algebra/relations.rb | 4 +-- lib/arel/algebra/relations/writes.rb | 36 ++++++++++++++++++++++ lib/arel/algebra/relations/writes/delete.rb | 10 ------ lib/arel/algebra/relations/writes/insert.rb | 14 --------- lib/arel/algebra/relations/writes/update.rb | 14 --------- lib/arel/engines/memory/predicates.rb | 14 --------- lib/arel/engines/memory/primitives.rb | 15 +++++++-- lib/arel/engines/memory/primitives/attribute.rb | 7 ----- lib/arel/engines/memory/primitives/value.rb | 7 ----- lib/arel/engines/memory/relations.rb | 3 +- lib/arel/engines/memory/relations/operations.rb | 7 +++++ .../engines/memory/relations/operations/where.rb | 7 ----- lib/arel/engines/sql/primitives.rb | 34 ++++++++++++++++++-- lib/arel/engines/sql/primitives/attribute.rb | 15 --------- lib/arel/engines/sql/primitives/expression.rb | 7 ----- lib/arel/engines/sql/primitives/value.rb | 11 ------- lib/arel/engines/sql/relations.rb | 4 +-- lib/arel/engines/sql/relations/writes.rb | 36 ++++++++++++++++++++++ lib/arel/engines/sql/relations/writes/delete.rb | 12 -------- lib/arel/engines/sql/relations/writes/insert.rb | 12 -------- lib/arel/engines/sql/relations/writes/update.rb | 14 --------- spec/arel/unit/relations/table_spec.rb | 4 +-- 23 files changed, 142 insertions(+), 175 deletions(-) create mode 100644 lib/arel/algebra/relations/writes.rb delete mode 100644 lib/arel/algebra/relations/writes/delete.rb delete mode 100644 lib/arel/algebra/relations/writes/insert.rb delete mode 100644 lib/arel/algebra/relations/writes/update.rb delete mode 100644 lib/arel/engines/memory/primitives/attribute.rb delete mode 100644 lib/arel/engines/memory/primitives/value.rb create mode 100644 lib/arel/engines/memory/relations/operations.rb delete mode 100644 lib/arel/engines/memory/relations/operations/where.rb delete mode 100644 lib/arel/engines/sql/primitives/attribute.rb delete mode 100644 lib/arel/engines/sql/primitives/expression.rb delete mode 100644 lib/arel/engines/sql/primitives/value.rb create mode 100644 lib/arel/engines/sql/relations/writes.rb delete mode 100644 lib/arel/engines/sql/relations/writes/delete.rb delete mode 100644 lib/arel/engines/sql/relations/writes/insert.rb delete mode 100644 lib/arel/engines/sql/relations/writes/update.rb diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index f83101306e..7f093ded6d 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -1,5 +1,12 @@ module Arel class Predicate + def or(other_predicate) + Or.new(self, other_predicate) + end + + def and(other_predicate) + And.new(self, other_predicate) + end end class Binary < Predicate @@ -25,21 +32,10 @@ module Arel end end - class GreaterThanOrEqualTo < Binary - end - - class GreaterThan < Binary - end - - class LessThanOrEqualTo < Binary - end - - class LessThan < Binary - end - - class Match < Binary - end - - class In < Binary - end + class GreaterThanOrEqualTo < Binary; end + class GreaterThan < Binary; end + class LessThanOrEqualTo < Binary; end + class LessThan < Binary; end + class Match < Binary; end + class In < Binary; end end \ No newline at end of file diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index 03f04d2459..b75a31e5e3 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -2,9 +2,7 @@ require 'arel/algebra/relations/relation' require 'arel/algebra/relations/utilities/compound' require 'arel/algebra/relations/utilities/nil' require 'arel/algebra/relations/utilities/externalization' -require 'arel/algebra/relations/writes/delete' -require 'arel/algebra/relations/writes/update' -require 'arel/algebra/relations/writes/insert' +require 'arel/algebra/relations/writes' require 'arel/algebra/relations/operations/alias' require 'arel/algebra/relations/operations/group' require 'arel/algebra/relations/operations/join' diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb new file mode 100644 index 0000000000..352f7bc7e5 --- /dev/null +++ b/lib/arel/algebra/relations/writes.rb @@ -0,0 +1,36 @@ +module Arel + class Deletion < Compound + attributes :relation + deriving :initialize, :== + + def call + engine.delete(self) + end + end + + class Insert < Compound + attributes :relation, :record + deriving :== + + def initialize(relation, record) + @relation, @record = relation, record.bind(relation) + end + + def call + engine.create(self) + end + end + + class Update < Compound + attributes :relation, :assignments + deriving :== + + def initialize(relation, assignments) + @relation, @assignments = relation, assignments.bind(relation) + end + + def call + engine.update(self) + end + end +end \ No newline at end of file diff --git a/lib/arel/algebra/relations/writes/delete.rb b/lib/arel/algebra/relations/writes/delete.rb deleted file mode 100644 index a94067c7fa..0000000000 --- a/lib/arel/algebra/relations/writes/delete.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Arel - class Deletion < Compound - attributes :relation - deriving :initialize, :== - - def call - engine.delete(self) - end - end -end diff --git a/lib/arel/algebra/relations/writes/insert.rb b/lib/arel/algebra/relations/writes/insert.rb deleted file mode 100644 index 6d85e9769a..0000000000 --- a/lib/arel/algebra/relations/writes/insert.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Insert < Compound - attributes :relation, :record - deriving :== - - def initialize(relation, record) - @relation, @record = relation, record.bind(relation) - end - - def call - engine.create(self) - end - end -end diff --git a/lib/arel/algebra/relations/writes/update.rb b/lib/arel/algebra/relations/writes/update.rb deleted file mode 100644 index e647218a80..0000000000 --- a/lib/arel/algebra/relations/writes/update.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Update < Compound - attributes :relation, :assignments - deriving :== - - def initialize(relation, assignments) - @relation, @assignments = relation, assignments - end - - def call - engine.update(self) - end - end -end diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index 3522ea3ffa..bbf39ba794 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -1,13 +1,4 @@ module Arel - class Predicate - def or(other_predicate) - Or.new(self, other_predicate) - end - - def and(other_predicate) - And.new(self, other_predicate) - end - end class Binary < Predicate def eval(row) @@ -30,11 +21,6 @@ module Arel end class Equality < Binary - def ==(other) - Equality === other and - ((operand1 == other.operand1 and operand2 == other.operand2) or - (operand1 == other.operand2 and operand2 == other.operand1)) - end end class GreaterThanOrEqualTo < Binary diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index 4d5c76e956..77d4c1a52c 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -1,2 +1,13 @@ -require 'arel/engines/memory/primitives/attribute' -require 'arel/engines/memory/primitives/value' +module Arel + class Attribute + def eval(row) + row[self] + end + end + + class Value + def eval(row) + value + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives/attribute.rb b/lib/arel/engines/memory/primitives/attribute.rb deleted file mode 100644 index 9864feadc2..0000000000 --- a/lib/arel/engines/memory/primitives/attribute.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Attribute - def eval(row) - row[self] - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives/value.rb b/lib/arel/engines/memory/primitives/value.rb deleted file mode 100644 index b83cd02e57..0000000000 --- a/lib/arel/engines/memory/primitives/value.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Value - def eval(row) - value - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 6361d7c9d7..9f8264c439 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,2 +1,3 @@ require 'arel/engines/memory/relations/array' -require 'arel/engines/memory/relations/operations/where' +require 'arel/engines/memory/relations/operations' + diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb new file mode 100644 index 0000000000..eb11fb55fd --- /dev/null +++ b/lib/arel/engines/memory/relations/operations.rb @@ -0,0 +1,7 @@ +module Arel + class Where < Compound + def eval + relation.eval.select { |row| predicate.eval(row) } + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations/operations/where.rb b/lib/arel/engines/memory/relations/operations/where.rb deleted file mode 100644 index eb11fb55fd..0000000000 --- a/lib/arel/engines/memory/relations/operations/where.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Where < Compound - def eval - relation.eval.select { |row| predicate.eval(row) } - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 405b1ca803..5544d63710 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -1,3 +1,31 @@ -require 'arel/engines/sql/primitives/attribute' -require 'arel/engines/sql/primitives/value' -require 'arel/engines/sql/primitives/expression' \ No newline at end of file +module Arel + class Attribute + def column + original_relation.column_for(self) + end + + def format(object) + object.to_sql(Sql::Attribute.new(self)) + end + + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.attribute self + end + end + + class Expression < Attribute + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + end + + class Value + def to_sql(formatter = Sql::WhereCondition.new(relation)) + formatter.value value + end + + def format(object) + object.to_sql(Sql::Value.new(relation)) + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/attribute.rb b/lib/arel/engines/sql/primitives/attribute.rb deleted file mode 100644 index ad78a9ec5b..0000000000 --- a/lib/arel/engines/sql/primitives/attribute.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Arel - class Attribute - def column - original_relation.column_for(self) - end - - def format(object) - object.to_sql(Sql::Attribute.new(self)) - end - - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.attribute self - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/expression.rb b/lib/arel/engines/sql/primitives/expression.rb deleted file mode 100644 index 24f6879848..0000000000 --- a/lib/arel/engines/sql/primitives/expression.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Expression < Attribute - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/primitives/value.rb b/lib/arel/engines/sql/primitives/value.rb deleted file mode 100644 index a44acc26e0..0000000000 --- a/lib/arel/engines/sql/primitives/value.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Arel - class Value - def to_sql(formatter = Sql::WhereCondition.new(relation)) - formatter.value value - end - - def format(object) - object.to_sql(Sql::Value.new(relation)) - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 39ef8852a1..d6e4d295ba 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -5,6 +5,4 @@ require 'arel/engines/sql/relations/relation' require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' require 'arel/engines/sql/relations/operations/alias' -require 'arel/engines/sql/relations/writes/delete' -require 'arel/engines/sql/relations/writes/insert' -require 'arel/engines/sql/relations/writes/update' \ No newline at end of file +require 'arel/engines/sql/relations/writes' \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb new file mode 100644 index 0000000000..edfd9f7233 --- /dev/null +++ b/lib/arel/engines/sql/relations/writes.rb @@ -0,0 +1,36 @@ +module Arel + class Deletion < Compound + def to_sql(formatter = nil) + [ + "DELETE", + "FROM #{table_sql}", + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ].compact.join("\n") + end + end + + class Insert < Compound + def to_sql(formatter = nil) + [ + "INSERT", + "INTO #{table_sql}", + "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", + "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" + ].join("\n") + end + end + + class Update < Compound + def to_sql(formatter = nil) + [ + "UPDATE #{table_sql} SET", + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n"), + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) + ].join("\n") + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/delete.rb b/lib/arel/engines/sql/relations/writes/delete.rb deleted file mode 100644 index b22ee51e24..0000000000 --- a/lib/arel/engines/sql/relations/writes/delete.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Arel - class Deletion < Compound - def to_sql(formatter = nil) - [ - "DELETE", - "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/insert.rb b/lib/arel/engines/sql/relations/writes/insert.rb deleted file mode 100644 index aac9c87a5b..0000000000 --- a/lib/arel/engines/sql/relations/writes/insert.rb +++ /dev/null @@ -1,12 +0,0 @@ -module Arel - class Insert < Compound - def to_sql(formatter = nil) - [ - "INSERT", - "INTO #{table_sql}", - "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", - "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" - ].join("\n") - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/relations/writes/update.rb b/lib/arel/engines/sql/relations/writes/update.rb deleted file mode 100644 index 3e35a0d5cc..0000000000 --- a/lib/arel/engines/sql/relations/writes/update.rb +++ /dev/null @@ -1,14 +0,0 @@ -module Arel - class Update < Compound - def to_sql(formatter = nil) - [ - "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb index 211e6921f8..2779c0fe5d 100644 --- a/spec/arel/unit/relations/table_spec.rb +++ b/spec/arel/unit/relations/table_spec.rb @@ -73,14 +73,14 @@ module Arel describe '#reset' do it "reloads columns from the database" do lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } - lambda { @relation.reset }.should change { @relation.attributes } + lambda { @relation.reset }.should change { @relation.attributes } end end end describe 'hashing' do it "implements hash equality" do - Table.new(:users).should hash_the_same_as(Table.new(:users)) + Table.new(:users).should hash_the_same_as(Table.new(:users)) Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) end end -- cgit v1.2.3 From 892337509b2bd269920dc567bc48c6a28c7222d2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:46:08 -0400 Subject: removed function_sql in favor of polymorphism Conflicts: lib/arel/algebra/primitives/attribute.rb lib/arel/algebra/primitives/expression.rb spec/arel/unit/primitives/expression_spec.rb --- doc/TODO | 10 ++++++-- lib/arel/algebra/primitives/attribute.rb | 10 ++++---- lib/arel/algebra/primitives/expression.rb | 18 ++++++++++---- lib/arel/engines/sql/primitives.rb | 36 +++++++++++++++++++++++----- spec/arel/unit/primitives/attribute_spec.rb | 10 ++++---- spec/arel/unit/primitives/expression_spec.rb | 8 +++---- 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/doc/TODO b/doc/TODO index 8a8dcf5380..ebc469ad70 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,6 +1,13 @@ todo: - expressions should be class-based, and joins too, anything _sql should be renamed - refactor adapter pattern +- clean up block_given stuff +- reorganize sql tests +- audit unit coverage of algebra +- break out adapters into sep modules +- data objects +- remove all explicit aliasing +- blocks for joins - implement in memory adapter - implement mnesia adapter - joins become subselects in writes: @@ -11,10 +18,8 @@ users.delete().where( ) - rename externalize to derived. - and/or w/ predicates -- blocks for all operations - result sets to attr correlation too - cache expiry on write - - rewrite of arecord querycache test in light of this - transactions - scoped writes - asc/desc for orderings @@ -83,6 +88,7 @@ done: - rename select to where - rename all ion classes - joining with LIMIT is like aggregations!! +- blocks for non-joins icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 5e216770e4..943c5b030e 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -109,23 +109,23 @@ module Arel module Expressions def count(distinct = false) - distinct ? Expression.new(self, "DISTINCT").count : Expression.new(self, "COUNT") + distinct ? Distinct.new(self).count : Count.new(self) end def sum - Expression.new(self, "SUM") + Sum.new(self) end def maximum - Expression.new(self, "MAX") + Maximum.new(self) end def minimum - Expression.new(self, "MIN") + Minimum.new(self) end def average - Expression.new(self, "AVG") + Average.new(self) end end include Expressions diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb index b67a5e1f8e..989397720c 100644 --- a/lib/arel/algebra/primitives/expression.rb +++ b/lib/arel/algebra/primitives/expression.rb @@ -1,12 +1,12 @@ module Arel class Expression < Attribute - attributes :attribute, :function_sql, :alias, :ancestor + attributes :attribute, :alias, :ancestor deriving :== delegate :relation, :to => :attribute alias_method :name, :alias - def initialize(attribute, function_sql, aliaz = nil, ancestor = nil) - @attribute, @function_sql, @alias, @ancestor = attribute, function_sql, aliaz, ancestor + def initialize(attribute, aliaz = nil, ancestor = nil) + @attribute, @alias, @ancestor = attribute, aliaz, ancestor end def aggregation? @@ -15,11 +15,11 @@ module Arel module Transformations def as(aliaz) - Expression.new(attribute, function_sql, aliaz, self) + self.class.new(attribute, aliaz, self) end def bind(new_relation) - new_relation == relation ? self : Expression.new(attribute.bind(new_relation), function_sql, @alias, self) + new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) end def to_attribute @@ -28,4 +28,12 @@ module Arel end include Transformations end + + class Count < Expression; end + class Distinct < Expression; end + class Sum < Expression; end + class Maximum < Expression; end + class Minimum < Expression; end + class Average < Expression; end end + diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 5544d63710..c4968558a2 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -13,12 +13,6 @@ module Arel end end - class Expression < Attribute - def to_sql(formatter = Sql::SelectClause.new(relation)) - formatter.expression self - end - end - class Value def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value @@ -28,4 +22,34 @@ module Arel object.to_sql(Sql::Value.new(relation)) end end + + class Expression < Attribute + def to_sql(formatter = Sql::SelectClause.new(relation)) + formatter.expression self + end + end + + class Count < Expression + def function_sql; 'COUNT' end + end + + class Distinct < Expression + def function_sql; 'DISTINCT' end + end + + class Sum < Expression + def function_sql; 'SUM' end + end + + class Maximum < Expression + def function_sql; 'MAX' end + end + + class Minimum < Expression + def function_sql; 'MIN' end + end + + class Average < Expression + def function_sql; 'AVG' end + end end \ No newline at end of file diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb index 6d0f146a39..e512b40ebf 100644 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ b/spec/arel/unit/primitives/attribute_spec.rb @@ -139,31 +139,31 @@ module Arel describe '#count' do it "manufactures a count Expression" do - @attribute.count.should == Expression.new(@attribute, "COUNT") + @attribute.count.should == Count.new(@attribute) end end describe '#sum' do it "manufactures a sum Expression" do - @attribute.sum.should == Expression.new(@attribute, "SUM") + @attribute.sum.should == Sum.new(@attribute) end end describe '#maximum' do it "manufactures a maximum Expression" do - @attribute.maximum.should == Expression.new(@attribute, "MAX") + @attribute.maximum.should == Maximum.new(@attribute) end end describe '#minimum' do it "manufactures a minimum Expression" do - @attribute.minimum.should == Expression.new(@attribute, "MIN") + @attribute.minimum.should == Minimum.new(@attribute) end end describe '#average' do it "manufactures an average Expression" do - @attribute.average.should == Expression.new(@attribute, "AVG") + @attribute.average.should == Average.new(@attribute) end end end diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb index ebde55ff90..92f300c4ee 100644 --- a/spec/arel/unit/primitives/expression_spec.rb +++ b/spec/arel/unit/primitives/expression_spec.rb @@ -9,13 +9,13 @@ module Arel describe Expression::Transformations do before do - @expression = Expression.new(@attribute, "COUNT") + @expression = Count.new(@attribute) end describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) - @expression.bind(derived_relation).should == Expression.new(@attribute.bind(derived_relation), "COUNT", nil, @expression) + @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) end it "returns self if the substituting to the same relation" do @@ -25,7 +25,7 @@ module Arel describe '#as' do it "manufactures an aliased expression" do - @expression.as(:alias).should == Expression.new(@attribute, "COUNT", :alias, @expression) + @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) end end @@ -38,7 +38,7 @@ module Arel describe '#to_sql' do it "manufactures sql with the expression and alias" do - sql = Expression.new(@attribute, "COUNT", :alias).to_sql + sql = Count.new(@attribute, :alias).to_sql adapter_is :mysql do sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) -- cgit v1.2.3 From 3a6e8e5a3f99841691b70b89b0a10f836e6ec071 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:49:56 -0400 Subject: join sql stuff moved into sql adapter Conflicts: lib/arel/algebra/primitives/value.rb lib/arel/algebra/relations/operations/join.rb lib/arel/algebra/relations/relation.rb spec/arel/unit/relations/join_spec.rb --- lib/arel/algebra/primitives/value.rb | 1 - lib/arel/algebra/relations/operations/join.rb | 14 +++++++++++--- lib/arel/algebra/relations/relation.rb | 15 +++++++-------- lib/arel/algebra/relations/utilities/compound.rb | 3 +-- lib/arel/engines/sql/primitives.rb | 18 ++++++++++-------- lib/arel/engines/sql/relations/operations/join.rb | 14 ++++++++++++++ spec/arel/unit/relations/join_spec.rb | 12 ++++++------ spec/arel/unit/relations/relation_spec.rb | 4 ++-- 8 files changed, 51 insertions(+), 30 deletions(-) diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/primitives/value.rb index 91c4045507..76c82890d0 100644 --- a/lib/arel/algebra/primitives/value.rb +++ b/lib/arel/algebra/primitives/value.rb @@ -2,7 +2,6 @@ module Arel class Value attributes :value, :relation deriving :initialize, :== - delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value def bind(relation) Value.new(value, relation) diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 8e19254378..695f360b51 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -1,12 +1,12 @@ module Arel class Join < Relation - attributes :join_sql, :relation1, :relation2, :predicates + attributes :relation1, :relation2, :predicates deriving :== delegate :engine, :name, :to => :relation1 hash_on :relation1 - def initialize(join_sql, relation1, relation2 = Nil.instance, *predicates) - @join_sql, @relation1, @relation2, @predicates = join_sql, relation1, relation2, predicates + def initialize(relation1, relation2 = Nil.instance, *predicates) + @relation1, @relation2, @predicates = relation1, relation2, predicates end def attributes @@ -33,6 +33,14 @@ module Arel end end + class InnerJoin < Join; end + class OuterJoin < Join; end + class StringJoin < Join + def attributes + relation1.externalize.attributes + end + end + class Relation def join? false diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 20badaf165..6d76e66638 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -32,28 +32,27 @@ module Arel include Enumerable module Operable - def join(other_relation = nil, join_type = "INNER JOIN") + def join(other_relation = nil, join_class = InnerJoin) case other_relation when String - Join.new(other_relation, self) + StringJoin.new(other_relation, self) when Relation - JoinOperation.new(join_type, self, other_relation) + JoinOperation.new(join_class, self, other_relation) else self end end def outer_join(other_relation = nil) - join(other_relation, "LEFT OUTER JOIN") + join(other_relation, OuterJoin) end [:where, :project, :order, :take, :skip, :group].each do |operation_name| - operation = <<-OPERATION + class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name}(*arguments, &block) arguments.all?(&:blank?) && !block_given?? self : #{operation_name.to_s.classify}.new(self, *arguments, &block) end OPERATION - class_eval operation, __FILE__, __LINE__ end def alias @@ -75,9 +74,9 @@ module Arel end include Writable - JoinOperation = Struct.new(:join_sql, :relation1, :relation2) do + JoinOperation = Struct.new(:join_class, :relation1, :relation2) do def on(*predicates) - Join.new(join_sql, relation1, relation2, *predicates) + join_class.new(relation1, relation2, *predicates) end end end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index e33b8dbf14..fbff36a868 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -7,12 +7,11 @@ module Arel :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| - operation = <<-OPERATION + class_eval <<-OPERATION, __FILE__, __LINE__ def #{operation_name} @#{operation_name} ||= relation.#{operation_name}.collect { |o| o.bind(self) } end OPERATION - class_eval operation, __FILE__, __LINE__ end end end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index c4968558a2..6f89723afe 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -3,7 +3,7 @@ module Arel def column original_relation.column_for(self) end - + def format(object) object.to_sql(Sql::Attribute.new(self)) end @@ -14,6 +14,8 @@ module Arel end class Value + delegate :inclusion_predicate_sql, :equality_predicate_sql, :to => :value + def to_sql(formatter = Sql::WhereCondition.new(relation)) formatter.value value end @@ -22,33 +24,33 @@ module Arel object.to_sql(Sql::Value.new(relation)) end end - + class Expression < Attribute def to_sql(formatter = Sql::SelectClause.new(relation)) formatter.expression self end end - + class Count < Expression def function_sql; 'COUNT' end end - + class Distinct < Expression def function_sql; 'DISTINCT' end end - + class Sum < Expression def function_sql; 'SUM' end end - + class Maximum < Expression def function_sql; 'MAX' end end - + class Minimum < Expression def function_sql; 'MIN' end end - + class Average < Expression def function_sql; 'AVG' end end diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index be21119bc9..2f5e23644e 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -16,4 +16,18 @@ module Arel end end end + + class InnerJoin < Join + def join_sql; "INNER JOIN" end + end + + class OuterJoin < Join + def join_sql; "OUTER JOIN" end + end + + class StringJoin < Join + def joins(_, __ = nil) + relation2 + end + end end \ No newline at end of file diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb index fa6bbbe216..0e3e6ef16b 100644 --- a/spec/arel/unit/relations/join_spec.rb +++ b/spec/arel/unit/relations/join_spec.rb @@ -10,20 +10,20 @@ module Arel describe 'hashing' do it 'implements hash equality' do - Join.new("INNER JOIN", @relation1, @relation2, @predicate) \ - .should hash_the_same_as(Join.new("INNER JOIN", @relation1, @relation2, @predicate)) + InnerJoin.new(@relation1, @relation2, @predicate) \ + .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) end end describe '#engine' do it "delegates to a relation's engine" do - Join.new("INNER JOIN", @relation1, @relation2, @predicate).engine.should == @relation1.engine + InnerJoin.new(@relation1, @relation2, @predicate).engine.should == @relation1.engine end end describe '#attributes' do it 'combines the attributes of the two relations' do - join = Join.new("INNER JOIN", @relation1, @relation2, @predicate) + join = InnerJoin.new(@relation1, @relation2, @predicate) join.attributes.should == (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } end @@ -32,7 +32,7 @@ module Arel describe '#to_sql' do describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do - sql = Join.new("INNER JOIN", @relation1, @relation2, @predicate).to_sql + sql = InnerJoin.new(@relation1, @relation2, @predicate).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -54,7 +54,7 @@ module Arel describe 'when joining with a string' do it "passes the string through to the where clause" do - sql = Join.new("INNER JOIN asdf ON fdsa", @relation1).to_sql + sql = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa").to_sql adapter_is :mysql do sql.should be_like(%Q{ diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb index 7df10be59c..6a61f39966 100644 --- a/spec/arel/unit/relations/relation_spec.rb +++ b/spec/arel/unit/relations/relation_spec.rb @@ -34,7 +34,7 @@ module Arel describe 'when given a relation' do it "manufactures an inner join operation between those two relations" do @relation.join(@relation).on(@predicate). \ - should == Join.new("INNER JOIN", @relation, @relation, @predicate) + should == InnerJoin.new(@relation, @relation, @predicate) end end @@ -54,7 +54,7 @@ module Arel describe '#outer_join' do it "manufactures a left outer join operation between those two relations" do @relation.outer_join(@relation).on(@predicate). \ - should == Join.new("LEFT OUTER JOIN", @relation, @relation, @predicate) + should == OuterJoin.new(@relation, @relation, @predicate) end end end -- cgit v1.2.3 From 437429764510338bdc5f4915286425f07565a573 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 26 May 2008 14:30:51 -0700 Subject: moved table-related stuff into sql engine --- lib/arel/algebra/relations/utilities/compound.rb | 2 +- lib/arel/engines/sql/relations.rb | 1 + lib/arel/engines/sql/relations/utilities/compound.rb | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 lib/arel/engines/sql/relations/utilities/compound.rb diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index fbff36a868..4d7cece812 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -3,7 +3,7 @@ module Arel attr_reader :relation hash_on :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :table, :table_sql, :array, + :column_for, :engine, :to => :relation [:attributes, :wheres, :groupings, :orders].each do |operation_name| diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index d6e4d295ba..0eb1303ec9 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -1,3 +1,4 @@ +require 'arel/engines/sql/relations/utilities/compound' require 'arel/engines/sql/relations/utilities/recursion' require 'arel/engines/sql/relations/utilities/externalization' require 'arel/engines/sql/relations/utilities/nil' diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb new file mode 100644 index 0000000000..502bf8b01e --- /dev/null +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -0,0 +1,6 @@ +module Arel + class Compound < Relation + delegate :table, :table_sql, :array, :to => :relation + end +end + \ No newline at end of file -- cgit v1.2.3 From 4e3c9a01307339916f6b947d24f19b0f442afd78 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:58:46 -0400 Subject: most in memory operations save join and group Conflicts: lib/arel/algebra/extensions/object.rb lib/arel/algebra/primitives/value.rb lib/arel/engines/memory/relations.rb lib/arel/engines/sql/formatters.rb lib/arel/engines/sql/primitives.rb spec/arel/unit/relations/alias_spec.rb spec/arel/unit/relations/array_spec.rb spec/arel/unit/relations/order_spec.rb --- doc/TODO | 8 ++- lib/arel/algebra/extensions/array.rb | 7 ++ lib/arel/algebra/extensions/hash.rb | 7 ++ lib/arel/algebra/extensions/object.rb | 5 ++ lib/arel/algebra/primitives.rb | 1 + lib/arel/algebra/primitives/attribute.rb | 17 +++++ lib/arel/algebra/primitives/ordering.rb | 18 ++++++ lib/arel/algebra/primitives/value.rb | 8 +-- lib/arel/algebra/relations/operations/order.rb | 3 +- lib/arel/engines/memory/primitives.rb | 14 ++++ lib/arel/engines/memory/relations.rb | 1 + lib/arel/engines/memory/relations/compound.rb | 5 ++ lib/arel/engines/memory/relations/operations.rb | 33 ++++++++++ lib/arel/engines/sql/formatters.rb | 6 +- lib/arel/engines/sql/primitives.rb | 14 ++++ .../engines/sql/relations/utilities/compound.rb | 2 +- spec/arel/unit/relations/alias_spec.rb | 4 +- spec/arel/unit/relations/array_spec.rb | 75 ++++++++++++++++++---- spec/arel/unit/relations/order_spec.rb | 12 ++-- 19 files changed, 208 insertions(+), 32 deletions(-) create mode 100644 lib/arel/algebra/primitives/ordering.rb create mode 100644 lib/arel/engines/memory/relations/compound.rb diff --git a/doc/TODO b/doc/TODO index ebc469ad70..dfbf09de9d 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,6 +1,9 @@ todo: -- expressions should be class-based, and joins too, anything _sql should be renamed +- projection is by definition distincting +- union/intersection - refactor adapter pattern +- result sets to attr correlation too + - result sets should be array relations - clean up block_given stuff - reorganize sql tests - audit unit coverage of algebra @@ -10,6 +13,7 @@ todo: - blocks for joins - implement in memory adapter - implement mnesia adapter +- test ordering - joins become subselects in writes: users.delete().where( addresses.c.user_id== @@ -18,7 +22,6 @@ users.delete().where( ) - rename externalize to derived. - and/or w/ predicates -- result sets to attr correlation too - cache expiry on write - transactions - scoped writes @@ -89,6 +92,7 @@ done: - rename all ion classes - joining with LIMIT is like aggregations!! - blocks for non-joins +- expressions should be class-based, and joins too, anything _sql should be renamed icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb index 5b6d6d6abd..935569a07b 100644 --- a/lib/arel/algebra/extensions/array.rb +++ b/lib/arel/algebra/extensions/array.rb @@ -2,4 +2,11 @@ class Array def to_hash Hash[*flatten] end + + def group_by + inject({}) do |groups, element| + (groups[yield(element)] ||= []) << element + groups + end + end end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 7472b5aa73..bc97785e62 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -4,4 +4,11 @@ class Hash bound.merge(key.bind(relation) => value.bind(relation)) end end + + def slice(*attributes) + inject({}) do |cheese, (key, value)| + cheese[key] = value if attributes.include?(key) + cheese + end + end end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index d626407dcb..efdbbf525f 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -12,4 +12,9 @@ class Object self end end + + def let + yield(self) + end end + diff --git a/lib/arel/algebra/primitives.rb b/lib/arel/algebra/primitives.rb index a4c3169e0b..df8d16a5d5 100644 --- a/lib/arel/algebra/primitives.rb +++ b/lib/arel/algebra/primitives.rb @@ -1,4 +1,5 @@ require 'arel/algebra/primitives/attribute' +require 'arel/algebra/primitives/ordering' require 'arel/algebra/primitives/value' require 'arel/algebra/primitives/expression' diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 943c5b030e..7a4411e248 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -17,6 +17,10 @@ module Arel def aggregation? false end + + def inspect + "" + end module Transformations def self.included(klass) @@ -129,5 +133,18 @@ module Arel end end include Expressions + + module Orderings + def asc + Ascending.new(self) + end + + def desc + Descending.new(self) + end + + alias_method :to_ordering, :asc + end + include Orderings end end diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb new file mode 100644 index 0000000000..e8d8f97188 --- /dev/null +++ b/lib/arel/algebra/primitives/ordering.rb @@ -0,0 +1,18 @@ +module Arel + class Ordering + attributes :attribute + deriving :initialize, :== + delegate :relation, :to => :attribute + + def bind(relation) + self.class.new(attribute.bind(relation)) + end + + def to_ordering + self + end + end + + class Ascending < Ordering; end + class Descending < Ordering; end +end \ No newline at end of file diff --git a/lib/arel/algebra/primitives/value.rb b/lib/arel/algebra/primitives/value.rb index 76c82890d0..e363805140 100644 --- a/lib/arel/algebra/primitives/value.rb +++ b/lib/arel/algebra/primitives/value.rb @@ -7,12 +7,8 @@ module Arel Value.new(value, relation) end - def aggregation? - false - end - - def to_attribute - value + def to_ordering + self end end end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 05af3fde4d..eccd8bcda0 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -10,7 +10,8 @@ module Arel # TESTME def orders - (orderings + relation.orders).collect { |o| o.bind(self) } + # QUESTION - do we still need relation.orders ? + (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } end end end \ No newline at end of file diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index 77d4c1a52c..f8bbcedb55 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -10,4 +10,18 @@ module Arel value end end + + class Ordering + def eval(row1, row2) + (attribute.eval(row1) <=> attribute.eval(row2)) * direction + end + end + + class Descending < Ordering + def direction; -1 end + end + + class Ascending < Ordering + def direction; 1 end + end end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 9f8264c439..1b009537b9 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,3 +1,4 @@ require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' +require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb new file mode 100644 index 0000000000..b029082d57 --- /dev/null +++ b/lib/arel/engines/memory/relations/compound.rb @@ -0,0 +1,5 @@ +module Arel + class Compound < Relation + delegate :array, :to => :relation + end +end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index eb11fb55fd..115df054df 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -4,4 +4,37 @@ module Arel relation.eval.select { |row| predicate.eval(row) } end end + + class Order < Compound + def eval + relation.eval.sort do |row1, row2| + ordering = orderings.detect { |o| o.eval(row1, row2) != 0 } || orderings.last + ordering.eval(row1, row2) + end + end + end + + class Project < Compound + def eval + relation.eval.collect { |r| r.slice(*projections) } + end + end + + class Take < Compound + def eval + relation.eval[0, taken] + end + end + + class Skip < Compound + def eval + relation.eval[skipped..-1] + end + end + + class Group < Compound + def eval + raise NotImplementedError + end + end end \ No newline at end of file diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index f82ddf631f..bc5f0f7c64 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -47,9 +47,9 @@ module Arel class WhereClause < PassThrough end - class OrderClause < PassThrough - def attribute(attribute) - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + class OrderClause < PassThrough + def ordering(ordering) + "#{quote_table_name(name_for(ordering.attribute.original_relation))}.#{quote_column_name(ordering.attribute.name)} #{ordering.direction_sql}" end end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 6f89723afe..9e9143ac0f 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -24,6 +24,20 @@ module Arel object.to_sql(Sql::Value.new(relation)) end end + + class Ordering + def to_sql(formatter = Sql::OrderClause.new(relation)) + formatter.ordering self + end + end + + class Ascending < Ordering + def direction_sql; 'ASC' end + end + + class Descending < Ordering + def direction_sql; 'DESC' end + end class Expression < Attribute def to_sql(formatter = Sql::SelectClause.new(relation)) diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index 502bf8b01e..61df196d6e 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -1,6 +1,6 @@ module Arel class Compound < Relation - delegate :table, :table_sql, :array, :to => :relation + delegate :table, :table_sql, :to => :relation end end \ No newline at end of file diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb index 570f315892..63c15cfeff 100644 --- a/spec/arel/unit/relations/alias_spec.rb +++ b/spec/arel/unit/relations/alias_spec.rb @@ -30,7 +30,7 @@ module Arel FROM `users` WHERE `users`.`id` = 1 GROUP BY `users`.`id` - ORDER BY `users`.`id` + ORDER BY `users`.`id` ASC }) end @@ -40,7 +40,7 @@ module Arel FROM "users" WHERE "users"."id" = 1 GROUP BY "users"."id" - ORDER BY "users"."id" + ORDER BY "users"."id" ASC }) end end diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb index c90843cd7d..d1c65c60a9 100644 --- a/spec/arel/unit/relations/array_spec.rb +++ b/spec/arel/unit/relations/array_spec.rb @@ -3,13 +3,18 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') module Arel describe Array do before do - @relation = Array.new([[1], [2], [3]], [:id]) + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) end describe '#attributes' do it 'manufactures attributes corresponding to the names given on construction' do @relation.attributes.should == [ - Attribute.new(@relation, :id) + Attribute.new(@relation, :id), + Attribute.new(@relation, :name) ] end end @@ -17,17 +22,65 @@ module Arel describe '#call' do it "manufactures an array of hashes of attributes to values" do @relation.call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 }, - { @relation[:id] => 3 } + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } ] end - - it '' do - @relation.where(@relation[:id].lt(3)).call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 } - ] + + describe 'where' do + it 'filters the relation with the provided predicate' do + @relation.where(@relation[:id].lt(3)).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'group' do + it 'sorts the relation with the provided ordering' do + end + end + + describe 'order' do + it 'sorts the relation with the provided ordering' do + @relation.order(@relation[:id].desc).call.should == [ + { @relation[:id] => 3, @relation[:name] => 'goose' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 1, @relation[:name] => 'duck' } + ] + end + end + + describe 'project' do + it 'projects' do + @relation.project(@relation[:id]).call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 }, + { @relation[:id] => 3 } + ] + end + end + + describe 'skip' do + it 'slices' do + @relation.skip(1).call.should == [ + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } + ] + end + end + + describe 'take' do + it 'dices' do + @relation.take(2).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'join' do end end end diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb index 31014ddd39..cb0f1de84c 100644 --- a/spec/arel/unit/relations/order_spec.rb +++ b/spec/arel/unit/relations/order_spec.rb @@ -16,7 +16,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`id` + ORDER BY `users`.`id` ASC }) end @@ -24,7 +24,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" - ORDER BY "users"."id" + ORDER BY "users"."id" ASC }) end end @@ -42,7 +42,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`id`, `users`.`name` + ORDER BY `users`.`id` ASC, `users`.`name` ASC }) end @@ -50,7 +50,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" - ORDER BY "users"."id", "users"."name" + ORDER BY "users"."id" ASC, "users"."name" ASC }) end end @@ -95,7 +95,7 @@ module Arel sql.should be_like(%Q{ SELECT `users`.`id`, `users`.`name` FROM `users` - ORDER BY `users`.`name`, `users`.`id` + ORDER BY `users`.`name` ASC, `users`.`id` ASC }) end @@ -103,7 +103,7 @@ module Arel sql.should be_like(%Q{ SELECT "users"."id", "users"."name" FROM "users" - ORDER BY "users"."name", "users"."id" + ORDER BY "users"."name" ASC, "users"."id" ASC }) end end -- cgit v1.2.3 From 2753d8f5768ce0b5f91a96cf81c6ba1d747aeea9 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 14:59:06 -0400 Subject: Add rake whitespace --- Rakefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 9292ac2533..545993653e 100644 --- a/Rakefile +++ b/Rakefile @@ -28,4 +28,9 @@ desc "Run specs with mysql and sqlite3 database adapters (default)" task :spec => ["spec:sqlite3", "spec:mysql"] desc "Default task is to run specs" -task :default => :spec \ No newline at end of file +task :default => :spec + +desc 'Removes trailing whitespace' +task :whitespace do + sh %{find . -name '*.rb' -exec sed -i '' 's/ *$//g' {} \\;} +end -- cgit v1.2.3 From 9d77c08cf8a75636b058c1b85af52ef96e07cee5 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:00:10 -0400 Subject: made block stuff read nicer Conflicts: doc/TODO --- doc/TODO | 30 ++++++++++++------------ lib/arel/algebra/relations/operations/group.rb | 3 ++- lib/arel/algebra/relations/operations/order.rb | 3 ++- lib/arel/algebra/relations/operations/project.rb | 3 ++- lib/arel/algebra/relations/utilities/compound.rb | 5 ++++ 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/doc/TODO b/doc/TODO index dfbf09de9d..d7e3bb280d 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,31 +1,24 @@ todo: -- projection is by definition distincting -- union/intersection -- refactor adapter pattern - result sets to attr correlation too - result sets should be array relations +- fix AR - clean up block_given stuff - reorganize sql tests - audit unit coverage of algebra -- break out adapters into sep modules +- implement mnesia adapter - data objects - remove all explicit aliasing - blocks for joins -- implement in memory adapter -- implement mnesia adapter -- test ordering -- joins become subselects in writes: -users.delete().where( - addresses.c.user_id== - select([users.c.id]). - where(users.c.name=='jack') - ) - rename externalize to derived. - and/or w/ predicates +- scoped writes +- refactor adapter pattern +- break out adapters into sep modules +- projection is by definition distincting? +- union/intersection +- test ordering - cache expiry on write - transactions -- scoped writes -- asc/desc for orderings done: - and/or w/ predicates @@ -93,6 +86,7 @@ done: - joining with LIMIT is like aggregations!! - blocks for non-joins - expressions should be class-based, and joins too, anything _sql should be renamed +- implement in memory adapter icebox: - #bind in Attribute and Expression should be doing a descend? @@ -107,3 +101,9 @@ icebox: @reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" } - lock - SELECT suchandsuch FOR UPDATE +- joins become subselects in writes: +users.delete().where( + addresses.c.user_id== + select([users.c.id]). + where(users.c.name=='jack') + ) \ No newline at end of file diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 04fd9fea62..879f2352c5 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -5,7 +5,8 @@ module Arel def initialize(relation, *groupings, &block) @relation = relation - @groupings = (groupings + (block_given?? [yield(relatoin)] : [])).collect { |g| g.bind(relation) } + @groupings = (groupings + arguments_from_block(relation, &block)) \ + .collect { |g| g.bind(relation) } end def externalizable? diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index eccd8bcda0..4e7133f5a8 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -5,7 +5,8 @@ module Arel def initialize(relation, *orderings, &block) @relation = relation - @orderings = (orderings + (block_given?? [yield(relation)] : [])).collect { |o| o.bind(relation) } + @orderings = (orderings + arguments_from_block(relation, &block)) \ + .collect { |o| o.bind(relation) } end # TESTME diff --git a/lib/arel/algebra/relations/operations/project.rb b/lib/arel/algebra/relations/operations/project.rb index 5507ea3163..223d320e22 100644 --- a/lib/arel/algebra/relations/operations/project.rb +++ b/lib/arel/algebra/relations/operations/project.rb @@ -5,7 +5,8 @@ module Arel def initialize(relation, *projections, &block) @relation = relation - @projections = (projections + (block_given?? [yield(relation)] : [])).collect { |p| p.bind(relation) } + @projections = (projections + arguments_from_block(relation, &block)) \ + .collect { |p| p.bind(relation) } end def attributes diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 4d7cece812..99c3d02748 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -13,5 +13,10 @@ module Arel end OPERATION end + + private + def arguments_from_block(relation, &block) + block_given?? [yield(relation)] : [] + end end end -- cgit v1.2.3 From a7aacd29460aa137c3b06ee214ff8ffdff8ee365 Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Mon, 26 May 2008 21:02:23 -0700 Subject: reorganizing tests --- doc/TODO | 21 ++- spec/arel/algebra/unit/predicates/binary_spec.rb | 33 ++++ spec/arel/algebra/unit/predicates/equality_spec.rb | 27 +++ spec/arel/algebra/unit/predicates/in_spec.rb | 10 + .../arel/algebra/unit/primitives/attribute_spec.rb | 169 +++++++++++++++++ .../algebra/unit/primitives/expression_spec.rb | 39 ++++ spec/arel/algebra/unit/primitives/value_spec.rb | 15 ++ spec/arel/algebra/unit/relations/alias_spec.rb | 16 ++ spec/arel/algebra/unit/relations/delete_spec.rb | 9 + spec/arel/algebra/unit/relations/group_spec.rb | 10 + spec/arel/algebra/unit/relations/insert_spec.rb | 9 + spec/arel/algebra/unit/relations/join_spec.rb | 26 +++ spec/arel/algebra/unit/relations/order_spec.rb | 11 ++ spec/arel/algebra/unit/relations/project_spec.rb | 34 ++++ spec/arel/algebra/unit/relations/relation_spec.rb | 188 ++++++++++++++++++ spec/arel/algebra/unit/relations/skip_spec.rb | 10 + spec/arel/algebra/unit/relations/table_spec.rb | 39 ++++ spec/arel/algebra/unit/relations/take_spec.rb | 10 + spec/arel/algebra/unit/relations/update_spec.rb | 9 + spec/arel/algebra/unit/relations/where_spec.rb | 18 ++ spec/arel/algebra/unit/session/session_spec.rb | 84 +++++++++ .../sql/integration/joins/with_adjacency_spec.rb | 209 +++++++++++++++++++++ .../integration/joins/with_aggregations_spec.rb | 167 ++++++++++++++++ .../sql/integration/joins/with_compounds_spec.rb | 107 +++++++++++ .../engines/sql/unit/predicates/binary_spec.rb | 125 ++++++++++++ .../engines/sql/unit/predicates/equality_spec.rb | 61 ++++++ spec/arel/engines/sql/unit/predicates/in_spec.rb | 86 +++++++++ .../engines/sql/unit/primitives/attribute_spec.rb | 171 +++++++++++++++++ .../engines/sql/unit/primitives/expression_spec.rb | 53 ++++++ .../arel/engines/sql/unit/primitives/value_spec.rb | 28 +++ spec/arel/engines/sql/unit/relations/alias_spec.rb | 50 +++++ spec/arel/engines/sql/unit/relations/array_spec.rb | 87 +++++++++ .../arel/engines/sql/unit/relations/delete_spec.rb | 63 +++++++ spec/arel/engines/sql/unit/relations/group_spec.rb | 56 ++++++ .../arel/engines/sql/unit/relations/insert_spec.rb | 91 +++++++++ spec/arel/engines/sql/unit/relations/join_spec.rb | 78 ++++++++ spec/arel/engines/sql/unit/relations/order_spec.rb | 113 +++++++++++ .../engines/sql/unit/relations/project_spec.rb | 134 +++++++++++++ .../engines/sql/unit/relations/relation_spec.rb | 169 +++++++++++++++++ spec/arel/engines/sql/unit/relations/skip_spec.rb | 32 ++++ spec/arel/engines/sql/unit/relations/table_spec.rb | 99 ++++++++++ spec/arel/engines/sql/unit/relations/take_spec.rb | 32 ++++ .../arel/engines/sql/unit/relations/update_spec.rb | 121 ++++++++++++ spec/arel/engines/sql/unit/relations/where_spec.rb | 64 +++++++ spec/arel/engines/sql/unit/session/session_spec.rb | 84 +++++++++ spec/arel/integration/joins/with_adjacency_spec.rb | 209 --------------------- .../integration/joins/with_aggregations_spec.rb | 167 ---------------- spec/arel/integration/joins/with_compounds_spec.rb | 107 ----------- spec/arel/unit/predicates/binary_spec.rb | 125 ------------ spec/arel/unit/predicates/equality_spec.rb | 61 ------ spec/arel/unit/predicates/in_spec.rb | 86 --------- spec/arel/unit/primitives/attribute_spec.rb | 171 ----------------- spec/arel/unit/primitives/expression_spec.rb | 53 ------ spec/arel/unit/primitives/value_spec.rb | 28 --- spec/arel/unit/relations/alias_spec.rb | 50 ----- spec/arel/unit/relations/array_spec.rb | 87 --------- spec/arel/unit/relations/delete_spec.rb | 63 ------- spec/arel/unit/relations/group_spec.rb | 56 ------ spec/arel/unit/relations/insert_spec.rb | 91 --------- spec/arel/unit/relations/join_spec.rb | 78 -------- spec/arel/unit/relations/order_spec.rb | 113 ----------- spec/arel/unit/relations/project_spec.rb | 134 ------------- spec/arel/unit/relations/relation_spec.rb | 169 ----------------- spec/arel/unit/relations/skip_spec.rb | 32 ---- spec/arel/unit/relations/table_spec.rb | 99 ---------- spec/arel/unit/relations/take_spec.rb | 32 ---- spec/arel/unit/relations/update_spec.rb | 121 ------------ spec/arel/unit/relations/where_spec.rb | 64 ------- spec/arel/unit/session/session_spec.rb | 84 --------- 69 files changed, 3059 insertions(+), 2288 deletions(-) create mode 100644 spec/arel/algebra/unit/predicates/binary_spec.rb create mode 100644 spec/arel/algebra/unit/predicates/equality_spec.rb create mode 100644 spec/arel/algebra/unit/predicates/in_spec.rb create mode 100644 spec/arel/algebra/unit/primitives/attribute_spec.rb create mode 100644 spec/arel/algebra/unit/primitives/expression_spec.rb create mode 100644 spec/arel/algebra/unit/primitives/value_spec.rb create mode 100644 spec/arel/algebra/unit/relations/alias_spec.rb create mode 100644 spec/arel/algebra/unit/relations/delete_spec.rb create mode 100644 spec/arel/algebra/unit/relations/group_spec.rb create mode 100644 spec/arel/algebra/unit/relations/insert_spec.rb create mode 100644 spec/arel/algebra/unit/relations/join_spec.rb create mode 100644 spec/arel/algebra/unit/relations/order_spec.rb create mode 100644 spec/arel/algebra/unit/relations/project_spec.rb create mode 100644 spec/arel/algebra/unit/relations/relation_spec.rb create mode 100644 spec/arel/algebra/unit/relations/skip_spec.rb create mode 100644 spec/arel/algebra/unit/relations/table_spec.rb create mode 100644 spec/arel/algebra/unit/relations/take_spec.rb create mode 100644 spec/arel/algebra/unit/relations/update_spec.rb create mode 100644 spec/arel/algebra/unit/relations/where_spec.rb create mode 100644 spec/arel/algebra/unit/session/session_spec.rb create mode 100644 spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb create mode 100644 spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb create mode 100644 spec/arel/engines/sql/integration/joins/with_compounds_spec.rb create mode 100644 spec/arel/engines/sql/unit/predicates/binary_spec.rb create mode 100644 spec/arel/engines/sql/unit/predicates/equality_spec.rb create mode 100644 spec/arel/engines/sql/unit/predicates/in_spec.rb create mode 100644 spec/arel/engines/sql/unit/primitives/attribute_spec.rb create mode 100644 spec/arel/engines/sql/unit/primitives/expression_spec.rb create mode 100644 spec/arel/engines/sql/unit/primitives/value_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/alias_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/array_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/delete_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/group_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/insert_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/join_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/order_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/project_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/relation_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/skip_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/table_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/take_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/update_spec.rb create mode 100644 spec/arel/engines/sql/unit/relations/where_spec.rb create mode 100644 spec/arel/engines/sql/unit/session/session_spec.rb delete mode 100644 spec/arel/integration/joins/with_adjacency_spec.rb delete mode 100644 spec/arel/integration/joins/with_aggregations_spec.rb delete mode 100644 spec/arel/integration/joins/with_compounds_spec.rb delete mode 100644 spec/arel/unit/predicates/binary_spec.rb delete mode 100644 spec/arel/unit/predicates/equality_spec.rb delete mode 100644 spec/arel/unit/predicates/in_spec.rb delete mode 100644 spec/arel/unit/primitives/attribute_spec.rb delete mode 100644 spec/arel/unit/primitives/expression_spec.rb delete mode 100644 spec/arel/unit/primitives/value_spec.rb delete mode 100644 spec/arel/unit/relations/alias_spec.rb delete mode 100644 spec/arel/unit/relations/array_spec.rb delete mode 100644 spec/arel/unit/relations/delete_spec.rb delete mode 100644 spec/arel/unit/relations/group_spec.rb delete mode 100644 spec/arel/unit/relations/insert_spec.rb delete mode 100644 spec/arel/unit/relations/join_spec.rb delete mode 100644 spec/arel/unit/relations/order_spec.rb delete mode 100644 spec/arel/unit/relations/project_spec.rb delete mode 100644 spec/arel/unit/relations/relation_spec.rb delete mode 100644 spec/arel/unit/relations/skip_spec.rb delete mode 100644 spec/arel/unit/relations/table_spec.rb delete mode 100644 spec/arel/unit/relations/take_spec.rb delete mode 100644 spec/arel/unit/relations/update_spec.rb delete mode 100644 spec/arel/unit/relations/where_spec.rb delete mode 100644 spec/arel/unit/session/session_spec.rb diff --git a/doc/TODO b/doc/TODO index d7e3bb280d..f97e74ef17 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,22 +1,26 @@ todo: -- result sets to attr correlation too - - result sets should be array relations -- fix AR -- clean up block_given stuff - reorganize sql tests -- audit unit coverage of algebra +- reorganize memory tests +- blocks for joins +- implement joins in memory +- recursive memory operations +- result sets should be array relations +- cross-engine joins +- fix grouping - implement mnesia adapter +- fix AR +- rename externalize to derived. + +- result sets to attr correlation too +- audit unit coverage of algebra - data objects - remove all explicit aliasing -- blocks for joins -- rename externalize to derived. - and/or w/ predicates - scoped writes - refactor adapter pattern - break out adapters into sep modules - projection is by definition distincting? - union/intersection -- test ordering - cache expiry on write - transactions @@ -87,6 +91,7 @@ done: - blocks for non-joins - expressions should be class-based, and joins too, anything _sql should be renamed - implement in memory adapter +- clean up block_given stuff icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb new file mode 100644 index 0000000000..9022a543d1 --- /dev/null +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -0,0 +1,33 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Binary do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + class ConcreteBinary < Binary + end + end + + describe '#bind' do + before do + @another_relation = @relation.alias + end + + describe 'when both operands are attributes' do + it "manufactures an expression with the attributes bound to the relation" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) + end + end + + describe 'when an operand is a value' do + it "manufactures an expression with unmodified values" do + ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ + should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb new file mode 100644 index 0000000000..9a56ed5eaf --- /dev/null +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Equality do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) + Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) + end + + it "is commutative on the attributes" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/arel/algebra/unit/predicates/in_spec.rb new file mode 100644 index 0000000000..91c154763c --- /dev/null +++ b/spec/arel/algebra/unit/predicates/in_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe In do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb new file mode 100644 index 0000000000..bab9fad3d5 --- /dev/null +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -0,0 +1,169 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Attribute do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Attribute::Transformations do + describe '#as' do + it "manufactures an aliased attributed" do + @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) + end + end + + describe '#bind' do + it "manufactures an attribute with the relation bound and self as an ancestor" do + derived_relation = @relation.where(@relation[:id].eq(1)) + @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) + end + + it "returns self if the substituting to the same relation" do + @attribute.bind(@relation).should == @attribute + end + end + + describe '#to_attribute' do + it "returns self" do + @attribute.to_attribute.should == @attribute + end + end + end + + describe '#column' do + it "returns the corresponding column in the relation" do + @attribute.column.should == @relation.column_for(@attribute) + end + end + + describe '#engine' do + it "delegates to its relation" do + Attribute.new(@relation, :id).engine.should == @relation.engine + end + end + + describe Attribute::Congruence do + describe '/' do + before do + @aliased_relation = @relation.alias + @doubly_aliased_relation = @aliased_relation.alias + end + + describe 'when dividing two unrelated attributes' do + it "returns 0.0" do + (@relation[:id] / @relation[:name]).should == 0.0 + end + end + + describe 'when dividing two matching attributes' do + it 'returns a the highest score for the most similar attributes' do + (@aliased_relation[:id] / @relation[:id]) \ + .should == (@aliased_relation[:id] / @relation[:id]) + (@aliased_relation[:id] / @relation[:id]) \ + .should < (@aliased_relation[:id] / @aliased_relation[:id]) + end + end + end + end + + describe Attribute::Predications do + before do + @attribute = Attribute.new(@relation, :name) + end + + describe '#eq' do + it "manufactures an equality predicate" do + @attribute.eq('name').should == Equality.new(@attribute, 'name') + end + end + + describe '#lt' do + it "manufactures a less-than predicate" do + @attribute.lt(10).should == LessThan.new(@attribute, 10) + end + end + + describe '#lteq' do + it "manufactures a less-than or equal-to predicate" do + @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) + end + end + + describe '#gt' do + it "manufactures a greater-than predicate" do + @attribute.gt(10).should == GreaterThan.new(@attribute, 10) + end + end + + describe '#gteq' do + it "manufactures a greater-than or equal-to predicate" do + @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) + end + end + + describe '#matches' do + it "manufactures a match predicate" do + @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) + end + end + + describe '#in' do + it "manufactures an in predicate" do + @attribute.in(1..30).should == In.new(@attribute, (1..30)) + end + end + end + + describe Attribute::Expressions do + before do + @attribute = Attribute.new(@relation, :name) + end + + describe '#count' do + it "manufactures a count Expression" do + @attribute.count.should == Count.new(@attribute) + end + end + + describe '#sum' do + it "manufactures a sum Expression" do + @attribute.sum.should == Sum.new(@attribute) + end + end + + describe '#maximum' do + it "manufactures a maximum Expression" do + @attribute.maximum.should == Maximum.new(@attribute) + end + end + + describe '#minimum' do + it "manufactures a minimum Expression" do + @attribute.minimum.should == Minimum.new(@attribute) + end + end + + describe '#average' do + it "manufactures an average Expression" do + @attribute.average.should == Average.new(@attribute) + end + end + end + + describe Attribute::Orderings do + describe '#asc' do + it 'manufactures an ascending ordering' do + pending + end + end + + describe '#desc' do + it 'manufactures a descending ordering' do + pending + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb new file mode 100644 index 0000000000..10bdb56302 --- /dev/null +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Expression do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Expression::Transformations do + before do + @expression = Count.new(@attribute) + end + + describe '#bind' do + it "manufactures an attribute with a rebound relation and self as the ancestor" do + derived_relation = @relation.where(@relation[:id].eq(1)) + @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) + end + + it "returns self if the substituting to the same relation" do + @expression.bind(@relation).should == @expression + end + end + + describe '#as' do + it "manufactures an aliased expression" do + @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) + end + end + + describe '#to_attribute' do + it "manufactures an attribute with the expression as an ancestor" do + @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/primitives/value_spec.rb b/spec/arel/algebra/unit/primitives/value_spec.rb new file mode 100644 index 0000000000..8774ca78c5 --- /dev/null +++ b/spec/arel/algebra/unit/primitives/value_spec.rb @@ -0,0 +1,15 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Value do + before do + @relation = Table.new(:users) + end + + describe '#bind' do + it "manufactures a new value whose relation is the provided relation" do + Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/arel/algebra/unit/relations/alias_spec.rb new file mode 100644 index 0000000000..c87a0ca2dd --- /dev/null +++ b/spec/arel/algebra/unit/relations/alias_spec.rb @@ -0,0 +1,16 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Alias do + before do + @relation = Table.new(:users) + end + + describe '==' do + it "obtains if the objects are the same" do + Alias.new(@relation).should_not == Alias.new(@relation) + (aliaz = Alias.new(@relation)).should == aliaz + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/delete_spec.rb b/spec/arel/algebra/unit/relations/delete_spec.rb new file mode 100644 index 0000000000..075e59e724 --- /dev/null +++ b/spec/arel/algebra/unit/relations/delete_spec.rb @@ -0,0 +1,9 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Deletion do + before do + @relation = Table.new(:users) + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/group_spec.rb b/spec/arel/algebra/unit/relations/group_spec.rb new file mode 100644 index 0000000000..050de2993d --- /dev/null +++ b/spec/arel/algebra/unit/relations/group_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Group do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/insert_spec.rb b/spec/arel/algebra/unit/relations/insert_spec.rb new file mode 100644 index 0000000000..184cd2a926 --- /dev/null +++ b/spec/arel/algebra/unit/relations/insert_spec.rb @@ -0,0 +1,9 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Insert do + before do + @relation = Table.new(:users) + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/join_spec.rb b/spec/arel/algebra/unit/relations/join_spec.rb new file mode 100644 index 0000000000..5b512cc7f6 --- /dev/null +++ b/spec/arel/algebra/unit/relations/join_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe 'hashing' do + it 'implements hash equality' do + InnerJoin.new(@relation1, @relation2, @predicate) \ + .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) + end + end + + describe '#attributes' do + it 'combines the attributes of the two relations' do + join = InnerJoin.new(@relation1, @relation2, @predicate) + join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb new file mode 100644 index 0000000000..0e1b1a0e54 --- /dev/null +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -0,0 +1,11 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Order do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + end +end + \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/project_spec.rb b/spec/arel/algebra/unit/relations/project_spec.rb new file mode 100644 index 0000000000..b71acf5e91 --- /dev/null +++ b/spec/arel/algebra/unit/relations/project_spec.rb @@ -0,0 +1,34 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Project do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#attributes' do + before do + @projection = Project.new(@relation, @attribute) + end + + it "manufactures attributes associated with the projection relation" do + @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } + end + end + + describe '#externalizable?' do + describe 'when the projections are attributes' do + it 'returns false' do + Project.new(@relation, @attribute).should_not be_externalizable + end + end + + describe 'when the projections include an aggregation' do + it "obtains" do + Project.new(@relation, @attribute.sum).should be_externalizable + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb new file mode 100644 index 0000000000..3286f373f5 --- /dev/null +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -0,0 +1,188 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Relation do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + end + + describe '[]' do + describe 'when given an', Attribute do + it "return the attribute congruent to the provided attribute" do + @relation[@attribute1].should == @attribute1 + end + end + + describe 'when given a', Symbol, String do + it "returns the attribute with the same name, if it exists" do + @relation[:id].should == @attribute1 + @relation['id'].should == @attribute1 + @relation[:does_not_exist].should be_nil + end + end + end + + describe Relation::Operable do + describe 'joins' do + before do + @predicate = @relation[:id].eq(@relation[:id]) + end + + describe '#join' do + describe 'when given a relation' do + it "manufactures an inner join operation between those two relations" do + @relation.join(@relation).on(@predicate). \ + should == InnerJoin.new(@relation, @relation, @predicate) + end + end + + describe "when given a string" do + it "manufactures a join operation with the string passed through" do + @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + end + end + + describe "when given something blank" do + it "returns self" do + @relation.join.should == @relation + end + end + end + + describe '#outer_join' do + it "manufactures a left outer join operation between those two relations" do + @relation.outer_join(@relation).on(@predicate). \ + should == OuterJoin.new(@relation, @relation, @predicate) + end + end + end + + describe '#project' do + it "manufactures a projection relation" do + @relation.project(@attribute1, @attribute2). \ + should == Project.new(@relation, @attribute1, @attribute2) + end + + describe "when given blank attributes" do + it "returns self" do + @relation.project.should == @relation + end + end + end + + describe '#alias' do + it "manufactures an alias relation" do + @relation.alias.relation.should == Alias.new(@relation).relation + end + end + + describe '#where' do + before do + @predicate = Equality.new(@attribute1, @attribute2) + end + + it "manufactures a where relation" do + @relation.where(@predicate).should == Where.new(@relation, @predicate) + end + + it "accepts arbitrary strings" do + @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") + end + + describe 'when given a blank predicate' do + it 'returns self' do + @relation.where.should == @relation + end + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) + end + + describe 'when given a blank ordering' do + it 'returns self' do + @relation.order.should == @relation + end + end + end + + describe '#take' do + it "manufactures a take relation" do + @relation.take(5).should == Take.new(@relation, 5) + end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.take.should == @relation + end + end + end + + describe '#skip' do + it "manufactures a skip relation" do + @relation.skip(4).should == Skip.new(@relation, 4) + end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.skip.should == @relation + end + end + end + + describe '#group' do + it 'manufactures a group relation' do + @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) + end + + describe 'when given blank groupings' do + it 'returns self' do + @relation.group.should == @relation + end + end + end + + describe Relation::Operable::Writable do + describe '#delete' do + it 'manufactures a deletion relation' do + Session.start do + mock(Session.new).delete(Deletion.new(@relation)) + @relation.delete + end + end + end + + describe '#insert' do + it 'manufactures an insertion relation' do + Session.start do + record = {@relation[:name] => 'carl'} + mock(Session.new).create(Insert.new(@relation, record)) + @relation.insert(record) + end + end + end + + describe '#update' do + it 'manufactures an update relation' do + Session.start do + assignments = {@relation[:name] => Value.new('bob', @relation)} + mock(Session.new).update(Update.new(@relation, assignments)) + @relation.update(assignments) + end + end + end + end + end + + describe Relation::Enumerable do + it "implements enumerable" do + @relation.collect.should == @relation.session.read(@relation) + @relation.first.should == @relation.session.read(@relation).first + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/skip_spec.rb b/spec/arel/algebra/unit/relations/skip_spec.rb new file mode 100644 index 0000000000..ff57e03d1c --- /dev/null +++ b/spec/arel/algebra/unit/relations/skip_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Skip do + before do + @relation = Table.new(:users) + @skipped = 4 + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb new file mode 100644 index 0000000000..4821d92299 --- /dev/null +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Table do + before do + @relation = Table.new(:users) + end + + describe '[]' do + describe 'when given a', Symbol do + it "manufactures an attribute if the symbol names an attribute within the relation" do + @relation[:id].should == Attribute.new(@relation, :id) + @relation[:does_not_exist].should be_nil + end + end + + describe 'when given an', Attribute do + it "returns the attribute if the attribute is within the relation" do + @relation[@relation[:id]].should == @relation[:id] + end + + it "returns nil if the attribtue is not within the relation" do + another_relation = Table.new(:photos) + @relation[another_relation[:id]].should be_nil + end + end + + describe 'when given an', Expression do + before do + @expression = @relation[:id].count + end + + it "returns the Expression if the Expression is within the relation" do + @relation[@expression].should be_nil + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/take_spec.rb b/spec/arel/algebra/unit/relations/take_spec.rb new file mode 100644 index 0000000000..6f8b4fd36e --- /dev/null +++ b/spec/arel/algebra/unit/relations/take_spec.rb @@ -0,0 +1,10 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Take do + before do + @relation = Table.new(:users) + @taken = 4 + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/update_spec.rb b/spec/arel/algebra/unit/relations/update_spec.rb new file mode 100644 index 0000000000..c27afb48b2 --- /dev/null +++ b/spec/arel/algebra/unit/relations/update_spec.rb @@ -0,0 +1,9 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Update do + before do + @relation = Table.new(:users) + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/relations/where_spec.rb b/spec/arel/algebra/unit/relations/where_spec.rb new file mode 100644 index 0000000000..3f37b53138 --- /dev/null +++ b/spec/arel/algebra/unit/relations/where_spec.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Where do + before do + @relation = Table.new(:users) + @predicate = @relation[:id].eq(1) + end + + describe '#initialize' do + it "manufactures nested where relations if multiple predicates are provided" do + another_predicate = @relation[:name].lt(2) + Where.new(@relation, @predicate, another_predicate). \ + should == Where.new(Where.new(@relation, another_predicate), @predicate) + end + end + end +end \ No newline at end of file diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/arel/algebra/unit/session/session_spec.rb new file mode 100644 index 0000000000..e17b5d638a --- /dev/null +++ b/spec/arel/algebra/unit/session/session_spec.rb @@ -0,0 +1,84 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Session do + before do + @relation = Table.new(:users) + @session = Session.new + end + + describe '::start' do + describe '::instance' do + it "it is a singleton within the started session" do + Session.start do + Session.new.should == Session.new + end + end + + it "is a singleton across nested sessions" do + Session.start do + outside = Session.new + Session.start do + Session.new.should == outside + end + end + end + + it "manufactures new sessions outside of the started session" do + Session.new.should_not == Session.new + end + end + end + + describe Session::CRUD do + before do + @insert = Insert.new(@relation, @relation[:name] => 'nick') + @update = Update.new(@relation, @relation[:name] => 'nick') + @delete = Deletion.new(@relation) + @read = @relation + end + + describe '#create' do + it "executes an insertion on the connection" do + mock(@insert).call + @session.create(@insert) + end + end + + describe '#read' do + it "executes an selection on the connection" do + mock(@read).call + @session.read(@read) + end + + it "is memoized" do + mock(@read).call.once + @session.read(@read) + @session.read(@read) + end + end + + describe '#update' do + it "executes an update on the connection" do + mock(@update).call + @session.update(@update) + end + end + + describe '#delete' do + it "executes a delete on the connection" do + mock(@delete).call + @session.delete(@delete) + end + end + end + + describe 'Transactions' do + describe '#begin' do + end + + describe '#end' do + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb new file mode 100644 index 0000000000..50b0908441 --- /dev/null +++ b/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb @@ -0,0 +1,209 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table(:users) + @relation2 = @relation1.alias + @predicate = @relation1[:id].eq(@relation2[:id]) + end + + describe 'when joining a relation to itself' do + describe '#to_sql' do + it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do + sql = @relation1.join(@relation2).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + }) + end + end + + describe 'when joining with a where on the same relation' do + it 'manufactures sql aliasing the tables properly' do + sql = @relation1 \ + .join(@relation2.where(@relation2[:id].eq(1))) \ + .on(@predicate) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1 + }) + end + end + + describe 'when the where occurs before the alias' do + it 'manufactures sql aliasing the predicates properly' do + relation2 = @relation1.where(@relation1[:id].eq(1)).alias + + sql = @relation1 \ + .join(relation2) \ + .on(relation2[:id].eq(@relation1[:id])) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1 + }) + end + end + end + end + + describe 'when joining the relation to itself multiple times' do + before do + @relation3 = @relation1.alias + end + + describe 'when joining left-associatively' do + it 'manufactures sql aliasing the tables properly' do + sql = @relation1 \ + .join(@relation2 \ + .join(@relation3) \ + .on(@relation2[:id].eq(@relation3[:id]))) \ + .on(@relation1[:id].eq(@relation2[:id])) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + INNER JOIN "users" AS "users_3" + ON "users_2"."id" = "users_3"."id" + }) + end + end + end + + describe 'when joining right-associatively' do + it 'manufactures sql aliasing the tables properly' do + sql = @relation1 \ + .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ + .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` + FROM `users` + INNER JOIN `users` AS `users_2` + ON `users`.`id` = `users_2`.`id` + INNER JOIN `users` AS `users_3` + ON `users_2`.`id` = `users_3`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" + FROM "users" + INNER JOIN "users" AS "users_2" + ON "users"."id" = "users_2"."id" + INNER JOIN "users" AS "users_3" + ON "users_2"."id" = "users_3"."id" + }) + end + end + end + end + end + + describe '[]' do + describe 'when given an attribute belonging to both sub-relations' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + @relation1 \ + .join(@relation2) \ + .on(@predicate) \ + .should disambiguate_attributes(@relation1[:id], @relation2[:id]) + end + + describe 'when both relations are compound and only one is an alias' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + compound1 = @relation1.where(@predicate) + compound2 = compound1.alias + compound1 \ + .join(compound2) \ + .on(@predicate) \ + .should disambiguate_attributes(compound1[:id], compound2[:id]) + end + end + + describe 'when the left relation is extremely compound' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + @relation1 \ + .where(@predicate) \ + .where(@predicate) \ + .join(@relation2) \ + .on(@predicate) \ + .should disambiguate_attributes(@relation1[:id], @relation2[:id]) + end + end + + describe 'when the right relation is extremely compound' do + it 'disambiguates the relation that serves as the ancestor to the attribute' do + @relation1 \ + .join( \ + @relation2 \ + .where(@predicate) \ + .where(@predicate) \ + .where(@predicate)) \ + .on(@predicate) \ + .should disambiguate_attributes(@relation1[:id], @relation2[:id]) + end + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb new file mode 100644 index 0000000000..709ae9f8d1 --- /dev/null +++ b/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb @@ -0,0 +1,167 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table(:users) + @relation2 = Table(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe 'when joining aggregated relations' do + before do + @aggregation = @relation2 \ + .group(@relation2[:user_id]) \ + .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ + end + + describe '#to_sql' do + # CLEANUP + it '' do + sql = @relation1.join(@relation2.take(3)).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` + FROM `users` + INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" + FROM "users" + INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end + end + + describe 'with the aggregation on the right' do + it 'manufactures sql joining the left table to a derived table' do + sql = @relation1.join(@aggregation).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" + FROM "users" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end + end + end + + describe 'with the aggregation on the left' do + it 'manufactures sql joining the right table to a derived table' do + sql = @aggregation.join(@relation1).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN `users` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN "users" + ON "users"."id" = "photos_external"."user_id" + }) + end + end + end + + describe 'with the aggregation on both sides' do + it 'it properly aliases the aggregations' do + aggregation2 = @aggregation.alias + sql = @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` + ON `photos_external_2`.`user_id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external_2" + ON "photos_external_2"."user_id" = "photos_external"."user_id" + }) + end + end + end + + describe 'when the aggration has a where' do + describe 'with the aggregation on the left' do + it "manufactures sql keeping wheres on the aggregation within the derived table" do + sql = @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` + FROM `users` + INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" + FROM "users" + INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + ON "users"."id" = "photos_external"."user_id" + }) + end + end + end + + describe 'with the aggregation on the right' do + it "manufactures sql keeping wheres on the aggregation within the derived table" do + sql = @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` + FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` + INNER JOIN `users` + ON `users`.`id` = `photos_external`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" + FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" + INNER JOIN "users" + ON "users"."id" = "photos_external"."user_id" + }) + end + end + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb new file mode 100644 index 0000000000..4bceef4975 --- /dev/null +++ b/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb @@ -0,0 +1,107 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table(:users) + @relation2 = Table(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe '#to_sql' do + describe 'when the join contains a where' do + describe 'and the where is given a string' do + it 'does not escape the string' do + sql = @relation1 \ + .join(@relation2.where("asdf")) \ + .on(@predicate) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` AND asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" AND asdf + }) + end + end + end + end + + describe 'when a compound contains a join' do + describe 'and the compound is a where' do + it 'manufactures sql disambiguating the tables' do + sql = @relation1 \ + .where(@relation1[:id].eq(1)) \ + .join(@relation2) \ + .on(@predicate) \ + .where(@relation1[:id].eq(1)) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + WHERE `users`.`id` = 1 + AND `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" + WHERE "users"."id" = 1 + AND "users"."id" = 1 + }) + end + end + end + + describe 'and the compound is a group' do + it 'manufactures sql disambiguating the tables' do + sql = @relation1 \ + .join(@relation2) \ + .on(@predicate) \ + .group(@relation1[:id]) \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` + ON `users`.`id` = `photos`.`user_id` + GROUP BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" + ON "users"."id" = "photos"."user_id" + GROUP BY "users"."id" + }) + end + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb new file mode 100644 index 0000000000..03574225c2 --- /dev/null +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -0,0 +1,125 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Binary do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + class ConcreteBinary < Binary + def predicate_sql + "<=>" + end + end + end + + describe "with compound predicates" do + before do + @operand1 = ConcreteBinary.new(@attribute1, 1) + @operand2 = ConcreteBinary.new(@attribute2, "name") + end + + describe Or do + describe "#to_sql" do + it "manufactures sql with an OR operation" do + sql = Or.new(@operand1, @operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) + end + end + end + end + + describe And do + describe "#to_sql" do + it "manufactures sql with an AND operation" do + sql = And.new(@operand1, @operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) + end + end + end + end + end + + describe '#to_sql' do + describe 'when relating two attributes' do + it 'manufactures sql with a binary operation' do + sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> "users"."name"}) + end + end + end + + describe 'when relating an attribute and a value' do + before do + @value = "1-asdf" + end + + describe 'when relating to an integer attribute' do + it 'formats values as integers' do + sql = ConcreteBinary.new(@attribute1, @value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` <=> 1}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" <=> 1}) + end + end + end + + describe 'when relating to a string attribute' do + it 'formats values as strings' do + sql = ConcreteBinary.new(@attribute2, @value).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) + end + end + end + end + end + + describe '#bind' do + before do + @another_relation = @relation.alias + end + + describe 'when both operands are attributes' do + it "manufactures an expression with the attributes bound to the relation" do + ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ + should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) + end + end + + describe 'when an operand is a value' do + it "manufactures an expression with unmodified values" do + ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ + should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb new file mode 100644 index 0000000000..2ab79d7028 --- /dev/null +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -0,0 +1,61 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Equality do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @attribute1 = @relation1[:id] + @attribute2 = @relation2[:user_id] + end + + describe '==' do + it "obtains if attribute1 and attribute2 are identical" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) + Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) + end + + it "obtains if the concrete type of the predicates are identical" do + Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) + end + + it "is commutative on the attributes" do + Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) + end + end + + describe '#to_sql' do + describe 'when relating to a non-nil value' do + it "manufactures an equality predicate" do + sql = Equality.new(@attribute1, @attribute2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) + end + end + end + + describe 'when relation to a nil value' do + before do + @nil = nil + end + + it "manufactures an is null predicate" do + sql = Equality.new(@attribute1, @nil).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IS NULL}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IS NULL}) + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb new file mode 100644 index 0000000000..d977937e4e --- /dev/null +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -0,0 +1,86 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe In do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#to_sql' do + describe 'when relating to an array' do + describe 'when the array\'s elements are the same type as the attribute' do + before do + @array = [1, 2, 3] + end + + it 'manufactures sql with a comma separated list' do + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end + end + end + + describe 'when the array\'s elements are not same type as the attribute' do + before do + @array = ['1-asdf', 2, 3] + end + + it 'formats values in the array as the type of the attribute' do + sql = In.new(@attribute, @array).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) + end + end + end + end + + describe 'when relating to a range' do + before do + @range = 1..2 + end + + it 'manufactures sql with a between' do + sql = In.new(@attribute, @range).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) + end + end + end + + describe 'when relating to a relation' do + it 'manufactures sql with a subselect' do + sql = In.new(@attribute, @relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") + }) + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb new file mode 100644 index 0000000000..f37cd14370 --- /dev/null +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -0,0 +1,171 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Attribute do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Attribute::Transformations do + describe '#as' do + it "manufactures an aliased attributed" do + @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) + end + end + + describe '#bind' do + it "manufactures an attribute with the relation bound and self as an ancestor" do + derived_relation = @relation.where(@relation[:id].eq(1)) + @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) + end + + it "returns self if the substituting to the same relation" do + @attribute.bind(@relation).should == @attribute + end + end + + describe '#to_attribute' do + it "returns self" do + @attribute.to_attribute.should == @attribute + end + end + end + + describe '#column' do + it "returns the corresponding column in the relation" do + @attribute.column.should == @relation.column_for(@attribute) + end + end + + describe '#engine' do + it "delegates to its relation" do + Attribute.new(@relation, :id).engine.should == @relation.engine + end + end + + describe Attribute::Congruence do + describe '/' do + before do + @aliased_relation = @relation.alias + @doubly_aliased_relation = @aliased_relation.alias + end + + describe 'when dividing two unrelated attributes' do + it "returns 0.0" do + (@relation[:id] / @relation[:name]).should == 0.0 + end + end + + describe 'when dividing two matching attributes' do + it 'returns a the highest score for the most similar attributes' do + (@aliased_relation[:id] / @relation[:id]) \ + .should == (@aliased_relation[:id] / @relation[:id]) + (@aliased_relation[:id] / @relation[:id]) \ + .should < (@aliased_relation[:id] / @aliased_relation[:id]) + end + end + end + end + + describe '#to_sql' do + describe 'for a simple attribute' do + it "manufactures sql with an alias" do + sql = @attribute.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{`users`.`id`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{"users"."id"}) + end + end + end + end + + describe Attribute::Predications do + before do + @attribute = Attribute.new(@relation, :name) + end + + describe '#eq' do + it "manufactures an equality predicate" do + @attribute.eq('name').should == Equality.new(@attribute, 'name') + end + end + + describe '#lt' do + it "manufactures a less-than predicate" do + @attribute.lt(10).should == LessThan.new(@attribute, 10) + end + end + + describe '#lteq' do + it "manufactures a less-than or equal-to predicate" do + @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) + end + end + + describe '#gt' do + it "manufactures a greater-than predicate" do + @attribute.gt(10).should == GreaterThan.new(@attribute, 10) + end + end + + describe '#gteq' do + it "manufactures a greater-than or equal-to predicate" do + @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) + end + end + + describe '#matches' do + it "manufactures a match predicate" do + @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) + end + end + + describe '#in' do + it "manufactures an in predicate" do + @attribute.in(1..30).should == In.new(@attribute, (1..30)) + end + end + end + + describe Attribute::Expressions do + before do + @attribute = Attribute.new(@relation, :name) + end + + describe '#count' do + it "manufactures a count Expression" do + @attribute.count.should == Count.new(@attribute) + end + end + + describe '#sum' do + it "manufactures a sum Expression" do + @attribute.sum.should == Sum.new(@attribute) + end + end + + describe '#maximum' do + it "manufactures a maximum Expression" do + @attribute.maximum.should == Maximum.new(@attribute) + end + end + + describe '#minimum' do + it "manufactures a minimum Expression" do + @attribute.minimum.should == Minimum.new(@attribute) + end + end + + describe '#average' do + it "manufactures an average Expression" do + @attribute.average.should == Average.new(@attribute) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/primitives/expression_spec.rb b/spec/arel/engines/sql/unit/primitives/expression_spec.rb new file mode 100644 index 0000000000..0869d9e403 --- /dev/null +++ b/spec/arel/engines/sql/unit/primitives/expression_spec.rb @@ -0,0 +1,53 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Expression do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe Expression::Transformations do + before do + @expression = Count.new(@attribute) + end + + describe '#bind' do + it "manufactures an attribute with a rebound relation and self as the ancestor" do + derived_relation = @relation.where(@relation[:id].eq(1)) + @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) + end + + it "returns self if the substituting to the same relation" do + @expression.bind(@relation).should == @expression + end + end + + describe '#as' do + it "manufactures an aliased expression" do + @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) + end + end + + describe '#to_attribute' do + it "manufactures an attribute with the expression as an ancestor" do + @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) + end + end + end + + describe '#to_sql' do + it "manufactures sql with the expression and alias" do + sql = Count.new(@attribute, :alias).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{COUNT("users"."id") AS "alias"}) + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb new file mode 100644 index 0000000000..f76323f32b --- /dev/null +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -0,0 +1,28 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Value do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "appropriately quotes the value" do + Value.new(1, @relation).to_sql.should be_like('1') + Value.new('asdf', @relation).to_sql.should be_like("'asdf'") + end + end + + describe '#format' do + it "returns the sql of the provided object" do + Value.new(1, @relation).format(@relation[:id]).should == @relation[:id].to_sql + end + end + + describe '#bind' do + it "manufactures a new value whose relation is the provided relation" do + Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/alias_spec.rb b/spec/arel/engines/sql/unit/relations/alias_spec.rb new file mode 100644 index 0000000000..83b9113f6d --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/alias_spec.rb @@ -0,0 +1,50 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Alias do + before do + @relation = Table.new(:users) + end + + describe '==' do + it "obtains if the objects are the same" do + Alias.new(@relation).should_not == Alias.new(@relation) + (aliaz = Alias.new(@relation)).should == aliaz + end + end + + describe '#to_sql' do + describe 'when there is no ambiguity' do + it 'does not alias table names anywhere a table name can appear' do + sql = @relation \ + .where(@relation[:id].eq(1)) \ + .order(@relation[:id]) \ + .project(@relation[:id]) \ + .group(@relation[:id]) \ + .alias \ + .to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id` + FROM `users` + WHERE `users`.`id` = 1 + GROUP BY `users`.`id` + ORDER BY `users`.`id` ASC + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id" + FROM "users" + WHERE "users"."id" = 1 + GROUP BY "users"."id" + ORDER BY "users"."id" ASC + }) + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/array_spec.rb b/spec/arel/engines/sql/unit/relations/array_spec.rb new file mode 100644 index 0000000000..8d40858c5f --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/array_spec.rb @@ -0,0 +1,87 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Array do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#attributes' do + it 'manufactures attributes corresponding to the names given on construction' do + @relation.attributes.should == [ + Attribute.new(@relation, :id), + Attribute.new(@relation, :name) + ] + end + end + + describe '#call' do + it "manufactures an array of hashes of attributes to values" do + @relation.call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } + ] + end + + describe 'where' do + it 'filters the relation with the provided predicate' do + @relation.where(@relation[:id].lt(3)).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'group' do + it 'sorts the relation with the provided ordering' do + end + end + + describe 'order' do + it 'sorts the relation with the provided ordering' do + @relation.order(@relation[:id].desc).call.should == [ + { @relation[:id] => 3, @relation[:name] => 'goose' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 1, @relation[:name] => 'duck' } + ] + end + end + + describe 'project' do + it 'projects' do + @relation.project(@relation[:id]).call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 }, + { @relation[:id] => 3 } + ] + end + end + + describe 'skip' do + it 'slices' do + @relation.skip(1).call.should == [ + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } + ] + end + end + + describe 'take' do + it 'dices' do + @relation.take(2).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'join' do + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/delete_spec.rb b/spec/arel/engines/sql/unit/relations/delete_spec.rb new file mode 100644 index 0000000000..7a5e2b0088 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/delete_spec.rb @@ -0,0 +1,63 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Deletion do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql deleting a table relation' do + sql = Deletion.new(@relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{DELETE FROM `users`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{DELETE FROM "users"}) + end + end + + it 'manufactures sql deleting a where relation' do + sql = Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + DELETE + FROM `users` + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + DELETE + FROM "users" + WHERE "users"."id" = 1 + }) + end + end + + it "manufactures sql deleting a ranged relation" do + sql = Deletion.new(@relation.take(1)).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + DELETE + FROM `users` + LIMIT 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + DELETE + FROM "users" + LIMIT 1 + }) + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/group_spec.rb b/spec/arel/engines/sql/unit/relations/group_spec.rb new file mode 100644 index 0000000000..b7279a23d9 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/group_spec.rb @@ -0,0 +1,56 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Group do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#to_sql' do + describe 'when given a predicate' do + it "manufactures sql with where clause conditions" do + sql = Group.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY `users`.`id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + GROUP BY "users"."id" + }) + end + end + end + + describe 'when given a string' do + it "passes the string through to the where clause" do + sql = Group.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + GROUP BY asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + GROUP BY asdf + }) + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb new file mode 100644 index 0000000000..dd1995cced --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -0,0 +1,91 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Insert do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it 'manufactures sql inserting data when given multiple rows' do + pending 'it should insert multiple rows' do + @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) + + @insertion.to_sql.should be_like(" + INSERT + INTO `users` + (`name`) VALUES ('nick'), ('bryan') + ") + end + end + + it 'manufactures sql inserting data when given multiple values' do + @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") + + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`id`, `name`) VALUES (1, 'nick') + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id", "name") VALUES (1, 'nick') + }) + end + end + + describe 'when given values whose types correspond to the types of the attributes' do + before do + @insertion = Insert.new(@relation, @relation[:name] => "nick") + end + + it 'manufactures sql inserting data' do + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`name`) VALUES ('nick') + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("name") VALUES ('nick') + }) + end + end + end + + describe 'when given values whose types differ from from the types of the attributes' do + before do + @insertion = Insert.new(@relation, @relation[:id] => '1-asdf') + end + + it 'manufactures sql inserting data' do + adapter_is :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO `users` + (`id`) VALUES (1) + }) + end + + adapter_is_not :mysql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id") VALUES (1) + }) + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb new file mode 100644 index 0000000000..ea17f8106f --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -0,0 +1,78 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Table.new(:users) + @relation2 = Table.new(:photos) + @predicate = @relation1[:id].eq(@relation2[:user_id]) + end + + describe 'hashing' do + it 'implements hash equality' do + InnerJoin.new(@relation1, @relation2, @predicate) \ + .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) + end + end + + describe '#engine' do + it "delegates to a relation's engine" do + InnerJoin.new(@relation1, @relation2, @predicate).engine.should == @relation1.engine + end + end + + describe '#attributes' do + it 'combines the attributes of the two relations' do + join = InnerJoin.new(@relation1, @relation2, @predicate) + join.attributes.should == + (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } + end + end + + describe '#to_sql' do + describe 'when joining with another relation' do + it 'manufactures sql joining the two tables on the predicate' do + sql = InnerJoin.new(@relation1, @relation2, @predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` + INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" + INNER JOIN "photos" ON "users"."id" = "photos"."user_id" + }) + end + end + end + + describe 'when joining with a string' do + it "passes the string through to the where clause" do + sql = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + INNER JOIN asdf ON fdsa + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + INNER JOIN asdf ON fdsa + }) + end + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/order_spec.rb b/spec/arel/engines/sql/unit/relations/order_spec.rb new file mode 100644 index 0000000000..ce97a4dd5e --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/order_spec.rb @@ -0,0 +1,113 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Order do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#to_sql' do + describe "when given an attribute" do + it "manufactures sql with an order clause populated by the attribute" do + sql = Order.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id` ASC + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."id" ASC + }) + end + end + end + + describe "when given multiple attributes" do + before do + @another_attribute = @relation[:name] + end + + it "manufactures sql with an order clause populated by comma-separated attributes" do + sql = Order.new(@relation, @attribute, @another_attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`id` ASC, `users`.`name` ASC + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."id" ASC, "users"."name" ASC + }) + end + end + end + + describe "when given a string" do + before do + @string = "asdf" + end + + it "passes the string through to the order clause" do + sql = Order.new(@relation, @string).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY asdf + }) + end + end + end + + describe "when ordering an ordered relation" do + before do + @ordered_relation = Order.new(@relation, @attribute) + @another_attribute = @relation[:name] + end + + it "manufactures sql with the order clause of the last ordering preceding the first ordering" do + sql = Order.new(@ordered_relation, @another_attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + ORDER BY `users`.`name` ASC, `users`.`id` ASC + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + ORDER BY "users"."name" ASC, "users"."id" ASC + }) + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/project_spec.rb b/spec/arel/engines/sql/unit/relations/project_spec.rb new file mode 100644 index 0000000000..9d6b9fab06 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/project_spec.rb @@ -0,0 +1,134 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Project do + before do + @relation = Table.new(:users) + @attribute = @relation[:id] + end + + describe '#attributes' do + before do + @projection = Project.new(@relation, @attribute) + end + + it "manufactures attributes associated with the projection relation" do + @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } + end + end + + describe '#to_sql' do + describe 'when given an attribute' do + it "manufactures sql with a limited select clause" do + sql = Project.new(@relation, @attribute).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id" + FROM "users" + }) + end + end + end + + describe 'when given a relation' do + before do + @scalar_relation = Project.new(@relation, @relation[:name]) + end + + it "manufactures sql with scalar selects" do + sql = Project.new(@relation, @scalar_relation).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users" + }) + end + end + end + + describe 'when given a string' do + it "passes the string through to the select clause" do + sql = Project.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT asdf FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT asdf FROM "users" + }) + end + end + end + + describe 'when given an expression' do + it 'manufactures sql with expressions' do + sql = @relation.project(@attribute.count).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(`users`.`id`) AS count_id + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT COUNT("users"."id") AS count_id + FROM "users" + }) + end + end + + it 'manufactures sql with distinct expressions' do + sql = @relation.project(@attribute.count(true)).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT `users`.`id`) AS count_id + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT COUNT(DISTINCT "users"."id") AS count_id + FROM "users" + }) + end + end + end + end + + describe '#externalizable?' do + describe 'when the projections are attributes' do + it 'returns false' do + Project.new(@relation, @attribute).should_not be_externalizable + end + end + + describe 'when the projections include an aggregation' do + it "obtains" do + Project.new(@relation, @attribute.sum).should be_externalizable + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/relation_spec.rb b/spec/arel/engines/sql/unit/relations/relation_spec.rb new file mode 100644 index 0000000000..9a5cfbff41 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/relation_spec.rb @@ -0,0 +1,169 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Relation do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + end + + describe '[]' do + describe 'when given an', Attribute do + it "return the attribute congruent to the provided attribute" do + @relation[@attribute1].should == @attribute1 + end + end + + describe 'when given a', Symbol, String do + it "returns the attribute with the same name, if it exists" do + @relation[:id].should == @attribute1 + @relation['id'].should == @attribute1 + @relation[:does_not_exist].should be_nil + end + end + end + + describe Relation::Operable do + describe 'joins' do + before do + @predicate = @relation[:id].eq(@relation[:id]) + end + + describe '#join' do + describe 'when given a relation' do + it "manufactures an inner join operation between those two relations" do + @relation.join(@relation).on(@predicate). \ + should == InnerJoin.new(@relation, @relation, @predicate) + end + end + + describe "when given a string" do + it "manufactures a join operation with the string passed through" do + @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + end + end + + describe "when given something blank" do + it "returns self" do + @relation.join.should == @relation + end + end + end + + describe '#outer_join' do + it "manufactures a left outer join operation between those two relations" do + @relation.outer_join(@relation).on(@predicate). \ + should == OuterJoin.new(@relation, @relation, @predicate) + end + end + end + + describe '#project' do + it "manufactures a projection relation" do + @relation.project(@attribute1, @attribute2). \ + should == Project.new(@relation, @attribute1, @attribute2) + end + + describe "when given blank attributes" do + it "returns self" do + @relation.project.should == @relation + end + end + end + + describe '#alias' do + it "manufactures an alias relation" do + @relation.alias.relation.should == Alias.new(@relation).relation + end + end + + describe '#where' do + before do + @predicate = Equality.new(@attribute1, @attribute2) + end + + it "manufactures a where relation" do + @relation.where(@predicate).should == Where.new(@relation, @predicate) + end + + it "accepts arbitrary strings" do + @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") + end + + describe 'when given a blank predicate' do + it 'returns self' do + @relation.where.should == @relation + end + end + end + + describe '#order' do + it "manufactures an order relation" do + @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) + end + + describe 'when given a blank ordering' do + it 'returns self' do + @relation.order.should == @relation + end + end + end + + describe '#take' do + it "manufactures a take relation" do + @relation.take(5).should == Take.new(@relation, 5) + end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.take.should == @relation + end + end + end + + describe '#skip' do + it "manufactures a skip relation" do + @relation.skip(4).should == Skip.new(@relation, 4) + end + + describe 'when given a blank number of items' do + it 'returns self' do + @relation.skip.should == @relation + end + end + end + + describe '#group' do + it 'manufactures a group relation' do + @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) + end + + describe 'when given blank groupings' do + it 'returns self' do + @relation.group.should == @relation + end + end + end + + describe Relation::Operable::Writable do + describe '#insert' do + it 'manufactures an insertion relation' do + Session.start do + record = {@relation[:name] => 'carl'} + mock(Session.new).create(Insert.new(@relation, record)) + @relation.insert(record).should == @relation + end + end + end + end + end + + describe Relation::Enumerable do + it "implements enumerable" do + @relation.collect.should == @relation.session.read(@relation) + @relation.first.should == @relation.session.read(@relation).first + end + end + end +end diff --git a/spec/arel/engines/sql/unit/relations/skip_spec.rb b/spec/arel/engines/sql/unit/relations/skip_spec.rb new file mode 100644 index 0000000000..f8e5ceaad3 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/skip_spec.rb @@ -0,0 +1,32 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Skip do + before do + @relation = Table.new(:users) + @skipped = 4 + end + + describe '#to_sql' do + it "manufactures sql with limit and offset" do + sql = Skip.new(@relation, @skipped).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + OFFSET 4 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + OFFSET 4 + }) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb new file mode 100644 index 0000000000..6de49a9157 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -0,0 +1,99 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Table do + before do + @relation = Table.new(:users) + end + + describe '[]' do + describe 'when given a', Symbol do + it "manufactures an attribute if the symbol names an attribute within the relation" do + @relation[:id].should == Attribute.new(@relation, :id) + @relation[:does_not_exist].should be_nil + end + end + + describe 'when given an', Attribute do + it "returns the attribute if the attribute is within the relation" do + @relation[@relation[:id]].should == @relation[:id] + end + + it "returns nil if the attribtue is not within the relation" do + another_relation = Table.new(:photos) + @relation[another_relation[:id]].should be_nil + end + end + + describe 'when given an', Expression do + before do + @expression = @relation[:id].count + end + + it "returns the Expression if the Expression is within the relation" do + @relation[@expression].should be_nil + end + end + end + + describe '#to_sql' do + it "manufactures a simple select query" do + sql = @relation.to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + }) + end + end + end + + describe '#column_for' do + it "returns the column corresponding to the attribute" do + @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } + end + end + + describe '#attributes' do + it 'manufactures attributes corresponding to columns in the table' do + @relation.attributes.should == [ + Attribute.new(@relation, :id), + Attribute.new(@relation, :name) + ] + end + + describe '#reset' do + it "reloads columns from the database" do + lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } + lambda { @relation.reset }.should change { @relation.attributes } + end + end + end + + describe 'hashing' do + it "implements hash equality" do + Table.new(:users).should hash_the_same_as(Table.new(:users)) + Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) + end + end + + describe '#engine' do + it "defaults to global engine" do + Table.engine = engine = Sql::Engine.new + Table.new(:users).engine.should == engine + end + + it "can be specified" do + Table.new(:users, engine = Sql::Engine.new).engine.should == engine + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/take_spec.rb b/spec/arel/engines/sql/unit/relations/take_spec.rb new file mode 100644 index 0000000000..1263ed4795 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/take_spec.rb @@ -0,0 +1,32 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Take do + before do + @relation = Table.new(:users) + @taken = 4 + end + + describe '#to_sql' do + it "manufactures sql with limit and offset" do + sql = Take.new(@relation, @taken).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + LIMIT 4 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + LIMIT 4 + }) + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb new file mode 100644 index 0000000000..f553490ef5 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -0,0 +1,121 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Update do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "manufactures sql updating attributes when given multiple attributes" do + sql = Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + UPDATE `users` + SET `id` = 1, `name` = 'nick' + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1, "name" = 'nick' + }) + end + end + + it "manufactures sql updating attributes when given a ranged relation" do + sql = Update.new(@relation.take(1), @relation[:name] => "nick").to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + LIMIT 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + LIMIT 1 + }) + end + end + + describe 'when given values whose types correspond to the types of the attributes' do + before do + @update = Update.new(@relation, @relation[:name] => "nick") + end + + it 'manufactures sql updating attributes' do + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + }) + end + end + end + + describe 'when given values whose types differ from from the types of the attributes' do + before do + @update = Update.new(@relation, @relation[:id] => '1-asdf') + end + + it 'manufactures sql updating attributes' do + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `id` = 1 + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1 + }) + end + end + end + + describe 'when the relation is a where' do + before do + @update = Update.new( + @relation.where(@relation[:id].eq(1)), + @relation[:name] => "nick" + ) + end + + it 'manufactures sql updating a where relation' do + adapter_is :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE `users` + SET `name` = 'nick' + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = 'nick' + WHERE "users"."id" = 1 + }) + end + end + end + end + + end +end diff --git a/spec/arel/engines/sql/unit/relations/where_spec.rb b/spec/arel/engines/sql/unit/relations/where_spec.rb new file mode 100644 index 0000000000..5870b6b793 --- /dev/null +++ b/spec/arel/engines/sql/unit/relations/where_spec.rb @@ -0,0 +1,64 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Where do + before do + @relation = Table.new(:users) + @predicate = @relation[:id].eq(1) + end + + describe '#initialize' do + it "manufactures nested where relations if multiple predicates are provided" do + another_predicate = @relation[:name].lt(2) + Where.new(@relation, @predicate, another_predicate). \ + should == Where.new(Where.new(@relation, another_predicate), @predicate) + end + end + + describe '#to_sql' do + describe 'when given a predicate' do + it "manufactures sql with where clause conditions" do + sql = Where.new(@relation, @predicate).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE `users`.`id` = 1 + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + WHERE "users"."id" = 1 + }) + end + end + end + + describe 'when given a string' do + it "passes the string through to the where clause" do + sql = Where.new(@relation, 'asdf').to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `users`.`id`, `users`.`name` + FROM `users` + WHERE asdf + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "users"."id", "users"."name" + FROM "users" + WHERE asdf + }) + end + end + end + end + end +end diff --git a/spec/arel/engines/sql/unit/session/session_spec.rb b/spec/arel/engines/sql/unit/session/session_spec.rb new file mode 100644 index 0000000000..c489984a61 --- /dev/null +++ b/spec/arel/engines/sql/unit/session/session_spec.rb @@ -0,0 +1,84 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Session do + before do + @relation = Table.new(:users) + @session = Session.new + end + + describe '::start' do + describe '::instance' do + it "it is a singleton within the started session" do + Session.start do + Session.new.should == Session.new + end + end + + it "is a singleton across nested sessions" do + Session.start do + outside = Session.new + Session.start do + Session.new.should == outside + end + end + end + + it "manufactures new sessions outside of the started session" do + Session.new.should_not == Session.new + end + end + end + + describe Session::CRUD do + before do + @insert = Insert.new(@relation, @relation[:name] => 'nick') + @update = Update.new(@relation, @relation[:name] => 'nick') + @delete = Deletion.new(@relation) + @read = @relation + end + + describe '#create' do + it "executes an insertion on the connection" do + mock(@insert).call + @session.create(@insert) + end + end + + describe '#read' do + it "executes an selection on the connection" do + mock(@read).call + @session.read(@read) + end + + it "is memoized" do + mock(@read).call.once + @session.read(@read) + @session.read(@read) + end + end + + describe '#update' do + it "executes an update on the connection" do + mock(@update).call + @session.update(@update) + end + end + + describe '#delete' do + it "executes a delete on the connection" do + mock(@delete).call + @session.delete(@delete) + end + end + end + + describe 'Transactions' do + describe '#begin' do + end + + describe '#end' do + end + end + end +end diff --git a/spec/arel/integration/joins/with_adjacency_spec.rb b/spec/arel/integration/joins/with_adjacency_spec.rb deleted file mode 100644 index ffd6498749..0000000000 --- a/spec/arel/integration/joins/with_adjacency_spec.rb +++ /dev/null @@ -1,209 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Join do - before do - @relation1 = Table(:users) - @relation2 = @relation1.alias - @predicate = @relation1[:id].eq(@relation2[:id]) - end - - describe 'when joining a relation to itself' do - describe '#to_sql' do - it 'manufactures sql aliasing the table and attributes properly in the join predicate and the where clause' do - sql = @relation1.join(@relation2).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" - FROM "users" - INNER JOIN "users" AS "users_2" - ON "users"."id" = "users_2"."id" - }) - end - end - - describe 'when joining with a where on the same relation' do - it 'manufactures sql aliasing the tables properly' do - sql = @relation1 \ - .join(@relation2.where(@relation2[:id].eq(1))) \ - .on(@predicate) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` AND `users_2`.`id` = 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" - FROM "users" - INNER JOIN "users" AS "users_2" - ON "users"."id" = "users_2"."id" AND "users_2"."id" = 1 - }) - end - end - - describe 'when the where occurs before the alias' do - it 'manufactures sql aliasing the predicates properly' do - relation2 = @relation1.where(@relation1[:id].eq(1)).alias - - sql = @relation1 \ - .join(relation2) \ - .on(relation2[:id].eq(@relation1[:id])) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users_2`.`id` = `users`.`id` AND `users_2`.`id` = 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name" - FROM "users" - INNER JOIN "users" AS "users_2" - ON "users_2"."id" = "users"."id" AND "users_2"."id" = 1 - }) - end - end - end - end - - describe 'when joining the relation to itself multiple times' do - before do - @relation3 = @relation1.alias - end - - describe 'when joining left-associatively' do - it 'manufactures sql aliasing the tables properly' do - sql = @relation1 \ - .join(@relation2 \ - .join(@relation3) \ - .on(@relation2[:id].eq(@relation3[:id]))) \ - .on(@relation1[:id].eq(@relation2[:id])) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" - FROM "users" - INNER JOIN "users" AS "users_2" - ON "users"."id" = "users_2"."id" - INNER JOIN "users" AS "users_3" - ON "users_2"."id" = "users_3"."id" - }) - end - end - end - - describe 'when joining right-associatively' do - it 'manufactures sql aliasing the tables properly' do - sql = @relation1 \ - .join(@relation2).on(@relation1[:id].eq(@relation2[:id])) \ - .join(@relation3).on(@relation2[:id].eq(@relation3[:id])) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `users_2`.`id`, `users_2`.`name`, `users_3`.`id`, `users_3`.`name` - FROM `users` - INNER JOIN `users` AS `users_2` - ON `users`.`id` = `users_2`.`id` - INNER JOIN `users` AS `users_3` - ON `users_2`.`id` = `users_3`.`id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "users_2"."id", "users_2"."name", "users_3"."id", "users_3"."name" - FROM "users" - INNER JOIN "users" AS "users_2" - ON "users"."id" = "users_2"."id" - INNER JOIN "users" AS "users_3" - ON "users_2"."id" = "users_3"."id" - }) - end - end - end - end - end - - describe '[]' do - describe 'when given an attribute belonging to both sub-relations' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - @relation1 \ - .join(@relation2) \ - .on(@predicate) \ - .should disambiguate_attributes(@relation1[:id], @relation2[:id]) - end - - describe 'when both relations are compound and only one is an alias' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - compound1 = @relation1.where(@predicate) - compound2 = compound1.alias - compound1 \ - .join(compound2) \ - .on(@predicate) \ - .should disambiguate_attributes(compound1[:id], compound2[:id]) - end - end - - describe 'when the left relation is extremely compound' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - @relation1 \ - .where(@predicate) \ - .where(@predicate) \ - .join(@relation2) \ - .on(@predicate) \ - .should disambiguate_attributes(@relation1[:id], @relation2[:id]) - end - end - - describe 'when the right relation is extremely compound' do - it 'disambiguates the relation that serves as the ancestor to the attribute' do - @relation1 \ - .join( \ - @relation2 \ - .where(@predicate) \ - .where(@predicate) \ - .where(@predicate)) \ - .on(@predicate) \ - .should disambiguate_attributes(@relation1[:id], @relation2[:id]) - end - end - end - end - end - end -end diff --git a/spec/arel/integration/joins/with_aggregations_spec.rb b/spec/arel/integration/joins/with_aggregations_spec.rb deleted file mode 100644 index 4aba005d51..0000000000 --- a/spec/arel/integration/joins/with_aggregations_spec.rb +++ /dev/null @@ -1,167 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Join do - before do - @relation1 = Table(:users) - @relation2 = Table(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) - end - - describe 'when joining aggregated relations' do - before do - @aggregation = @relation2 \ - .group(@relation2[:user_id]) \ - .project(@relation2[:user_id], @relation2[:id].count.as(:cnt)) \ - end - - describe '#to_sql' do - # CLEANUP - it '' do - sql = @relation1.join(@relation2.take(3)).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos_external`.`id`, `photos_external`.`user_id`, `photos_external`.`camera_id` - FROM `users` - INNER JOIN (SELECT `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` FROM `photos` LIMIT 3) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos_external"."id", "photos_external"."user_id", "photos_external"."camera_id" - FROM "users" - INNER JOIN (SELECT "photos"."id", "photos"."user_id", "photos"."camera_id" FROM "photos" LIMIT 3) AS "photos_external" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - - describe 'with the aggregation on the right' do - it 'manufactures sql joining the left table to a derived table' do - sql = @relation1.join(@aggregation).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" - FROM "users" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - - describe 'with the aggregation on the left' do - it 'manufactures sql joining the right table to a derived table' do - sql = @aggregation.join(@relation1).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" - INNER JOIN "users" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - - describe 'with the aggregation on both sides' do - it 'it properly aliases the aggregations' do - aggregation2 = @aggregation.alias - sql = @aggregation.join(aggregation2).on(aggregation2[:user_id].eq(@aggregation[:user_id])).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `photos_external_2`.`user_id`, `photos_external_2`.`cnt` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` GROUP BY `photos`.`user_id`) AS `photos_external_2` - ON `photos_external_2`.`user_id` = `photos_external`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "photos_external"."user_id", "photos_external"."cnt", "photos_external_2"."user_id", "photos_external_2"."cnt" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" GROUP BY "photos"."user_id") AS "photos_external_2" - ON "photos_external_2"."user_id" = "photos_external"."user_id" - }) - end - end - end - - describe 'when the aggration has a where' do - describe 'with the aggregation on the left' do - it "manufactures sql keeping wheres on the aggregation within the derived table" do - sql = @relation1.join(@aggregation.where(@aggregation[:user_id].eq(1))).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos_external`.`user_id`, `photos_external`.`cnt` - FROM `users` - INNER JOIN (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos_external"."user_id", "photos_external"."cnt" - FROM "users" - INNER JOIN (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - - describe 'with the aggregation on the right' do - it "manufactures sql keeping wheres on the aggregation within the derived table" do - sql = @aggregation.where(@aggregation[:user_id].eq(1)).join(@relation1).on(@predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `photos_external`.`user_id`, `photos_external`.`cnt`, `users`.`id`, `users`.`name` - FROM (SELECT `photos`.`user_id`, COUNT(`photos`.`id`) AS `cnt` FROM `photos` WHERE `photos`.`user_id` = 1 GROUP BY `photos`.`user_id`) AS `photos_external` - INNER JOIN `users` - ON `users`.`id` = `photos_external`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "photos_external"."user_id", "photos_external"."cnt", "users"."id", "users"."name" - FROM (SELECT "photos"."user_id", COUNT("photos"."id") AS "cnt" FROM "photos" WHERE "photos"."user_id" = 1 GROUP BY "photos"."user_id") AS "photos_external" - INNER JOIN "users" - ON "users"."id" = "photos_external"."user_id" - }) - end - end - end - end - end - end - end -end diff --git a/spec/arel/integration/joins/with_compounds_spec.rb b/spec/arel/integration/joins/with_compounds_spec.rb deleted file mode 100644 index 41f04349b8..0000000000 --- a/spec/arel/integration/joins/with_compounds_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Join do - before do - @relation1 = Table(:users) - @relation2 = Table(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) - end - - describe '#to_sql' do - describe 'when the join contains a where' do - describe 'and the where is given a string' do - it 'does not escape the string' do - sql = @relation1 \ - .join(@relation2.where("asdf")) \ - .on(@predicate) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` AND asdf - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" - ON "users"."id" = "photos"."user_id" AND asdf - }) - end - end - end - end - - describe 'when a compound contains a join' do - describe 'and the compound is a where' do - it 'manufactures sql disambiguating the tables' do - sql = @relation1 \ - .where(@relation1[:id].eq(1)) \ - .join(@relation2) \ - .on(@predicate) \ - .where(@relation1[:id].eq(1)) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - WHERE `users`.`id` = 1 - AND `users`.`id` = 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" - ON "users"."id" = "photos"."user_id" - WHERE "users"."id" = 1 - AND "users"."id" = 1 - }) - end - end - end - - describe 'and the compound is a group' do - it 'manufactures sql disambiguating the tables' do - sql = @relation1 \ - .join(@relation2) \ - .on(@predicate) \ - .group(@relation1[:id]) \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` - ON `users`.`id` = `photos`.`user_id` - GROUP BY `users`.`id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" - ON "users"."id" = "photos"."user_id" - GROUP BY "users"."id" - }) - end - end - end - end - end - end -end diff --git a/spec/arel/unit/predicates/binary_spec.rb b/spec/arel/unit/predicates/binary_spec.rb deleted file mode 100644 index 2d0c67e006..0000000000 --- a/spec/arel/unit/predicates/binary_spec.rb +++ /dev/null @@ -1,125 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Binary do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - class ConcreteBinary < Binary - def predicate_sql - "<=>" - end - end - end - - describe "with compound predicates" do - before do - @operand1 = ConcreteBinary.new(@attribute1, 1) - @operand2 = ConcreteBinary.new(@attribute2, "name") - end - - describe Or do - describe "#to_sql" do - it "manufactures sql with an OR operation" do - sql = Or.new(@operand1, @operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) - end - end - end - end - - describe And do - describe "#to_sql" do - it "manufactures sql with an AND operation" do - sql = And.new(@operand1, @operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) - end - end - end - end - end - - describe '#to_sql' do - describe 'when relating two attributes' do - it 'manufactures sql with a binary operation' do - sql = ConcreteBinary.new(@attribute1, @attribute2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` <=> `users`.`name`}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" <=> "users"."name"}) - end - end - end - - describe 'when relating an attribute and a value' do - before do - @value = "1-asdf" - end - - describe 'when relating to an integer attribute' do - it 'formats values as integers' do - sql = ConcreteBinary.new(@attribute1, @value).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` <=> 1}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" <=> 1}) - end - end - end - - describe 'when relating to a string attribute' do - it 'formats values as strings' do - sql = ConcreteBinary.new(@attribute2, @value).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) - end - end - end - end - end - - describe '#bind' do - before do - @another_relation = @relation.alias - end - - describe 'when both operands are attributes' do - it "manufactures an expression with the attributes bound to the relation" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ - should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) - end - end - - describe 'when an operand is a value' do - it "manufactures an expression with unmodified values" do - ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/predicates/equality_spec.rb b/spec/arel/unit/predicates/equality_spec.rb deleted file mode 100644 index b595cdd247..0000000000 --- a/spec/arel/unit/predicates/equality_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Equality do - before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @attribute1 = @relation1[:id] - @attribute2 = @relation2[:user_id] - end - - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) - Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the predicates are identical" do - Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) - end - - it "is commutative on the attributes" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) - end - end - - describe '#to_sql' do - describe 'when relating to a non-nil value' do - it "manufactures an equality predicate" do - sql = Equality.new(@attribute1, @attribute2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` = `photos`.`user_id`}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" = "photos"."user_id"}) - end - end - end - - describe 'when relation to a nil value' do - before do - @nil = nil - end - - it "manufactures an is null predicate" do - sql = Equality.new(@attribute1, @nil).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IS NULL}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IS NULL}) - end - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/predicates/in_spec.rb b/spec/arel/unit/predicates/in_spec.rb deleted file mode 100644 index 9107da9d4b..0000000000 --- a/spec/arel/unit/predicates/in_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe In do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe 'when relating to an array' do - describe 'when the array\'s elements are the same type as the attribute' do - before do - @array = [1, 2, 3] - end - - it 'manufactures sql with a comma separated list' do - sql = In.new(@attribute, @array).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) - end - end - end - - describe 'when the array\'s elements are not same type as the attribute' do - before do - @array = ['1-asdf', 2, 3] - end - - it 'formats values in the array as the type of the attribute' do - sql = In.new(@attribute, @array).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` IN (1, 2, 3)}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" IN (1, 2, 3)}) - end - end - end - end - - describe 'when relating to a range' do - before do - @range = 1..2 - end - - it 'manufactures sql with a between' do - sql = In.new(@attribute, @range).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id` BETWEEN 1 AND 2}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id" BETWEEN 1 AND 2}) - end - end - end - - describe 'when relating to a relation' do - it 'manufactures sql with a subselect' do - sql = In.new(@attribute, @relation).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - `users`.`id` IN (SELECT `users`.`id`, `users`.`name` FROM `users`) - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - "users"."id" IN (SELECT "users"."id", "users"."name" FROM "users") - }) - end - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/primitives/attribute_spec.rb b/spec/arel/unit/primitives/attribute_spec.rb deleted file mode 100644 index e512b40ebf..0000000000 --- a/spec/arel/unit/primitives/attribute_spec.rb +++ /dev/null @@ -1,171 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Attribute do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe Attribute::Transformations do - describe '#as' do - it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) - end - end - - describe '#bind' do - it "manufactures an attribute with the relation bound and self as an ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) - end - - it "returns self if the substituting to the same relation" do - @attribute.bind(@relation).should == @attribute - end - end - - describe '#to_attribute' do - it "returns self" do - @attribute.to_attribute.should == @attribute - end - end - end - - describe '#column' do - it "returns the corresponding column in the relation" do - @attribute.column.should == @relation.column_for(@attribute) - end - end - - describe '#engine' do - it "delegates to its relation" do - Attribute.new(@relation, :id).engine.should == @relation.engine - end - end - - describe Attribute::Congruence do - describe '/' do - before do - @aliased_relation = @relation.alias - @doubly_aliased_relation = @aliased_relation.alias - end - - describe 'when dividing two unrelated attributes' do - it "returns 0.0" do - (@relation[:id] / @relation[:name]).should == 0.0 - end - end - - describe 'when dividing two matching attributes' do - it 'returns a the highest score for the most similar attributes' do - (@aliased_relation[:id] / @relation[:id]) \ - .should == (@aliased_relation[:id] / @relation[:id]) - (@aliased_relation[:id] / @relation[:id]) \ - .should < (@aliased_relation[:id] / @aliased_relation[:id]) - end - end - end - end - - describe '#to_sql' do - describe 'for a simple attribute' do - it "manufactures sql with an alias" do - sql = @attribute.to_sql - - adapter_is :mysql do - sql.should be_like(%Q{`users`.`id`}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{"users"."id"}) - end - end - end - end - - describe Attribute::Predications do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#eq' do - it "manufactures an equality predicate" do - @attribute.eq('name').should == Equality.new(@attribute, 'name') - end - end - - describe '#lt' do - it "manufactures a less-than predicate" do - @attribute.lt(10).should == LessThan.new(@attribute, 10) - end - end - - describe '#lteq' do - it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#gt' do - it "manufactures a greater-than predicate" do - @attribute.gt(10).should == GreaterThan.new(@attribute, 10) - end - end - - describe '#gteq' do - it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#matches' do - it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) - end - end - - describe '#in' do - it "manufactures an in predicate" do - @attribute.in(1..30).should == In.new(@attribute, (1..30)) - end - end - end - - describe Attribute::Expressions do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#count' do - it "manufactures a count Expression" do - @attribute.count.should == Count.new(@attribute) - end - end - - describe '#sum' do - it "manufactures a sum Expression" do - @attribute.sum.should == Sum.new(@attribute) - end - end - - describe '#maximum' do - it "manufactures a maximum Expression" do - @attribute.maximum.should == Maximum.new(@attribute) - end - end - - describe '#minimum' do - it "manufactures a minimum Expression" do - @attribute.minimum.should == Minimum.new(@attribute) - end - end - - describe '#average' do - it "manufactures an average Expression" do - @attribute.average.should == Average.new(@attribute) - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/primitives/expression_spec.rb b/spec/arel/unit/primitives/expression_spec.rb deleted file mode 100644 index 92f300c4ee..0000000000 --- a/spec/arel/unit/primitives/expression_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Expression do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe Expression::Transformations do - before do - @expression = Count.new(@attribute) - end - - describe '#bind' do - it "manufactures an attribute with a rebound relation and self as the ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) - end - - it "returns self if the substituting to the same relation" do - @expression.bind(@relation).should == @expression - end - end - - describe '#as' do - it "manufactures an aliased expression" do - @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) - end - end - - describe '#to_attribute' do - it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) - end - end - end - - describe '#to_sql' do - it "manufactures sql with the expression and alias" do - sql = Count.new(@attribute, :alias).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{COUNT(`users`.`id`) AS `alias`}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{COUNT("users"."id") AS "alias"}) - end - end - end - end -end diff --git a/spec/arel/unit/primitives/value_spec.rb b/spec/arel/unit/primitives/value_spec.rb deleted file mode 100644 index ba9a80bb49..0000000000 --- a/spec/arel/unit/primitives/value_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Value do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "appropriately quotes the value" do - Value.new(1, @relation).to_sql.should be_like('1') - Value.new('asdf', @relation).to_sql.should be_like("'asdf'") - end - end - - describe '#format' do - it "returns the sql of the provided object" do - Value.new(1, @relation).format(@relation[:id]).should == @relation[:id].to_sql - end - end - - describe '#bind' do - it "manufactures a new value whose relation is the provided relation" do - Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) - end - end - end -end diff --git a/spec/arel/unit/relations/alias_spec.rb b/spec/arel/unit/relations/alias_spec.rb deleted file mode 100644 index 63c15cfeff..0000000000 --- a/spec/arel/unit/relations/alias_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Alias do - before do - @relation = Table.new(:users) - end - - describe '==' do - it "obtains if the objects are the same" do - Alias.new(@relation).should_not == Alias.new(@relation) - (aliaz = Alias.new(@relation)).should == aliaz - end - end - - describe '#to_sql' do - describe 'when there is no ambiguity' do - it 'does not alias table names anywhere a table name can appear' do - sql = @relation \ - .where(@relation[:id].eq(1)) \ - .order(@relation[:id]) \ - .project(@relation[:id]) \ - .group(@relation[:id]) \ - .alias \ - .to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id` - FROM `users` - WHERE `users`.`id` = 1 - GROUP BY `users`.`id` - ORDER BY `users`.`id` ASC - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id" - FROM "users" - WHERE "users"."id" = 1 - GROUP BY "users"."id" - ORDER BY "users"."id" ASC - }) - end - end - end - end - end -end diff --git a/spec/arel/unit/relations/array_spec.rb b/spec/arel/unit/relations/array_spec.rb deleted file mode 100644 index d1c65c60a9..0000000000 --- a/spec/arel/unit/relations/array_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Array do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [:id, :name]) - end - - describe '#attributes' do - it 'manufactures attributes corresponding to the names given on construction' do - @relation.attributes.should == [ - Attribute.new(@relation, :id), - Attribute.new(@relation, :name) - ] - end - end - - describe '#call' do - it "manufactures an array of hashes of attributes to values" do - @relation.call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } - ] - end - - describe 'where' do - it 'filters the relation with the provided predicate' do - @relation.where(@relation[:id].lt(3)).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] - end - end - - describe 'group' do - it 'sorts the relation with the provided ordering' do - end - end - - describe 'order' do - it 'sorts the relation with the provided ordering' do - @relation.order(@relation[:id].desc).call.should == [ - { @relation[:id] => 3, @relation[:name] => 'goose' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 1, @relation[:name] => 'duck' } - ] - end - end - - describe 'project' do - it 'projects' do - @relation.project(@relation[:id]).call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 }, - { @relation[:id] => 3 } - ] - end - end - - describe 'skip' do - it 'slices' do - @relation.skip(1).call.should == [ - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } - ] - end - end - - describe 'take' do - it 'dices' do - @relation.take(2).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] - end - end - - describe 'join' do - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/delete_spec.rb b/spec/arel/unit/relations/delete_spec.rb deleted file mode 100644 index 23aca563f7..0000000000 --- a/spec/arel/unit/relations/delete_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Deletion do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql deleting a table relation' do - sql = Deletion.new(@relation).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{DELETE FROM `users`}) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{DELETE FROM "users"}) - end - end - - it 'manufactures sql deleting a where relation' do - sql = Deletion.new(@relation.where(@relation[:id].eq(1))).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - DELETE - FROM `users` - WHERE `users`.`id` = 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - DELETE - FROM "users" - WHERE "users"."id" = 1 - }) - end - end - - it "manufactures sql deleting a ranged relation" do - sql = Deletion.new(@relation.take(1)).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - DELETE - FROM `users` - LIMIT 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - DELETE - FROM "users" - LIMIT 1 - }) - end - end - end - end -end diff --git a/spec/arel/unit/relations/group_spec.rb b/spec/arel/unit/relations/group_spec.rb deleted file mode 100644 index 658c0ad406..0000000000 --- a/spec/arel/unit/relations/group_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Group do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe 'when given a predicate' do - it "manufactures sql with where clause conditions" do - sql = Group.new(@relation, @attribute).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY `users`.`id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - GROUP BY "users"."id" - }) - end - end - end - - describe 'when given a string' do - it "passes the string through to the where clause" do - sql = Group.new(@relation, 'asdf').to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - GROUP BY asdf - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - GROUP BY asdf - }) - end - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/insert_spec.rb b/spec/arel/unit/relations/insert_spec.rb deleted file mode 100644 index 5ab3ef1299..0000000000 --- a/spec/arel/unit/relations/insert_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Insert do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it 'manufactures sql inserting data when given multiple rows' do - pending 'it should insert multiple rows' do - @insertion = Insert.new(@relation, [@relation[:name] => "nick", @relation[:name] => "bryan"]) - - @insertion.to_sql.should be_like(" - INSERT - INTO `users` - (`name`) VALUES ('nick'), ('bryan') - ") - end - end - - it 'manufactures sql inserting data when given multiple values' do - @insertion = Insert.new(@relation, @relation[:id] => "1", @relation[:name] => "nick") - - adapter_is :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO `users` - (`id`, `name`) VALUES (1, 'nick') - }) - end - - adapter_is_not :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("id", "name") VALUES (1, 'nick') - }) - end - end - - describe 'when given values whose types correspond to the types of the attributes' do - before do - @insertion = Insert.new(@relation, @relation[:name] => "nick") - end - - it 'manufactures sql inserting data' do - adapter_is :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO `users` - (`name`) VALUES ('nick') - }) - end - - adapter_is_not :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("name") VALUES ('nick') - }) - end - end - end - - describe 'when given values whose types differ from from the types of the attributes' do - before do - @insertion = Insert.new(@relation, @relation[:id] => '1-asdf') - end - - it 'manufactures sql inserting data' do - adapter_is :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO `users` - (`id`) VALUES (1) - }) - end - - adapter_is_not :mysql do - @insertion.to_sql.should be_like(%Q{ - INSERT - INTO "users" - ("id") VALUES (1) - }) - end - end - end - end - end -end diff --git a/spec/arel/unit/relations/join_spec.rb b/spec/arel/unit/relations/join_spec.rb deleted file mode 100644 index 0e3e6ef16b..0000000000 --- a/spec/arel/unit/relations/join_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Join do - before do - @relation1 = Table.new(:users) - @relation2 = Table.new(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) - end - - describe 'hashing' do - it 'implements hash equality' do - InnerJoin.new(@relation1, @relation2, @predicate) \ - .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) - end - end - - describe '#engine' do - it "delegates to a relation's engine" do - InnerJoin.new(@relation1, @relation2, @predicate).engine.should == @relation1.engine - end - end - - describe '#attributes' do - it 'combines the attributes of the two relations' do - join = InnerJoin.new(@relation1, @relation2, @predicate) - join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } - end - end - - describe '#to_sql' do - describe 'when joining with another relation' do - it 'manufactures sql joining the two tables on the predicate' do - sql = InnerJoin.new(@relation1, @relation2, @predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` - FROM `users` - INNER JOIN `photos` ON `users`.`id` = `photos`.`user_id` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" - FROM "users" - INNER JOIN "photos" ON "users"."id" = "photos"."user_id" - }) - end - end - end - - describe 'when joining with a string' do - it "passes the string through to the where clause" do - sql = StringJoin.new(@relation1, "INNER JOIN asdf ON fdsa").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - INNER JOIN asdf ON fdsa - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - INNER JOIN asdf ON fdsa - }) - end - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/order_spec.rb b/spec/arel/unit/relations/order_spec.rb deleted file mode 100644 index cb0f1de84c..0000000000 --- a/spec/arel/unit/relations/order_spec.rb +++ /dev/null @@ -1,113 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Order do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#to_sql' do - describe "when given an attribute" do - it "manufactures sql with an order clause populated by the attribute" do - sql = Order.new(@relation, @attribute).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` ASC - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY "users"."id" ASC - }) - end - end - end - - describe "when given multiple attributes" do - before do - @another_attribute = @relation[:name] - end - - it "manufactures sql with an order clause populated by comma-separated attributes" do - sql = Order.new(@relation, @attribute, @another_attribute).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`id` ASC, `users`.`name` ASC - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY "users"."id" ASC, "users"."name" ASC - }) - end - end - end - - describe "when given a string" do - before do - @string = "asdf" - end - - it "passes the string through to the order clause" do - sql = Order.new(@relation, @string).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY asdf - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY asdf - }) - end - end - end - - describe "when ordering an ordered relation" do - before do - @ordered_relation = Order.new(@relation, @attribute) - @another_attribute = @relation[:name] - end - - it "manufactures sql with the order clause of the last ordering preceding the first ordering" do - sql = Order.new(@ordered_relation, @another_attribute).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - ORDER BY `users`.`name` ASC, `users`.`id` ASC - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - ORDER BY "users"."name" ASC, "users"."id" ASC - }) - end - end - end - end - end -end diff --git a/spec/arel/unit/relations/project_spec.rb b/spec/arel/unit/relations/project_spec.rb deleted file mode 100644 index d2d1fb3873..0000000000 --- a/spec/arel/unit/relations/project_spec.rb +++ /dev/null @@ -1,134 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Project do - before do - @relation = Table.new(:users) - @attribute = @relation[:id] - end - - describe '#attributes' do - before do - @projection = Project.new(@relation, @attribute) - end - - it "manufactures attributes associated with the projection relation" do - @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } - end - end - - describe '#to_sql' do - describe 'when given an attribute' do - it "manufactures sql with a limited select clause" do - sql = Project.new(@relation, @attribute).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id` - FROM `users` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id" - FROM "users" - }) - end - end - end - - describe 'when given a relation' do - before do - @scalar_relation = Project.new(@relation, @relation[:name]) - end - - it "manufactures sql with scalar selects" do - sql = Project.new(@relation, @scalar_relation).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT (SELECT `users`.`name` FROM `users`) AS `users` FROM `users` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT (SELECT "users"."name" FROM "users") AS "users" FROM "users" - }) - end - end - end - - describe 'when given a string' do - it "passes the string through to the select clause" do - sql = Project.new(@relation, 'asdf').to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT asdf FROM `users` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT asdf FROM "users" - }) - end - end - end - - describe 'when given an expression' do - it 'manufactures sql with expressions' do - sql = @relation.project(@attribute.count).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT COUNT(`users`.`id`) AS count_id - FROM `users` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT COUNT("users"."id") AS count_id - FROM "users" - }) - end - end - - it 'manufactures sql with distinct expressions' do - sql = @relation.project(@attribute.count(true)).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT COUNT(DISTINCT `users`.`id`) AS count_id - FROM `users` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT COUNT(DISTINCT "users"."id") AS count_id - FROM "users" - }) - end - end - end - end - - describe '#externalizable?' do - describe 'when the projections are attributes' do - it 'returns false' do - Project.new(@relation, @attribute).should_not be_externalizable - end - end - - describe 'when the projections include an aggregation' do - it "obtains" do - Project.new(@relation, @attribute.sum).should be_externalizable - end - end - end - end -end diff --git a/spec/arel/unit/relations/relation_spec.rb b/spec/arel/unit/relations/relation_spec.rb deleted file mode 100644 index 6a61f39966..0000000000 --- a/spec/arel/unit/relations/relation_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Relation do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - end - - describe '[]' do - describe 'when given an', Attribute do - it "return the attribute congruent to the provided attribute" do - @relation[@attribute1].should == @attribute1 - end - end - - describe 'when given a', Symbol, String do - it "returns the attribute with the same name, if it exists" do - @relation[:id].should == @attribute1 - @relation['id'].should == @attribute1 - @relation[:does_not_exist].should be_nil - end - end - end - - describe Relation::Operable do - describe 'joins' do - before do - @predicate = @relation[:id].eq(@relation[:id]) - end - - describe '#join' do - describe 'when given a relation' do - it "manufactures an inner join operation between those two relations" do - @relation.join(@relation).on(@predicate). \ - should == InnerJoin.new(@relation, @relation, @predicate) - end - end - - describe "when given a string" do - it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) - end - end - - describe "when given something blank" do - it "returns self" do - @relation.join.should == @relation - end - end - end - - describe '#outer_join' do - it "manufactures a left outer join operation between those two relations" do - @relation.outer_join(@relation).on(@predicate). \ - should == OuterJoin.new(@relation, @relation, @predicate) - end - end - end - - describe '#project' do - it "manufactures a projection relation" do - @relation.project(@attribute1, @attribute2). \ - should == Project.new(@relation, @attribute1, @attribute2) - end - - describe "when given blank attributes" do - it "returns self" do - @relation.project.should == @relation - end - end - end - - describe '#alias' do - it "manufactures an alias relation" do - @relation.alias.relation.should == Alias.new(@relation).relation - end - end - - describe '#where' do - before do - @predicate = Equality.new(@attribute1, @attribute2) - end - - it "manufactures a where relation" do - @relation.where(@predicate).should == Where.new(@relation, @predicate) - end - - it "accepts arbitrary strings" do - @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") - end - - describe 'when given a blank predicate' do - it 'returns self' do - @relation.where.should == @relation - end - end - end - - describe '#order' do - it "manufactures an order relation" do - @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) - end - - describe 'when given a blank ordering' do - it 'returns self' do - @relation.order.should == @relation - end - end - end - - describe '#take' do - it "manufactures a take relation" do - @relation.take(5).should == Take.new(@relation, 5) - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.take.should == @relation - end - end - end - - describe '#skip' do - it "manufactures a skip relation" do - @relation.skip(4).should == Skip.new(@relation, 4) - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.skip.should == @relation - end - end - end - - describe '#group' do - it 'manufactures a group relation' do - @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) - end - - describe 'when given blank groupings' do - it 'returns self' do - @relation.group.should == @relation - end - end - end - - describe Relation::Operable::Writable do - describe '#insert' do - it 'manufactures an insertion relation' do - Session.start do - record = {@relation[:name] => 'carl'} - mock(Session.new).create(Insert.new(@relation, record)) - @relation.insert(record).should == @relation - end - end - end - end - end - - describe Relation::Enumerable do - it "implements enumerable" do - @relation.collect.should == @relation.session.read(@relation) - @relation.first.should == @relation.session.read(@relation).first - end - end - end -end diff --git a/spec/arel/unit/relations/skip_spec.rb b/spec/arel/unit/relations/skip_spec.rb deleted file mode 100644 index 2c8f6ccadb..0000000000 --- a/spec/arel/unit/relations/skip_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Skip do - before do - @relation = Table.new(:users) - @skipped = 4 - end - - describe '#to_sql' do - it "manufactures sql with limit and offset" do - sql = Skip.new(@relation, @skipped).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - OFFSET 4 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - OFFSET 4 - }) - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/table_spec.rb b/spec/arel/unit/relations/table_spec.rb deleted file mode 100644 index 2779c0fe5d..0000000000 --- a/spec/arel/unit/relations/table_spec.rb +++ /dev/null @@ -1,99 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Table do - before do - @relation = Table.new(:users) - end - - describe '[]' do - describe 'when given a', Symbol do - it "manufactures an attribute if the symbol names an attribute within the relation" do - @relation[:id].should == Attribute.new(@relation, :id) - @relation[:does_not_exist].should be_nil - end - end - - describe 'when given an', Attribute do - it "returns the attribute if the attribute is within the relation" do - @relation[@relation[:id]].should == @relation[:id] - end - - it "returns nil if the attribtue is not within the relation" do - another_relation = Table.new(:photos) - @relation[another_relation[:id]].should be_nil - end - end - - describe 'when given an', Expression do - before do - @expression = @relation[:id].count - end - - it "returns the Expression if the Expression is within the relation" do - @relation[@expression].should be_nil - end - end - end - - describe '#to_sql' do - it "manufactures a simple select query" do - sql = @relation.to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - }) - end - end - end - - describe '#column_for' do - it "returns the column corresponding to the attribute" do - @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } - end - end - - describe '#attributes' do - it 'manufactures attributes corresponding to columns in the table' do - @relation.attributes.should == [ - Attribute.new(@relation, :id), - Attribute.new(@relation, :name) - ] - end - - describe '#reset' do - it "reloads columns from the database" do - lambda { stub(@relation.engine).columns { [] } }.should_not change { @relation.attributes } - lambda { @relation.reset }.should change { @relation.attributes } - end - end - end - - describe 'hashing' do - it "implements hash equality" do - Table.new(:users).should hash_the_same_as(Table.new(:users)) - Table.new(:users).should_not hash_the_same_as(Table.new(:photos)) - end - end - - describe '#engine' do - it "defaults to global engine" do - Table.engine = engine = Sql::Engine.new - Table.new(:users).engine.should == engine - end - - it "can be specified" do - Table.new(:users, engine = Sql::Engine.new).engine.should == engine - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/take_spec.rb b/spec/arel/unit/relations/take_spec.rb deleted file mode 100644 index d6442fc9d1..0000000000 --- a/spec/arel/unit/relations/take_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Take do - before do - @relation = Table.new(:users) - @taken = 4 - end - - describe '#to_sql' do - it "manufactures sql with limit and offset" do - sql = Take.new(@relation, @taken).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - LIMIT 4 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - LIMIT 4 - }) - end - end - end - end -end \ No newline at end of file diff --git a/spec/arel/unit/relations/update_spec.rb b/spec/arel/unit/relations/update_spec.rb deleted file mode 100644 index e0d7ddd295..0000000000 --- a/spec/arel/unit/relations/update_spec.rb +++ /dev/null @@ -1,121 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Update do - before do - @relation = Table.new(:users) - end - - describe '#to_sql' do - it "manufactures sql updating attributes when given multiple attributes" do - sql = Update.new(@relation, @relation[:id] => 1, @relation[:name] => "nick").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - UPDATE `users` - SET `id` = 1, `name` = 'nick' - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - UPDATE "users" - SET "id" = 1, "name" = 'nick' - }) - end - end - - it "manufactures sql updating attributes when given a ranged relation" do - sql = Update.new(@relation.take(1), @relation[:name] => "nick").to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - UPDATE `users` - SET `name` = 'nick' - LIMIT 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - UPDATE "users" - SET "name" = 'nick' - LIMIT 1 - }) - end - end - - describe 'when given values whose types correspond to the types of the attributes' do - before do - @update = Update.new(@relation, @relation[:name] => "nick") - end - - it 'manufactures sql updating attributes' do - adapter_is :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE `users` - SET `name` = 'nick' - }) - end - - adapter_is_not :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "name" = 'nick' - }) - end - end - end - - describe 'when given values whose types differ from from the types of the attributes' do - before do - @update = Update.new(@relation, @relation[:id] => '1-asdf') - end - - it 'manufactures sql updating attributes' do - adapter_is :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE `users` - SET `id` = 1 - }) - end - - adapter_is_not :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "id" = 1 - }) - end - end - end - - describe 'when the relation is a where' do - before do - @update = Update.new( - @relation.where(@relation[:id].eq(1)), - @relation[:name] => "nick" - ) - end - - it 'manufactures sql updating a where relation' do - adapter_is :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE `users` - SET `name` = 'nick' - WHERE `users`.`id` = 1 - }) - end - - adapter_is_not :mysql do - @update.to_sql.should be_like(%Q{ - UPDATE "users" - SET "name" = 'nick' - WHERE "users"."id" = 1 - }) - end - end - end - end - - end -end diff --git a/spec/arel/unit/relations/where_spec.rb b/spec/arel/unit/relations/where_spec.rb deleted file mode 100644 index 64f97c8135..0000000000 --- a/spec/arel/unit/relations/where_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Where do - before do - @relation = Table.new(:users) - @predicate = @relation[:id].eq(1) - end - - describe '#initialize' do - it "manufactures nested where relations if multiple predicates are provided" do - another_predicate = @relation[:name].lt(2) - Where.new(@relation, @predicate, another_predicate). \ - should == Where.new(Where.new(@relation, another_predicate), @predicate) - end - end - - describe '#to_sql' do - describe 'when given a predicate' do - it "manufactures sql with where clause conditions" do - sql = Where.new(@relation, @predicate).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE `users`.`id` = 1 - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - WHERE "users"."id" = 1 - }) - end - end - end - - describe 'when given a string' do - it "passes the string through to the where clause" do - sql = Where.new(@relation, 'asdf').to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - SELECT `users`.`id`, `users`.`name` - FROM `users` - WHERE asdf - }) - end - - adapter_is_not :mysql do - sql.should be_like(%Q{ - SELECT "users"."id", "users"."name" - FROM "users" - WHERE asdf - }) - end - end - end - end - end -end diff --git a/spec/arel/unit/session/session_spec.rb b/spec/arel/unit/session/session_spec.rb deleted file mode 100644 index c30ba6195f..0000000000 --- a/spec/arel/unit/session/session_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Session do - before do - @relation = Table.new(:users) - @session = Session.new - end - - describe '::start' do - describe '::instance' do - it "it is a singleton within the started session" do - Session.start do - Session.new.should == Session.new - end - end - - it "is a singleton across nested sessions" do - Session.start do - outside = Session.new - Session.start do - Session.new.should == outside - end - end - end - - it "manufactures new sessions outside of the started session" do - Session.new.should_not == Session.new - end - end - end - - describe Session::CRUD do - before do - @insert = Insert.new(@relation, @relation[:name] => 'nick') - @update = Update.new(@relation, @relation[:name] => 'nick') - @delete = Deletion.new(@relation) - @read = @relation - end - - describe '#create' do - it "executes an insertion on the connection" do - mock(@insert).call - @session.create(@insert) - end - end - - describe '#read' do - it "executes an selection on the connection" do - mock(@read).call - @session.read(@read) - end - - it "is memoized" do - mock(@read).call.once - @session.read(@read) - @session.read(@read) - end - end - - describe '#update' do - it "executes an update on the connection" do - mock(@update).call - @session.update(@update) - end - end - - describe '#delete' do - it "executes a delete on the connection" do - mock(@delete).call - @session.delete(@delete) - end - end - end - - describe 'Transactions' do - describe '#begin' do - end - - describe '#end' do - end - end - end -end -- cgit v1.2.3 From 4c71e3b2ea4b8da574954cbd8a26d12f2cc640d0 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:41:49 -0400 Subject: removed duplicates from sql tests Conflicts: spec/arel/engines/sql/unit/predicates/binary_spec.rb spec/arel/engines/sql/unit/predicates/equality_spec.rb spec/arel/engines/sql/unit/primitives/attribute_spec.rb spec/arel/engines/sql/unit/primitives/expression_spec.rb spec/arel/engines/sql/unit/relations/alias_spec.rb spec/arel/engines/sql/unit/relations/join_spec.rb spec/arel/engines/sql/unit/relations/project_spec.rb spec/arel/engines/sql/unit/relations/relation_spec.rb spec/arel/engines/sql/unit/relations/table_spec.rb spec/arel/engines/sql/unit/relations/where_spec.rb spec/arel/engines/sql/unit/session/session_spec.rb --- .../engines/memory/unit/relations/array_spec.rb | 87 +++++++++++ .../engines/sql/unit/predicates/binary_spec.rb | 20 --- .../engines/sql/unit/predicates/equality_spec.rb | 15 -- .../engines/sql/unit/primitives/attribute_spec.rb | 141 +---------------- .../engines/sql/unit/primitives/expression_spec.rb | 29 ---- .../arel/engines/sql/unit/primitives/value_spec.rb | 6 - spec/arel/engines/sql/unit/relations/alias_spec.rb | 7 - spec/arel/engines/sql/unit/relations/array_spec.rb | 87 ----------- spec/arel/engines/sql/unit/relations/join_spec.rb | 21 --- .../engines/sql/unit/relations/project_spec.rb | 24 --- .../engines/sql/unit/relations/relation_spec.rb | 169 --------------------- spec/arel/engines/sql/unit/relations/table_spec.rb | 30 ---- spec/arel/engines/sql/unit/relations/where_spec.rb | 8 - spec/arel/engines/sql/unit/session/session_spec.rb | 84 ---------- 14 files changed, 88 insertions(+), 640 deletions(-) create mode 100644 spec/arel/engines/memory/unit/relations/array_spec.rb delete mode 100644 spec/arel/engines/sql/unit/relations/array_spec.rb delete mode 100644 spec/arel/engines/sql/unit/relations/relation_spec.rb delete mode 100644 spec/arel/engines/sql/unit/session/session_spec.rb diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb new file mode 100644 index 0000000000..8d40858c5f --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -0,0 +1,87 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Array do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#attributes' do + it 'manufactures attributes corresponding to the names given on construction' do + @relation.attributes.should == [ + Attribute.new(@relation, :id), + Attribute.new(@relation, :name) + ] + end + end + + describe '#call' do + it "manufactures an array of hashes of attributes to values" do + @relation.call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } + ] + end + + describe 'where' do + it 'filters the relation with the provided predicate' do + @relation.where(@relation[:id].lt(3)).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'group' do + it 'sorts the relation with the provided ordering' do + end + end + + describe 'order' do + it 'sorts the relation with the provided ordering' do + @relation.order(@relation[:id].desc).call.should == [ + { @relation[:id] => 3, @relation[:name] => 'goose' }, + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 1, @relation[:name] => 'duck' } + ] + end + end + + describe 'project' do + it 'projects' do + @relation.project(@relation[:id]).call.should == [ + { @relation[:id] => 1 }, + { @relation[:id] => 2 }, + { @relation[:id] => 3 } + ] + end + end + + describe 'skip' do + it 'slices' do + @relation.skip(1).call.should == [ + { @relation[:id] => 2, @relation[:name] => 'duck' }, + { @relation[:id] => 3, @relation[:name] => 'goose' } + ] + end + end + + describe 'take' do + it 'dices' do + @relation.take(2).call.should == [ + { @relation[:id] => 1, @relation[:name] => 'duck' }, + { @relation[:id] => 2, @relation[:name] => 'duck' } + ] + end + end + + describe 'join' do + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 03574225c2..679147067e 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -101,25 +101,5 @@ module Arel end end end - - describe '#bind' do - before do - @another_relation = @relation.alias - end - - describe 'when both operands are attributes' do - it "manufactures an expression with the attributes bound to the relation" do - ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ - should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) - end - end - - describe 'when an operand is a value' do - it "manufactures an expression with unmodified values" do - ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ - should == ConcreteBinary.new(@attribute1.find_correlate_in(@another_relation), "asdf".find_correlate_in(@another_relation)) - end - end - end end end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index 2ab79d7028..e8c8c42675 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -9,21 +9,6 @@ module Arel @attribute2 = @relation2[:user_id] end - describe '==' do - it "obtains if attribute1 and attribute2 are identical" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) - Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) - end - - it "obtains if the concrete type of the predicates are identical" do - Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) - end - - it "is commutative on the attributes" do - Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) - end - end - describe '#to_sql' do describe 'when relating to a non-nil value' do it "manufactures an equality predicate" do diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index f37cd14370..e71ab949f1 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -7,67 +7,12 @@ module Arel @attribute = @relation[:id] end - describe Attribute::Transformations do - describe '#as' do - it "manufactures an aliased attributed" do - @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) - end - end - - describe '#bind' do - it "manufactures an attribute with the relation bound and self as an ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) - end - - it "returns self if the substituting to the same relation" do - @attribute.bind(@relation).should == @attribute - end - end - - describe '#to_attribute' do - it "returns self" do - @attribute.to_attribute.should == @attribute - end - end - end - describe '#column' do it "returns the corresponding column in the relation" do @attribute.column.should == @relation.column_for(@attribute) end end - - describe '#engine' do - it "delegates to its relation" do - Attribute.new(@relation, :id).engine.should == @relation.engine - end - end - - describe Attribute::Congruence do - describe '/' do - before do - @aliased_relation = @relation.alias - @doubly_aliased_relation = @aliased_relation.alias - end - - describe 'when dividing two unrelated attributes' do - it "returns 0.0" do - (@relation[:id] / @relation[:name]).should == 0.0 - end - end - - describe 'when dividing two matching attributes' do - it 'returns a the highest score for the most similar attributes' do - (@aliased_relation[:id] / @relation[:id]) \ - .should == (@aliased_relation[:id] / @relation[:id]) - (@aliased_relation[:id] / @relation[:id]) \ - .should < (@aliased_relation[:id] / @aliased_relation[:id]) - end - end - end - end - + describe '#to_sql' do describe 'for a simple attribute' do it "manufactures sql with an alias" do @@ -83,89 +28,5 @@ module Arel end end end - - describe Attribute::Predications do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#eq' do - it "manufactures an equality predicate" do - @attribute.eq('name').should == Equality.new(@attribute, 'name') - end - end - - describe '#lt' do - it "manufactures a less-than predicate" do - @attribute.lt(10).should == LessThan.new(@attribute, 10) - end - end - - describe '#lteq' do - it "manufactures a less-than or equal-to predicate" do - @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#gt' do - it "manufactures a greater-than predicate" do - @attribute.gt(10).should == GreaterThan.new(@attribute, 10) - end - end - - describe '#gteq' do - it "manufactures a greater-than or equal-to predicate" do - @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) - end - end - - describe '#matches' do - it "manufactures a match predicate" do - @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) - end - end - - describe '#in' do - it "manufactures an in predicate" do - @attribute.in(1..30).should == In.new(@attribute, (1..30)) - end - end - end - - describe Attribute::Expressions do - before do - @attribute = Attribute.new(@relation, :name) - end - - describe '#count' do - it "manufactures a count Expression" do - @attribute.count.should == Count.new(@attribute) - end - end - - describe '#sum' do - it "manufactures a sum Expression" do - @attribute.sum.should == Sum.new(@attribute) - end - end - - describe '#maximum' do - it "manufactures a maximum Expression" do - @attribute.maximum.should == Maximum.new(@attribute) - end - end - - describe '#minimum' do - it "manufactures a minimum Expression" do - @attribute.minimum.should == Minimum.new(@attribute) - end - end - - describe '#average' do - it "manufactures an average Expression" do - @attribute.average.should == Average.new(@attribute) - end - end - end end end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/primitives/expression_spec.rb b/spec/arel/engines/sql/unit/primitives/expression_spec.rb index 0869d9e403..ee7f2c1461 100644 --- a/spec/arel/engines/sql/unit/primitives/expression_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/expression_spec.rb @@ -7,35 +7,6 @@ module Arel @attribute = @relation[:id] end - describe Expression::Transformations do - before do - @expression = Count.new(@attribute) - end - - describe '#bind' do - it "manufactures an attribute with a rebound relation and self as the ancestor" do - derived_relation = @relation.where(@relation[:id].eq(1)) - @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) - end - - it "returns self if the substituting to the same relation" do - @expression.bind(@relation).should == @expression - end - end - - describe '#as' do - it "manufactures an aliased expression" do - @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) - end - end - - describe '#to_attribute' do - it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) - end - end - end - describe '#to_sql' do it "manufactures sql with the expression and alias" do sql = Count.new(@attribute, :alias).to_sql diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb index f76323f32b..da5a163d3b 100644 --- a/spec/arel/engines/sql/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -18,11 +18,5 @@ module Arel Value.new(1, @relation).format(@relation[:id]).should == @relation[:id].to_sql end end - - describe '#bind' do - it "manufactures a new value whose relation is the provided relation" do - Value.new(1, @relation).bind(another_relation = Table.new(:photos)).should == Value.new(1, another_relation) - end - end end end diff --git a/spec/arel/engines/sql/unit/relations/alias_spec.rb b/spec/arel/engines/sql/unit/relations/alias_spec.rb index 83b9113f6d..b67a0bbc89 100644 --- a/spec/arel/engines/sql/unit/relations/alias_spec.rb +++ b/spec/arel/engines/sql/unit/relations/alias_spec.rb @@ -6,13 +6,6 @@ module Arel @relation = Table.new(:users) end - describe '==' do - it "obtains if the objects are the same" do - Alias.new(@relation).should_not == Alias.new(@relation) - (aliaz = Alias.new(@relation)).should == aliaz - end - end - describe '#to_sql' do describe 'when there is no ambiguity' do it 'does not alias table names anywhere a table name can appear' do diff --git a/spec/arel/engines/sql/unit/relations/array_spec.rb b/spec/arel/engines/sql/unit/relations/array_spec.rb deleted file mode 100644 index 8d40858c5f..0000000000 --- a/spec/arel/engines/sql/unit/relations/array_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') - -module Arel - describe Array do - before do - @relation = Array.new([ - [1, 'duck' ], - [2, 'duck' ], - [3, 'goose'] - ], [:id, :name]) - end - - describe '#attributes' do - it 'manufactures attributes corresponding to the names given on construction' do - @relation.attributes.should == [ - Attribute.new(@relation, :id), - Attribute.new(@relation, :name) - ] - end - end - - describe '#call' do - it "manufactures an array of hashes of attributes to values" do - @relation.call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } - ] - end - - describe 'where' do - it 'filters the relation with the provided predicate' do - @relation.where(@relation[:id].lt(3)).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] - end - end - - describe 'group' do - it 'sorts the relation with the provided ordering' do - end - end - - describe 'order' do - it 'sorts the relation with the provided ordering' do - @relation.order(@relation[:id].desc).call.should == [ - { @relation[:id] => 3, @relation[:name] => 'goose' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 1, @relation[:name] => 'duck' } - ] - end - end - - describe 'project' do - it 'projects' do - @relation.project(@relation[:id]).call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 }, - { @relation[:id] => 3 } - ] - end - end - - describe 'skip' do - it 'slices' do - @relation.skip(1).call.should == [ - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } - ] - end - end - - describe 'take' do - it 'dices' do - @relation.take(2).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] - end - end - - describe 'join' do - end - end - end -end \ No newline at end of file diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index ea17f8106f..1f43101133 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -8,27 +8,6 @@ module Arel @predicate = @relation1[:id].eq(@relation2[:user_id]) end - describe 'hashing' do - it 'implements hash equality' do - InnerJoin.new(@relation1, @relation2, @predicate) \ - .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) - end - end - - describe '#engine' do - it "delegates to a relation's engine" do - InnerJoin.new(@relation1, @relation2, @predicate).engine.should == @relation1.engine - end - end - - describe '#attributes' do - it 'combines the attributes of the two relations' do - join = InnerJoin.new(@relation1, @relation2, @predicate) - join.attributes.should == - (@relation1.attributes + @relation2.attributes).collect { |a| a.bind(join) } - end - end - describe '#to_sql' do describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do diff --git a/spec/arel/engines/sql/unit/relations/project_spec.rb b/spec/arel/engines/sql/unit/relations/project_spec.rb index 9d6b9fab06..5e29124cfa 100644 --- a/spec/arel/engines/sql/unit/relations/project_spec.rb +++ b/spec/arel/engines/sql/unit/relations/project_spec.rb @@ -7,16 +7,6 @@ module Arel @attribute = @relation[:id] end - describe '#attributes' do - before do - @projection = Project.new(@relation, @attribute) - end - - it "manufactures attributes associated with the projection relation" do - @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } - end - end - describe '#to_sql' do describe 'when given an attribute' do it "manufactures sql with a limited select clause" do @@ -116,19 +106,5 @@ module Arel end end end - - describe '#externalizable?' do - describe 'when the projections are attributes' do - it 'returns false' do - Project.new(@relation, @attribute).should_not be_externalizable - end - end - - describe 'when the projections include an aggregation' do - it "obtains" do - Project.new(@relation, @attribute.sum).should be_externalizable - end - end - end end end diff --git a/spec/arel/engines/sql/unit/relations/relation_spec.rb b/spec/arel/engines/sql/unit/relations/relation_spec.rb deleted file mode 100644 index 9a5cfbff41..0000000000 --- a/spec/arel/engines/sql/unit/relations/relation_spec.rb +++ /dev/null @@ -1,169 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') - -module Arel - describe Relation do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - end - - describe '[]' do - describe 'when given an', Attribute do - it "return the attribute congruent to the provided attribute" do - @relation[@attribute1].should == @attribute1 - end - end - - describe 'when given a', Symbol, String do - it "returns the attribute with the same name, if it exists" do - @relation[:id].should == @attribute1 - @relation['id'].should == @attribute1 - @relation[:does_not_exist].should be_nil - end - end - end - - describe Relation::Operable do - describe 'joins' do - before do - @predicate = @relation[:id].eq(@relation[:id]) - end - - describe '#join' do - describe 'when given a relation' do - it "manufactures an inner join operation between those two relations" do - @relation.join(@relation).on(@predicate). \ - should == InnerJoin.new(@relation, @relation, @predicate) - end - end - - describe "when given a string" do - it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) - end - end - - describe "when given something blank" do - it "returns self" do - @relation.join.should == @relation - end - end - end - - describe '#outer_join' do - it "manufactures a left outer join operation between those two relations" do - @relation.outer_join(@relation).on(@predicate). \ - should == OuterJoin.new(@relation, @relation, @predicate) - end - end - end - - describe '#project' do - it "manufactures a projection relation" do - @relation.project(@attribute1, @attribute2). \ - should == Project.new(@relation, @attribute1, @attribute2) - end - - describe "when given blank attributes" do - it "returns self" do - @relation.project.should == @relation - end - end - end - - describe '#alias' do - it "manufactures an alias relation" do - @relation.alias.relation.should == Alias.new(@relation).relation - end - end - - describe '#where' do - before do - @predicate = Equality.new(@attribute1, @attribute2) - end - - it "manufactures a where relation" do - @relation.where(@predicate).should == Where.new(@relation, @predicate) - end - - it "accepts arbitrary strings" do - @relation.where("arbitrary").should == Where.new(@relation, "arbitrary") - end - - describe 'when given a blank predicate' do - it 'returns self' do - @relation.where.should == @relation - end - end - end - - describe '#order' do - it "manufactures an order relation" do - @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) - end - - describe 'when given a blank ordering' do - it 'returns self' do - @relation.order.should == @relation - end - end - end - - describe '#take' do - it "manufactures a take relation" do - @relation.take(5).should == Take.new(@relation, 5) - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.take.should == @relation - end - end - end - - describe '#skip' do - it "manufactures a skip relation" do - @relation.skip(4).should == Skip.new(@relation, 4) - end - - describe 'when given a blank number of items' do - it 'returns self' do - @relation.skip.should == @relation - end - end - end - - describe '#group' do - it 'manufactures a group relation' do - @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) - end - - describe 'when given blank groupings' do - it 'returns self' do - @relation.group.should == @relation - end - end - end - - describe Relation::Operable::Writable do - describe '#insert' do - it 'manufactures an insertion relation' do - Session.start do - record = {@relation[:name] => 'carl'} - mock(Session.new).create(Insert.new(@relation, record)) - @relation.insert(record).should == @relation - end - end - end - end - end - - describe Relation::Enumerable do - it "implements enumerable" do - @relation.collect.should == @relation.session.read(@relation) - @relation.first.should == @relation.session.read(@relation).first - end - end - end -end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 6de49a9157..3f5a5ac248 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -6,36 +6,6 @@ module Arel @relation = Table.new(:users) end - describe '[]' do - describe 'when given a', Symbol do - it "manufactures an attribute if the symbol names an attribute within the relation" do - @relation[:id].should == Attribute.new(@relation, :id) - @relation[:does_not_exist].should be_nil - end - end - - describe 'when given an', Attribute do - it "returns the attribute if the attribute is within the relation" do - @relation[@relation[:id]].should == @relation[:id] - end - - it "returns nil if the attribtue is not within the relation" do - another_relation = Table.new(:photos) - @relation[another_relation[:id]].should be_nil - end - end - - describe 'when given an', Expression do - before do - @expression = @relation[:id].count - end - - it "returns the Expression if the Expression is within the relation" do - @relation[@expression].should be_nil - end - end - end - describe '#to_sql' do it "manufactures a simple select query" do sql = @relation.to_sql diff --git a/spec/arel/engines/sql/unit/relations/where_spec.rb b/spec/arel/engines/sql/unit/relations/where_spec.rb index 5870b6b793..4f0cce1e01 100644 --- a/spec/arel/engines/sql/unit/relations/where_spec.rb +++ b/spec/arel/engines/sql/unit/relations/where_spec.rb @@ -7,14 +7,6 @@ module Arel @predicate = @relation[:id].eq(1) end - describe '#initialize' do - it "manufactures nested where relations if multiple predicates are provided" do - another_predicate = @relation[:name].lt(2) - Where.new(@relation, @predicate, another_predicate). \ - should == Where.new(Where.new(@relation, another_predicate), @predicate) - end - end - describe '#to_sql' do describe 'when given a predicate' do it "manufactures sql with where clause conditions" do diff --git a/spec/arel/engines/sql/unit/session/session_spec.rb b/spec/arel/engines/sql/unit/session/session_spec.rb deleted file mode 100644 index c489984a61..0000000000 --- a/spec/arel/engines/sql/unit/session/session_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') - -module Arel - describe Session do - before do - @relation = Table.new(:users) - @session = Session.new - end - - describe '::start' do - describe '::instance' do - it "it is a singleton within the started session" do - Session.start do - Session.new.should == Session.new - end - end - - it "is a singleton across nested sessions" do - Session.start do - outside = Session.new - Session.start do - Session.new.should == outside - end - end - end - - it "manufactures new sessions outside of the started session" do - Session.new.should_not == Session.new - end - end - end - - describe Session::CRUD do - before do - @insert = Insert.new(@relation, @relation[:name] => 'nick') - @update = Update.new(@relation, @relation[:name] => 'nick') - @delete = Deletion.new(@relation) - @read = @relation - end - - describe '#create' do - it "executes an insertion on the connection" do - mock(@insert).call - @session.create(@insert) - end - end - - describe '#read' do - it "executes an selection on the connection" do - mock(@read).call - @session.read(@read) - end - - it "is memoized" do - mock(@read).call.once - @session.read(@read) - @session.read(@read) - end - end - - describe '#update' do - it "executes an update on the connection" do - mock(@update).call - @session.update(@update) - end - end - - describe '#delete' do - it "executes a delete on the connection" do - mock(@delete).call - @session.delete(@delete) - end - end - end - - describe 'Transactions' do - describe '#begin' do - end - - describe '#end' do - end - end - end -end -- cgit v1.2.3 From 8339f024c7663133a78c4d0a8824b5b6fafaf239 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:42:42 -0400 Subject: recursive memory operations now possible Conflicts: lib/arel/algebra/relations/relation.rb --- doc/TODO | 7 +- lib/arel/algebra/extensions/hash.rb | 7 -- lib/arel/algebra/relations.rb | 1 + lib/arel/algebra/relations/relation.rb | 4 -- lib/arel/algebra/relations/row.rb | 21 ++++++ lib/arel/engines/memory/predicates.rb | 6 ++ lib/arel/engines/memory/relations.rb | 1 + lib/arel/engines/memory/relations/array.rb | 2 +- lib/arel/engines/memory/relations/compound.rb | 4 ++ lib/arel/engines/memory/relations/operations.rb | 10 +-- lib/arel/engines/memory/relations/relation.rb | 7 ++ .../engines/memory/unit/relations/array_spec.rb | 83 +++++++++++++++------- 12 files changed, 107 insertions(+), 46 deletions(-) create mode 100644 lib/arel/algebra/relations/row.rb create mode 100644 lib/arel/engines/memory/relations/relation.rb diff --git a/doc/TODO b/doc/TODO index f97e74ef17..7af8db6bdf 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,11 +1,11 @@ todo: -- reorganize sql tests +- recursive memory operations - reorganize memory tests -- blocks for joins +- deal with table tests in algebra - implement joins in memory -- recursive memory operations - result sets should be array relations - cross-engine joins +- blocks for joins - fix grouping - implement mnesia adapter - fix AR @@ -92,6 +92,7 @@ done: - expressions should be class-based, and joins too, anything _sql should be renamed - implement in memory adapter - clean up block_given stuff +- reorganize sql tests icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index bc97785e62..7472b5aa73 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -4,11 +4,4 @@ class Hash bound.merge(key.bind(relation) => value.bind(relation)) end end - - def slice(*attributes) - inject({}) do |cheese, (key, value)| - cheese[key] = value if attributes.include?(key) - cheese - end - end end \ No newline at end of file diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index b75a31e5e3..94df5938fe 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -2,6 +2,7 @@ require 'arel/algebra/relations/relation' require 'arel/algebra/relations/utilities/compound' require 'arel/algebra/relations/utilities/nil' require 'arel/algebra/relations/utilities/externalization' +require 'arel/algebra/relations/row' require 'arel/algebra/relations/writes' require 'arel/algebra/relations/operations/alias' require 'arel/algebra/relations/operations/group' diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index 6d76e66638..fe8cab4b02 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -14,10 +14,6 @@ module Arel self end - def root - self - end - module Enumerable include ::Enumerable diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb new file mode 100644 index 0000000000..2d63498452 --- /dev/null +++ b/lib/arel/algebra/relations/row.rb @@ -0,0 +1,21 @@ +module Arel + class Row + attributes :relation, :tuple + deriving :==, :initialize + + def [](attribute) + tuple[relation.position_of(attribute)] + end + + def slice(*attributes) + Row.new(relation, attributes.inject([]) do |cheese, attribute| + cheese << self[attribute] + cheese + end) + end + + def bind(relation) + Row.new(relation, tuple) + end + end +end \ No newline at end of file diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index bbf39ba794..e233f3ba39 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -21,15 +21,19 @@ module Arel end class Equality < Binary + def operator; :== end end class GreaterThanOrEqualTo < Binary + def operator; :>= end end class GreaterThan < Binary + def operator; :> end end class LessThanOrEqualTo < Binary + def operator; :<= end end class LessThan < Binary @@ -37,8 +41,10 @@ module Arel end class Match < Binary + def operator; :=~ end end class In < Binary + def operator; :include? end end end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 1b009537b9..820b0af4b2 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,3 +1,4 @@ +require 'arel/engines/memory/relations/relation' require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index c02c62891b..ea0b5af5ba 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -15,7 +15,7 @@ module Arel end def eval - @array.collect { |row| attributes.zip(row).to_hash } + @array.collect { |r| Row.new(self, r) } end end end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index b029082d57..3791fa4622 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -1,5 +1,9 @@ module Arel class Compound < Relation delegate :array, :to => :relation + + def unoperated_rows + relation.eval.collect { |row| row.bind(self) } + end end end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 115df054df..8e03aca7b1 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -1,13 +1,13 @@ module Arel class Where < Compound def eval - relation.eval.select { |row| predicate.eval(row) } + unoperated_rows.select { |row| predicate.eval(row) } end end class Order < Compound def eval - relation.eval.sort do |row1, row2| + unoperated_rows.sort do |row1, row2| ordering = orderings.detect { |o| o.eval(row1, row2) != 0 } || orderings.last ordering.eval(row1, row2) end @@ -16,19 +16,19 @@ module Arel class Project < Compound def eval - relation.eval.collect { |r| r.slice(*projections) } + unoperated_rows.collect { |r| r.slice(*projections) } end end class Take < Compound def eval - relation.eval[0, taken] + unoperated_rows[0, taken] end end class Skip < Compound def eval - relation.eval[skipped..-1] + unoperated_rows[skipped..-1] end end diff --git a/lib/arel/engines/memory/relations/relation.rb b/lib/arel/engines/memory/relations/relation.rb new file mode 100644 index 0000000000..abfb8bb37f --- /dev/null +++ b/lib/arel/engines/memory/relations/relation.rb @@ -0,0 +1,7 @@ +module Arel + class Relation + def position_of(attribute) + attributes.index(self[attribute]) + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 8d40858c5f..22cddf7156 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -22,61 +22,92 @@ module Arel describe '#call' do it "manufactures an array of hashes of attributes to values" do @relation.call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } + Row.new(@relation, [1, 'duck']), + Row.new(@relation, [2, 'duck']), + Row.new(@relation, [3, 'goose']) ] end describe 'where' do + xit 'filters the relation with the provided predicate' do + @relation \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end + end + it 'filters the relation with the provided predicate' do - @relation.where(@relation[:id].lt(3)).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] + @relation \ + .where(@relation[:id].gt(1)) \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']) + ] + end end end describe 'group' do - it 'sorts the relation with the provided ordering' do + xit 'sorts the relation with the provided ordering' do end end describe 'order' do it 'sorts the relation with the provided ordering' do - @relation.order(@relation[:id].desc).call.should == [ - { @relation[:id] => 3, @relation[:name] => 'goose' }, - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 1, @relation[:name] => 'duck' } - ] + @relation \ + .order(@relation[:id].desc) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [3, 'goose']), + Row.new(relation, [2, 'duck']), + Row.new(relation, [1, 'duck']) + ] + end end end describe 'project' do it 'projects' do - @relation.project(@relation[:id]).call.should == [ - { @relation[:id] => 1 }, - { @relation[:id] => 2 }, - { @relation[:id] => 3 } - ] + @relation \ + .project(@relation[:id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1]), + Row.new(relation, [2]), + Row.new(relation, [3]) + ] + end end end describe 'skip' do it 'slices' do - @relation.skip(1).call.should == [ - { @relation[:id] => 2, @relation[:name] => 'duck' }, - { @relation[:id] => 3, @relation[:name] => 'goose' } - ] + @relation \ + .skip(1) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + ] + end end end describe 'take' do it 'dices' do - @relation.take(2).call.should == [ - { @relation[:id] => 1, @relation[:name] => 'duck' }, - { @relation[:id] => 2, @relation[:name] => 'duck' } - ] + @relation \ + .take(2) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end end end -- cgit v1.2.3 From b7f58db57a535806e0cfc3057fbab80ca43b1a53 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:44:03 -0400 Subject: better test ordering Conflicts: doc/TODO --- doc/TODO | 9 +-- .../engines/memory/unit/relations/array_spec.rb | 86 ---------------------- .../engines/memory/unit/relations/order_spec.rb | 27 +++++++ .../engines/memory/unit/relations/project_spec.rb | 27 +++++++ .../engines/memory/unit/relations/skip_spec.rb | 26 +++++++ .../engines/memory/unit/relations/take_spec.rb | 26 +++++++ .../engines/memory/unit/relations/where_spec.rb | 39 ++++++++++ 7 files changed, 149 insertions(+), 91 deletions(-) create mode 100644 spec/arel/engines/memory/unit/relations/order_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/project_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/skip_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/take_spec.rb create mode 100644 spec/arel/engines/memory/unit/relations/where_spec.rb diff --git a/doc/TODO b/doc/TODO index 7af8db6bdf..2070a26efc 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,13 +1,12 @@ todo: -- recursive memory operations - reorganize memory tests -- deal with table tests in algebra - implement joins in memory - result sets should be array relations +- deal with table tests in algebra - cross-engine joins - blocks for joins -- fix grouping - implement mnesia adapter +- fix grouping - fix AR - rename externalize to derived. @@ -15,7 +14,6 @@ todo: - audit unit coverage of algebra - data objects - remove all explicit aliasing -- and/or w/ predicates - scoped writes - refactor adapter pattern - break out adapters into sep modules @@ -26,7 +24,6 @@ todo: done: - and/or w/ predicates -- mock out database . Relation <=> Relation -> InnerJoinOperation . Relation << Relation -> LeftOuterJoinOperation . InnerJoinOperation.on(*Predicate) -> InnerJoinRelation @@ -77,6 +74,7 @@ done: - test Value, in particular bind. - test blank checks in relation.rb - rename active_relation to arel +- mock out database - fix complex joining cases: - active record query adapter - anonymous table names @@ -93,6 +91,7 @@ done: - implement in memory adapter - clean up block_given stuff - reorganize sql tests +- recursive memory operations icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 22cddf7156..4fe24c77fa 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -27,92 +27,6 @@ module Arel Row.new(@relation, [3, 'goose']) ] end - - describe 'where' do - xit 'filters the relation with the provided predicate' do - @relation \ - .where(@relation[:id].lt(3)) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - ] - end - end - - it 'filters the relation with the provided predicate' do - @relation \ - .where(@relation[:id].gt(1)) \ - .where(@relation[:id].lt(3)) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [2, 'duck']) - ] - end - end - end - - describe 'group' do - xit 'sorts the relation with the provided ordering' do - end - end - - describe 'order' do - it 'sorts the relation with the provided ordering' do - @relation \ - .order(@relation[:id].desc) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [3, 'goose']), - Row.new(relation, [2, 'duck']), - Row.new(relation, [1, 'duck']) - ] - end - end - end - - describe 'project' do - it 'projects' do - @relation \ - .project(@relation[:id]) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1]), - Row.new(relation, [2]), - Row.new(relation, [3]) - ] - end - end - end - - describe 'skip' do - it 'slices' do - @relation \ - .skip(1) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [2, 'duck']), - Row.new(relation, [3, 'goose']), - ] - end - end - end - - describe 'take' do - it 'dices' do - @relation \ - .take(2) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, [1, 'duck']), - Row.new(relation, [2, 'duck']), - ] - end - end - end - - describe 'join' do - end end end end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/arel/engines/memory/unit/relations/order_spec.rb new file mode 100644 index 0000000000..3ecb31068b --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/order_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Order do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'sorts the relation with the provided ordering' do + @relation \ + .order(@relation[:id].desc) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [3, 'goose']), + Row.new(relation, [2, 'duck' ]), + Row.new(relation, [1, 'duck' ]) + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/arel/engines/memory/unit/relations/project_spec.rb new file mode 100644 index 0000000000..1d1224cfdc --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/project_spec.rb @@ -0,0 +1,27 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Project do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'retains only the attributes that are provided' do + @relation \ + .project(@relation[:id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1]), + Row.new(relation, [2]), + Row.new(relation, [3]) + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/arel/engines/memory/unit/relations/skip_spec.rb new file mode 100644 index 0000000000..86db45ef61 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/skip_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Skip do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'removes the first n rows' do + @relation \ + .skip(1) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/arel/engines/memory/unit/relations/take_spec.rb new file mode 100644 index 0000000000..8b774987e0 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/take_spec.rb @@ -0,0 +1,26 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Take do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'removes the rows after the first n' do + @relation \ + .take(2) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end + end + end + end +end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/arel/engines/memory/unit/relations/where_spec.rb new file mode 100644 index 0000000000..d75ee5dcbe --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/where_spec.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Where do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it 'filters the relation with the provided predicate' do + @relation \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + ] + end + end + + describe 'when filtering a where relation' do + it 'further filters the already-filtered relation with the provided predicate' do + @relation \ + .where(@relation[:id].gt(1)) \ + .where(@relation[:id].lt(3)) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [2, 'duck']) + ] + end + end + end + end + end +end \ No newline at end of file -- cgit v1.2.3 From 2fe585328d6a24df310d3e60059c9c7b05b64bac Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 27 May 2008 14:19:59 -0700 Subject: performing in memory joins --- doc/TODO | 8 +++--- lib/arel/algebra/relations/row.rb | 4 +++ lib/arel/engines/memory/relations/operations.rb | 21 ++++++++++++++ .../engines/memory/unit/relations/join_spec.rb | 32 ++++++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 spec/arel/engines/memory/unit/relations/join_spec.rb diff --git a/doc/TODO b/doc/TODO index 2070a26efc..3f8c34f660 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,16 +1,13 @@ todo: -- reorganize memory tests -- implement joins in memory - result sets should be array relations - deal with table tests in algebra - cross-engine joins - blocks for joins - implement mnesia adapter -- fix grouping - fix AR - rename externalize to derived. -- result sets to attr correlation too +- fix grouping - audit unit coverage of algebra - data objects - remove all explicit aliasing @@ -92,6 +89,9 @@ done: - clean up block_given stuff - reorganize sql tests - recursive memory operations +- reorganize memory tests +- result sets to attr correlation too +- implement joins in memory icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index 2d63498452..3731dd9696 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -17,5 +17,9 @@ module Arel def bind(relation) Row.new(relation, tuple) end + + def combine(other, relation) + Row.new(relation, tuple + other.tuple) + end end end \ No newline at end of file diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index 8e03aca7b1..e35fbe3234 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -37,4 +37,25 @@ module Arel raise NotImplementedError end end + + class Alias < Compound + def eval + unoperated_rows + end + end + + class Join < Relation + def eval + result = [] + relation1.eval.each do |row1| + relation2.eval.each do |row2| + combined_row = row1.combine(row2, self) + if predicates.all? { |p| p.eval(combined_row) } + result << combined_row + end + end + end + result + end + end end \ No newline at end of file diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb new file mode 100644 index 0000000000..920cc55d0a --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -0,0 +1,32 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @relation1 = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + @relation2 = @relation1.alias + @relation3 = @relation1.alias + end + + describe InnerJoin do + describe '#call' do + it 'combines the two tables where the predicate obtains' do + @relation1 \ + .join(@relation2) \ + .on(@relation1[:id].eq(@relation2[:id])) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck', 1, 'duck' ]), + Row.new(relation, [2, 'duck', 2, 'duck' ]), + Row.new(relation, [3, 'goose', 3, 'goose']) + ] + end + end + end + end + end +end \ No newline at end of file -- cgit v1.2.3 From 20b28b441b651d0404d64049253898c061a039be Mon Sep 17 00:00:00 2001 From: Nick Kallen Date: Tue, 27 May 2008 14:37:11 -0700 Subject: using in memory relations as results from sql relation Conflicts: lib/arel/algebra/primitives/expression.rb lib/arel/algebra/relations/relation.rb --- doc/TODO | 6 +++--- lib/arel/algebra/extensions.rb | 1 + lib/arel/algebra/extensions/symbol.rb | 5 +++++ lib/arel/algebra/primitives/attribute.rb | 4 ++-- lib/arel/algebra/primitives/expression.rb | 2 +- lib/arel/algebra/relations/relation.rb | 11 +++++++++-- lib/arel/algebra/relations/utilities/externalization.rb | 2 +- lib/arel/engines/memory/relations.rb | 1 - lib/arel/engines/memory/relations/array.rb | 4 ++-- lib/arel/engines/memory/relations/relation.rb | 7 ------- lib/arel/engines/sql/engine.rb | 10 +++++----- lib/arel/engines/sql/relations/operations/join.rb | 2 +- spec/arel/algebra/unit/primitives/attribute_spec.rb | 12 ++++++++++-- spec/arel/algebra/unit/primitives/expression_spec.rb | 2 +- spec/arel/algebra/unit/relations/relation_spec.rb | 10 +++++----- 15 files changed, 46 insertions(+), 33 deletions(-) create mode 100644 lib/arel/algebra/extensions/symbol.rb delete mode 100644 lib/arel/engines/memory/relations/relation.rb diff --git a/doc/TODO b/doc/TODO index 3f8c34f660..7e7028d39f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,10 +1,9 @@ todo: -- result sets should be array relations -- deal with table tests in algebra +- fix AR - cross-engine joins - blocks for joins +- deal with table tests in algebra - implement mnesia adapter -- fix AR - rename externalize to derived. - fix grouping @@ -92,6 +91,7 @@ done: - reorganize memory tests - result sets to attr correlation too - implement joins in memory +- result sets should be array relations icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb index 5338fee989..694dc60a2a 100644 --- a/lib/arel/algebra/extensions.rb +++ b/lib/arel/algebra/extensions.rb @@ -1,4 +1,5 @@ require 'arel/algebra/extensions/object' require 'arel/algebra/extensions/class' require 'arel/algebra/extensions/array' +require 'arel/algebra/extensions/symbol' require 'arel/algebra/extensions/hash' diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb new file mode 100644 index 0000000000..787867bdc3 --- /dev/null +++ b/lib/arel/algebra/extensions/symbol.rb @@ -0,0 +1,5 @@ +class Symbol + def to_attribute(relation) + Arel::Attribute.new(relation, self) + end +end \ No newline at end of file diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index 7a4411e248..aa1f2ae00c 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -39,8 +39,8 @@ module Arel relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self) end - def to_attribute - self + def to_attribute(relation) + bind(relation) end end include Transformations diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb index 989397720c..5566e2d0b7 100644 --- a/lib/arel/algebra/primitives/expression.rb +++ b/lib/arel/algebra/primitives/expression.rb @@ -22,7 +22,7 @@ module Arel new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self) end - def to_attribute + def to_attribute(relation) Attribute.new(relation, @alias, :ancestor => self) end end diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index fe8cab4b02..c38ab0e9c5 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -31,7 +31,7 @@ module Arel def join(other_relation = nil, join_class = InnerJoin) case other_relation when String - StringJoin.new(other_relation, self) + StringJoin.new(self, other_relation) when Relation JoinOperation.new(join_class, self, other_relation) else @@ -85,7 +85,8 @@ module Arel find_attribute_matching_name(index) when Attribute, Expression find_attribute_matching_attribute(index) - when Array + when ::Array + # TESTME index.collect { |i| self[i] } end end @@ -100,6 +101,12 @@ module Arel end end + def position_of(attribute) + (@position_of ||= Hash.new do |h, attribute| + h[attribute] = attributes.index(self[attribute]) + end)[attribute] + end + private def matching_attributes(attribute) (@matching_attributes ||= attributes.inject({}) do |hash, a| diff --git a/lib/arel/algebra/relations/utilities/externalization.rb b/lib/arel/algebra/relations/utilities/externalization.rb index bd067f2304..13758ccec9 100644 --- a/lib/arel/algebra/relations/utilities/externalization.rb +++ b/lib/arel/algebra/relations/utilities/externalization.rb @@ -8,7 +8,7 @@ module Arel end def attributes - @attributes ||= relation.attributes.collect(&:to_attribute).collect { |a| a.bind(self) } + @attributes ||= relation.attributes.collect { |a| a.to_attribute(self) } end end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 820b0af4b2..1b009537b9 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,4 +1,3 @@ -require 'arel/engines/memory/relations/relation' require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index ea0b5af5ba..15a3e95e1b 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -1,8 +1,8 @@ module Arel class Array < Relation attributes :array, :attribute_names - deriving :initialize include Recursion::BaseCase + deriving :==, :initialize def engine @engine ||= Memory::Engine.new @@ -10,7 +10,7 @@ module Arel def attributes @attributes ||= @attribute_names.collect do |name| - Attribute.new(self, name.to_sym) + name.to_attribute(self) end end diff --git a/lib/arel/engines/memory/relations/relation.rb b/lib/arel/engines/memory/relations/relation.rb deleted file mode 100644 index abfb8bb37f..0000000000 --- a/lib/arel/engines/memory/relations/relation.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Arel - class Relation - def position_of(attribute) - attributes.index(self[attribute]) - end - end -end \ No newline at end of file diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index e5d1a8b0ca..0700ae9733 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -19,12 +19,12 @@ module Arel end def read(relation) - results = connection.execute(relation.to_sql) - rows = [] - results.each do |row| - rows << attributes.zip(row).to_hash + # FIXME + class << rows = connection.execute(relation.to_sql) + include Enumerable end - rows + + Array.new(rows, relation.attributes) end def update(relation) diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index 2f5e23644e..f848fd3268 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -22,7 +22,7 @@ module Arel end class OuterJoin < Join - def join_sql; "OUTER JOIN" end + def join_sql; "LEFT OUTER JOIN" end end class StringJoin < Join diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index bab9fad3d5..dcac5abf65 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -26,8 +26,16 @@ module Arel end describe '#to_attribute' do - it "returns self" do - @attribute.to_attribute.should == @attribute + describe 'when the given relation is the same as the attributes relation' do + it "returns self" do + @attribute.to_attribute(@relation).should == @attribute + end + end + + describe 'when the given relation differs from the attributes relation' do + it 'binds to the new relation' do + @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation) + end end end end diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index 10bdb56302..dfd2100048 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -31,7 +31,7 @@ module Arel describe '#to_attribute' do it "manufactures an attribute with the expression as an ancestor" do - @expression.to_attribute.should == Attribute.new(@expression.relation, @expression.alias, :ancestor => @expression) + @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression) end end end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 3286f373f5..9707f2887c 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -40,7 +40,7 @@ module Arel describe "when given a string" do it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == Join.new(arbitrary_string, @relation) + @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) end end @@ -159,7 +159,7 @@ module Arel describe '#insert' do it 'manufactures an insertion relation' do Session.start do - record = {@relation[:name] => 'carl'} + record = { @relation[:name] => 'carl' } mock(Session.new).create(Insert.new(@relation, record)) @relation.insert(record) end @@ -169,7 +169,7 @@ module Arel describe '#update' do it 'manufactures an update relation' do Session.start do - assignments = {@relation[:name] => Value.new('bob', @relation)} + assignments = { @relation[:name] => Value.new('bob', @relation) } mock(Session.new).update(Update.new(@relation, assignments)) @relation.update(assignments) end @@ -180,8 +180,8 @@ module Arel describe Relation::Enumerable do it "implements enumerable" do - @relation.collect.should == @relation.session.read(@relation) - @relation.first.should == @relation.session.read(@relation).first + @relation.collect.should == @relation.session.read(@relation).collect + @relation.first.should == @relation.session.read(@relation).first end end end -- cgit v1.2.3 From 07833d39c2885a5cddf38eeb860d79353c0f447b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 15:47:10 -0400 Subject: basic implementation of in memory insertions Conflicts: lib/arel/engines/memory/relations.rb --- doc/TODO | 8 ++++--- lib/arel/algebra/relations/relation.rb | 2 +- lib/arel/engines/memory/engine.rb | 4 ++++ lib/arel/engines/memory/relations.rb | 1 + lib/arel/engines/memory/relations/writes.rb | 7 ++++++ lib/arel/session.rb | 3 +++ .../engines/memory/unit/relations/insert_spec.rb | 28 ++++++++++++++++++++++ 7 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 lib/arel/engines/memory/relations/writes.rb create mode 100644 spec/arel/engines/memory/unit/relations/insert_spec.rb diff --git a/doc/TODO b/doc/TODO index 7e7028d39f..5e3a7ee3ab 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,11 +1,12 @@ todo: -- fix AR +- insertions for in memory - cross-engine joins - blocks for joins -- deal with table tests in algebra +- test sql insertions - implement mnesia adapter -- rename externalize to derived. +- rename externalize to derived. +- deal with table tests in algebra - fix grouping - audit unit coverage of algebra - data objects @@ -92,6 +93,7 @@ done: - result sets to attr correlation too - implement joins in memory - result sets should be array relations +- fix AR icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/relation.rb b/lib/arel/algebra/relations/relation.rb index c38ab0e9c5..9fdac26528 100644 --- a/lib/arel/algebra/relations/relation.rb +++ b/lib/arel/algebra/relations/relation.rb @@ -57,7 +57,7 @@ module Arel module Writable def insert(record) - session.create Insert.new(self, record); self + session.create Insert.new(self, record) end def update(assignments) diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb index 67a084f2cd..c8f79c9d57 100644 --- a/lib/arel/engines/memory/engine.rb +++ b/lib/arel/engines/memory/engine.rb @@ -5,6 +5,10 @@ module Arel def read(relation) relation.eval end + + def create(relation) + relation.eval + end end include CRUD end diff --git a/lib/arel/engines/memory/relations.rb b/lib/arel/engines/memory/relations.rb index 1b009537b9..c67af2d63b 100644 --- a/lib/arel/engines/memory/relations.rb +++ b/lib/arel/engines/memory/relations.rb @@ -1,4 +1,5 @@ require 'arel/engines/memory/relations/array' require 'arel/engines/memory/relations/operations' +require 'arel/engines/memory/relations/writes' require 'arel/engines/memory/relations/compound' diff --git a/lib/arel/engines/memory/relations/writes.rb b/lib/arel/engines/memory/relations/writes.rb new file mode 100644 index 0000000000..fa8b84a32c --- /dev/null +++ b/lib/arel/engines/memory/relations/writes.rb @@ -0,0 +1,7 @@ +module Arel + class Insert < Compound + def eval + unoperated_rows + [Row.new(self, record.values.collect(&:value))] + end + end +end \ No newline at end of file diff --git a/lib/arel/session.rb b/lib/arel/session.rb index cf04e8a93a..921ad0a7ac 100644 --- a/lib/arel/session.rb +++ b/lib/arel/session.rb @@ -24,6 +24,7 @@ module Arel module CRUD def create(insert) insert.call + insert end def read(select) @@ -34,10 +35,12 @@ module Arel def update(update) update.call + update end def delete(delete) delete.call + delete end end include CRUD diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb new file mode 100644 index 0000000000..4b5e8833a0 --- /dev/null +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -0,0 +1,28 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Insert do + before do + @relation = Array.new([ + [1, 'duck' ], + [2, 'duck' ], + [3, 'goose'] + ], [:id, :name]) + end + + describe '#call' do + it "manufactures an array of hashes of attributes to values" do + @relation \ + .insert(@relation[:id] => 4, @relation[:name] => 'guinea fowl') \ + .let do |relation| + relation.call.should == [ + Row.new(relation, [1, 'duck']), + Row.new(relation, [2, 'duck']), + Row.new(relation, [3, 'goose']), + Row.new(relation, [4, 'guinea fowl']) + ] + end + end + end + end +end \ No newline at end of file -- cgit v1.2.3 From 7a51983efc50c8f9092785b1b586f8884dedc01a Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:02:10 -0400 Subject: initial implementation of cross-engine join Conflicts: lib/arel/engines/memory/relations/array.rb lib/arel/engines/sql/primitives.rb --- doc/TODO | 4 +-- lib/arel/algebra/relations/row.rb | 5 ++-- lib/arel/engines/memory/relations/array.rb | 4 +++ lib/arel/engines/memory/relations/compound.rb | 2 +- lib/arel/engines/memory/relations/operations.rb | 4 +-- lib/arel/engines/sql/engine.rb | 4 ++- lib/arel/engines/sql/primitives.rb | 4 +++ lib/arel/engines/sql/relations/table.rb | 4 +++ .../memory/integration/joins/cross_engine_spec.rb | 31 ++++++++++++++++++++++ 9 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 spec/arel/engines/memory/integration/joins/cross_engine_spec.rb diff --git a/doc/TODO b/doc/TODO index 5e3a7ee3ab..901d6ab13f 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,8 +1,7 @@ todo: -- insertions for in memory - cross-engine joins - blocks for joins -- test sql insertions +- fix sql insertions - implement mnesia adapter - rename externalize to derived. @@ -94,6 +93,7 @@ done: - implement joins in memory - result sets should be array relations - fix AR +- insertions for in memory icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index 3731dd9696..e8484944bd 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -4,12 +4,13 @@ module Arel deriving :==, :initialize def [](attribute) - tuple[relation.position_of(attribute)] + attribute.type_cast(tuple[relation.position_of(attribute)]) end def slice(*attributes) Row.new(relation, attributes.inject([]) do |cheese, attribute| - cheese << self[attribute] + # FIXME TESTME method chaining + cheese << tuple[relation.relation.position_of(attribute)] cheese end) end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 15a3e95e1b..6e2dc29252 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -14,6 +14,10 @@ module Arel end end + def format(attribute, value) + value + end + def eval @array.collect { |r| Row.new(self, r) } end diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index 3791fa4622..9e7827dfb3 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -3,7 +3,7 @@ module Arel delegate :array, :to => :relation def unoperated_rows - relation.eval.collect { |row| row.bind(self) } + relation.call.collect { |row| row.bind(self) } end end end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index e35fbe3234..e0fd2824b3 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -47,8 +47,8 @@ module Arel class Join < Relation def eval result = [] - relation1.eval.each do |row1| - relation2.eval.each do |row2| + relation1.call.each do |row1| + relation2.call.each do |row2| combined_row = row1.combine(row2, self) if predicates.all? { |p| p.eval(combined_row) } result << combined_row diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 0700ae9733..d27d93a5dc 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -20,7 +20,9 @@ module Arel def read(relation) # FIXME - class << rows = connection.execute(relation.to_sql) + rows = connection.select_rows(relation.to_sql) + + class << rows include Enumerable end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 9e9143ac0f..22ee19dcf0 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -4,6 +4,10 @@ module Arel original_relation.column_for(self) end + def type_cast(value) + root.relation.format(self, value) + end + def format(object) object.to_sql(Sql::Attribute.new(self)) end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 2653744149..e842f85ed1 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -16,6 +16,10 @@ module Arel end end + def format(attribute, value) + attribute.column.type_cast(value) + end + def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb new file mode 100644 index 0000000000..dd923ee6eb --- /dev/null +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -0,0 +1,31 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Join do + before do + @users = Array.new([ + [1, 'bryan' ], + [2, 'emilio' ], + [3, 'nick'] + ], [:id, :name]) + @photos = Table.new(:photos) + @photos.delete + @photos \ + .insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) \ + .insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) + end + + it 'joins across engines' do + @users \ + .join(@photos) \ + .on(@users[:id].eq(@photos[:user_id])) \ + .project(@users[:name], @photos[:camera_id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, ['bryan', '6']), + Row.new(relation, ['emilio', '42']) + ] + end + end + end +end \ No newline at end of file -- cgit v1.2.3 From 44743bed5568b3065e4f9da7972e3ea1d0d9e728 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:14:28 -0400 Subject: joining across engines in either direction Conflicts: spec/arel/engines/memory/integration/joins/cross_engine_spec.rb --- doc/TODO | 4 ++- lib/arel/algebra/relations/operations/join.rb | 10 +++++- .../memory/integration/joins/cross_engine_spec.rb | 39 ++++++++++++++++------ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/doc/TODO b/doc/TODO index 901d6ab13f..61ff24f4a0 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,9 +1,10 @@ todo: -- cross-engine joins +- fix AR again - blocks for joins - fix sql insertions - implement mnesia adapter +- CLEANUP!!!!! - rename externalize to derived. - deal with table tests in algebra - fix grouping @@ -94,6 +95,7 @@ done: - result sets should be array relations - fix AR - insertions for in memory +- cross-engine joins icebox: - #bind in Attribute and Expression should be doing a descend? diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 695f360b51..02a8fa629d 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -2,7 +2,7 @@ module Arel class Join < Relation attributes :relation1, :relation2, :predicates deriving :== - delegate :engine, :name, :to => :relation1 + delegate :name, :to => :relation1 hash_on :relation1 def initialize(relation1, relation2 = Nil.instance, *predicates) @@ -31,6 +31,10 @@ module Arel def join? true end + + def engine + relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine + end end class InnerJoin < Join; end @@ -39,6 +43,10 @@ module Arel def attributes relation1.externalize.attributes end + + def engine + relation1.engine + end end class Relation diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index dd923ee6eb..4862300052 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -14,17 +14,34 @@ module Arel .insert(@photos[:id] => 1, @photos[:user_id] => 1, @photos[:camera_id] => 6) \ .insert(@photos[:id] => 2, @photos[:user_id] => 2, @photos[:camera_id] => 42) end - - it 'joins across engines' do - @users \ - .join(@photos) \ - .on(@users[:id].eq(@photos[:user_id])) \ - .project(@users[:name], @photos[:camera_id]) \ - .let do |relation| - relation.call.should == [ - Row.new(relation, ['bryan', '6']), - Row.new(relation, ['emilio', '42']) - ] + + describe 'when the in memory relation is on the left' do + it 'joins across engines' do + @users \ + .join(@photos) \ + .on(@users[:id].eq(@photos[:user_id])) \ + .project(@users[:name], @photos[:camera_id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, ['bryan', '6']), + Row.new(relation, ['emilio', '42']) + ] + end + end + end + + describe 'when the in memory relation is on the right' do + it 'joins across engines' do + @photos \ + .join(@users) \ + .on(@users[:id].eq(@photos[:user_id])) \ + .project(@users[:name], @photos[:camera_id]) \ + .let do |relation| + relation.call.should == [ + Row.new(relation, ['bryan', '6']), + Row.new(relation, ['emilio', '42']) + ] + end end end end -- cgit v1.2.3 From 19b2af181009acfcb24d156ca350c148630e6787 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:20:25 -0400 Subject: Improve coverage output --- Rakefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 545993653e..cfae22260a 100644 --- a/Rakefile +++ b/Rakefile @@ -8,8 +8,12 @@ Spec::Rake::SpecTask.new(:coverage) do |t| t.spec_files = ["spec/connections/mysql_connection.rb"] + spec_file_list + t.rcov = true - t.rcov_opts = ['-x', 'spec,gems'] + t.rcov_opts << '--exclude' << "spec,gems" + t.rcov_opts << '--text-summary' + t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse' + t.rcov_opts << '--only-uncovered' end namespace :spec do -- cgit v1.2.3 From dc7b51883b1cc8ad7e525b7315fb575ae77a5b3d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:20:40 -0400 Subject: Whitespace --- lib/arel/algebra.rb | 2 +- lib/arel/algebra/extensions/array.rb | 4 +- lib/arel/algebra/extensions/class.rb | 10 ++-- lib/arel/algebra/extensions/hash.rb | 2 +- lib/arel/algebra/extensions/pathname.rb | 2 +- lib/arel/algebra/extensions/symbol.rb | 2 +- lib/arel/algebra/predicates.rb | 2 +- lib/arel/algebra/primitives/attribute.rb | 8 +-- lib/arel/algebra/primitives/ordering.rb | 8 +-- lib/arel/algebra/relations.rb | 2 +- lib/arel/algebra/relations/operations/alias.rb | 2 +- lib/arel/algebra/relations/operations/group.rb | 2 +- lib/arel/algebra/relations/operations/join.rb | 4 +- lib/arel/algebra/relations/operations/order.rb | 4 +- lib/arel/algebra/relations/operations/skip.rb | 4 +- lib/arel/algebra/relations/operations/take.rb | 4 +- lib/arel/algebra/relations/row.rb | 10 ++-- lib/arel/algebra/relations/utilities/compound.rb | 2 +- lib/arel/algebra/relations/writes.rb | 10 ++-- lib/arel/engines.rb | 2 +- lib/arel/engines/memory.rb | 2 +- lib/arel/engines/memory/engine.rb | 4 +- lib/arel/engines/memory/primitives.rb | 10 ++-- lib/arel/engines/memory/relations/array.rb | 6 +-- lib/arel/engines/memory/relations/compound.rb | 2 +- lib/arel/engines/memory/relations/operations.rb | 16 +++--- lib/arel/engines/memory/relations/writes.rb | 4 +- lib/arel/engines/sql.rb | 2 +- lib/arel/engines/sql/christener.rb | 2 +- lib/arel/engines/sql/engine.rb | 6 +-- lib/arel/engines/sql/extensions.rb | 2 +- lib/arel/engines/sql/extensions/array.rb | 2 +- lib/arel/engines/sql/extensions/nil_class.rb | 2 +- lib/arel/engines/sql/extensions/object.rb | 2 +- lib/arel/engines/sql/extensions/range.rb | 4 +- lib/arel/engines/sql/formatters.rb | 2 +- lib/arel/engines/sql/predicates.rb | 2 +- lib/arel/engines/sql/primitives.rb | 10 ++-- lib/arel/engines/sql/relations.rb | 2 +- lib/arel/engines/sql/relations/operations/alias.rb | 2 +- lib/arel/engines/sql/relations/operations/join.rb | 2 +- lib/arel/engines/sql/relations/relation.rb | 2 +- lib/arel/engines/sql/relations/table.rb | 2 +- .../engines/sql/relations/utilities/compound.rb | 2 +- .../sql/relations/utilities/externalization.rb | 2 +- lib/arel/engines/sql/relations/utilities/nil.rb | 2 +- .../engines/sql/relations/utilities/recursion.rb | 2 +- lib/arel/engines/sql/relations/writes.rb | 2 +- spec/arel/algebra/unit/predicates/binary_spec.rb | 8 +-- spec/arel/algebra/unit/predicates/equality_spec.rb | 10 ++-- spec/arel/algebra/unit/predicates/in_spec.rb | 2 +- .../arel/algebra/unit/primitives/attribute_spec.rb | 58 +++++++++++----------- .../algebra/unit/primitives/expression_spec.rb | 12 ++--- spec/arel/algebra/unit/primitives/value_spec.rb | 2 +- spec/arel/algebra/unit/relations/alias_spec.rb | 4 +- spec/arel/algebra/unit/relations/delete_spec.rb | 2 +- spec/arel/algebra/unit/relations/group_spec.rb | 2 +- spec/arel/algebra/unit/relations/insert_spec.rb | 2 +- spec/arel/algebra/unit/relations/join_spec.rb | 6 +-- spec/arel/algebra/unit/relations/order_spec.rb | 2 +- spec/arel/algebra/unit/relations/project_spec.rb | 10 ++-- spec/arel/algebra/unit/relations/relation_spec.rb | 36 +++++++------- spec/arel/algebra/unit/relations/skip_spec.rb | 2 +- spec/arel/algebra/unit/relations/table_spec.rb | 10 ++-- spec/arel/algebra/unit/relations/take_spec.rb | 2 +- spec/arel/algebra/unit/relations/update_spec.rb | 2 +- spec/arel/algebra/unit/relations/where_spec.rb | 6 +-- spec/arel/algebra/unit/session/session_spec.rb | 22 ++++---- .../memory/integration/joins/cross_engine_spec.rb | 2 +- .../engines/memory/unit/relations/array_spec.rb | 2 +- .../engines/memory/unit/relations/insert_spec.rb | 4 +- .../engines/memory/unit/relations/join_spec.rb | 4 +- .../engines/memory/unit/relations/order_spec.rb | 4 +- .../engines/memory/unit/relations/project_spec.rb | 4 +- .../engines/memory/unit/relations/skip_spec.rb | 4 +- .../engines/memory/unit/relations/take_spec.rb | 4 +- .../engines/memory/unit/relations/where_spec.rb | 6 +-- .../engines/sql/unit/predicates/binary_spec.rb | 2 +- .../engines/sql/unit/predicates/equality_spec.rb | 2 +- spec/arel/engines/sql/unit/predicates/in_spec.rb | 2 +- .../engines/sql/unit/primitives/attribute_spec.rb | 4 +- spec/arel/engines/sql/unit/relations/group_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/join_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/skip_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/table_spec.rb | 2 +- spec/arel/engines/sql/unit/relations/take_spec.rb | 2 +- spec/arel/unit/predicates/predicates_spec.rb | 2 +- spec/connections/mysql_connection.rb | 2 +- spec/doubles/hash.rb | 8 +-- spec/matchers/be_like.rb | 10 ++-- spec/matchers/disambiguate_attributes.rb | 10 ++-- spec/matchers/hash_the_same_as.rb | 10 ++-- spec/schemas/mysql_schema.rb | 2 +- spec/schemas/sqlite3_schema.rb | 2 +- 94 files changed, 243 insertions(+), 243 deletions(-) diff --git a/lib/arel/algebra.rb b/lib/arel/algebra.rb index f27882a343..c206fea0b0 100644 --- a/lib/arel/algebra.rb +++ b/lib/arel/algebra.rb @@ -1,4 +1,4 @@ require 'arel/algebra/extensions' require 'arel/algebra/predicates' require 'arel/algebra/relations' -require 'arel/algebra/primitives' \ No newline at end of file +require 'arel/algebra/primitives' diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb index 935569a07b..48541a395e 100644 --- a/lib/arel/algebra/extensions/array.rb +++ b/lib/arel/algebra/extensions/array.rb @@ -2,11 +2,11 @@ class Array def to_hash Hash[*flatten] end - + def group_by inject({}) do |groups, element| (groups[yield(element)] ||= []) << element groups end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index f37898e7d7..0a729d8255 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -3,11 +3,11 @@ class Class @attributes = attrs attr_reader *attrs end - + def deriving(*methods) methods.each { |m| derive m } end - + def derive(method_name) methods = { :initialize => " @@ -24,14 +24,14 @@ class Class } class_eval methods[method_name], __FILE__, __LINE__ end - + def hash_on(delegatee) define_method :eql? do |other| self == other end - + define_method :hash do @hash ||= delegatee.hash end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 7472b5aa73..82cd5e11d3 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -4,4 +4,4 @@ class Hash bound.merge(key.bind(relation) => value.bind(relation)) end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb index 2f7e2733e7..45f1a5f6b3 100644 --- a/lib/arel/algebra/extensions/pathname.rb +++ b/lib/arel/algebra/extensions/pathname.rb @@ -2,4 +2,4 @@ class Pathname def /(path) (self + path).expand_path end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb index 787867bdc3..8d324a801c 100644 --- a/lib/arel/algebra/extensions/symbol.rb +++ b/lib/arel/algebra/extensions/symbol.rb @@ -2,4 +2,4 @@ class Symbol def to_attribute(relation) Arel::Attribute.new(relation, self) end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/predicates.rb b/lib/arel/algebra/predicates.rb index 7f093ded6d..72167c2b27 100644 --- a/lib/arel/algebra/predicates.rb +++ b/lib/arel/algebra/predicates.rb @@ -38,4 +38,4 @@ module Arel class LessThan < Binary; end class Match < Binary; end class In < Binary; end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/primitives/attribute.rb b/lib/arel/algebra/primitives/attribute.rb index aa1f2ae00c..44a2f41733 100644 --- a/lib/arel/algebra/primitives/attribute.rb +++ b/lib/arel/algebra/primitives/attribute.rb @@ -17,7 +17,7 @@ module Arel def aggregation? false end - + def inspect "" end @@ -133,16 +133,16 @@ module Arel end end include Expressions - + module Orderings def asc Ascending.new(self) end - + def desc Descending.new(self) end - + alias_method :to_ordering, :asc end include Orderings diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb index e8d8f97188..a60d794f27 100644 --- a/lib/arel/algebra/primitives/ordering.rb +++ b/lib/arel/algebra/primitives/ordering.rb @@ -3,16 +3,16 @@ module Arel attributes :attribute deriving :initialize, :== delegate :relation, :to => :attribute - + def bind(relation) self.class.new(attribute.bind(relation)) end - + def to_ordering self end end - + class Ascending < Ordering; end class Descending < Ordering; end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations.rb b/lib/arel/algebra/relations.rb index 94df5938fe..f9fa24ba25 100644 --- a/lib/arel/algebra/relations.rb +++ b/lib/arel/algebra/relations.rb @@ -11,4 +11,4 @@ require 'arel/algebra/relations/operations/order' require 'arel/algebra/relations/operations/project' require 'arel/algebra/relations/operations/where' require 'arel/algebra/relations/operations/skip' -require 'arel/algebra/relations/operations/take' \ No newline at end of file +require 'arel/algebra/relations/operations/take' diff --git a/lib/arel/algebra/relations/operations/alias.rb b/lib/arel/algebra/relations/operations/alias.rb index 67837f6a75..0331d98b85 100644 --- a/lib/arel/algebra/relations/operations/alias.rb +++ b/lib/arel/algebra/relations/operations/alias.rb @@ -4,4 +4,4 @@ module Arel deriving :initialize alias_method :==, :equal? end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index 879f2352c5..b8975ed3d6 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -13,4 +13,4 @@ module Arel true end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index 02a8fa629d..e47d9fa9e0 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -31,7 +31,7 @@ module Arel def join? true end - + def engine relation1.engine != relation2.engine ? Memory::Engine.new : relation1.engine end @@ -43,7 +43,7 @@ module Arel def attributes relation1.externalize.attributes end - + def engine relation1.engine end diff --git a/lib/arel/algebra/relations/operations/order.rb b/lib/arel/algebra/relations/operations/order.rb index 4e7133f5a8..a589b56997 100644 --- a/lib/arel/algebra/relations/operations/order.rb +++ b/lib/arel/algebra/relations/operations/order.rb @@ -2,7 +2,7 @@ module Arel class Order < Compound attributes :relation, :orderings deriving :== - + def initialize(relation, *orderings, &block) @relation = relation @orderings = (orderings + arguments_from_block(relation, &block)) \ @@ -15,4 +15,4 @@ module Arel (orderings + relation.orders).collect { |o| o.bind(self) }.collect { |o| o.to_ordering } end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 930e4c94ea..2dda191c35 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -2,9 +2,9 @@ module Arel class Skip < Compound attributes :relation, :skipped deriving :initialize, :== - + def externalizable? true end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/operations/take.rb b/lib/arel/algebra/relations/operations/take.rb index 2fd3fdf635..eb32ec492e 100644 --- a/lib/arel/algebra/relations/operations/take.rb +++ b/lib/arel/algebra/relations/operations/take.rb @@ -2,9 +2,9 @@ module Arel class Take < Compound attributes :relation, :taken deriving :initialize, :== - + def externalizable? true end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/row.rb b/lib/arel/algebra/relations/row.rb index e8484944bd..3158557448 100644 --- a/lib/arel/algebra/relations/row.rb +++ b/lib/arel/algebra/relations/row.rb @@ -2,11 +2,11 @@ module Arel class Row attributes :relation, :tuple deriving :==, :initialize - + def [](attribute) attribute.type_cast(tuple[relation.position_of(attribute)]) end - + def slice(*attributes) Row.new(relation, attributes.inject([]) do |cheese, attribute| # FIXME TESTME method chaining @@ -14,13 +14,13 @@ module Arel cheese end) end - + def bind(relation) Row.new(relation, tuple) end - + def combine(other, relation) Row.new(relation, tuple + other.tuple) end end -end \ No newline at end of file +end diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 99c3d02748..676d80a737 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -13,7 +13,7 @@ module Arel end OPERATION end - + private def arguments_from_block(relation, &block) block_given?? [yield(relation)] : [] diff --git a/lib/arel/algebra/relations/writes.rb b/lib/arel/algebra/relations/writes.rb index 352f7bc7e5..d344987915 100644 --- a/lib/arel/algebra/relations/writes.rb +++ b/lib/arel/algebra/relations/writes.rb @@ -2,7 +2,7 @@ module Arel class Deletion < Compound attributes :relation deriving :initialize, :== - + def call engine.delete(self) end @@ -15,7 +15,7 @@ module Arel def initialize(relation, record) @relation, @record = relation, record.bind(relation) end - + def call engine.create(self) end @@ -24,13 +24,13 @@ module Arel class Update < Compound attributes :relation, :assignments deriving :== - + def initialize(relation, assignments) @relation, @assignments = relation, assignments.bind(relation) end - + def call engine.update(self) end end -end \ No newline at end of file +end diff --git a/lib/arel/engines.rb b/lib/arel/engines.rb index 3f854edf90..cd848d83e2 100644 --- a/lib/arel/engines.rb +++ b/lib/arel/engines.rb @@ -1,2 +1,2 @@ require 'arel/engines/sql' -require 'arel/engines/memory' \ No newline at end of file +require 'arel/engines/memory' diff --git a/lib/arel/engines/memory.rb b/lib/arel/engines/memory.rb index df6f6f3d48..9e7193ef13 100644 --- a/lib/arel/engines/memory.rb +++ b/lib/arel/engines/memory.rb @@ -1,4 +1,4 @@ require 'arel/engines/memory/relations' require 'arel/engines/memory/primitives' require 'arel/engines/memory/engine' -require 'arel/engines/memory/predicates' \ No newline at end of file +require 'arel/engines/memory/predicates' diff --git a/lib/arel/engines/memory/engine.rb b/lib/arel/engines/memory/engine.rb index c8f79c9d57..c7ac9422d4 100644 --- a/lib/arel/engines/memory/engine.rb +++ b/lib/arel/engines/memory/engine.rb @@ -5,7 +5,7 @@ module Arel def read(relation) relation.eval end - + def create(relation) relation.eval end @@ -13,4 +13,4 @@ module Arel include CRUD end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/primitives.rb b/lib/arel/engines/memory/primitives.rb index f8bbcedb55..935b34f5ee 100644 --- a/lib/arel/engines/memory/primitives.rb +++ b/lib/arel/engines/memory/primitives.rb @@ -4,24 +4,24 @@ module Arel row[self] end end - + class Value def eval(row) value end end - + class Ordering def eval(row1, row2) (attribute.eval(row1) <=> attribute.eval(row2)) * direction end end - + class Descending < Ordering def direction; -1 end end - + class Ascending < Ordering def direction; 1 end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/relations/array.rb b/lib/arel/engines/memory/relations/array.rb index 6e2dc29252..5e7c0a4ab1 100644 --- a/lib/arel/engines/memory/relations/array.rb +++ b/lib/arel/engines/memory/relations/array.rb @@ -3,7 +3,7 @@ module Arel attributes :array, :attribute_names include Recursion::BaseCase deriving :==, :initialize - + def engine @engine ||= Memory::Engine.new end @@ -17,9 +17,9 @@ module Arel def format(attribute, value) value end - + def eval @array.collect { |r| Row.new(self, r) } end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/relations/compound.rb b/lib/arel/engines/memory/relations/compound.rb index 9e7827dfb3..6dda92a6a1 100644 --- a/lib/arel/engines/memory/relations/compound.rb +++ b/lib/arel/engines/memory/relations/compound.rb @@ -1,7 +1,7 @@ module Arel class Compound < Relation delegate :array, :to => :relation - + def unoperated_rows relation.call.collect { |row| row.bind(self) } end diff --git a/lib/arel/engines/memory/relations/operations.rb b/lib/arel/engines/memory/relations/operations.rb index e0fd2824b3..8e01938360 100644 --- a/lib/arel/engines/memory/relations/operations.rb +++ b/lib/arel/engines/memory/relations/operations.rb @@ -4,7 +4,7 @@ module Arel unoperated_rows.select { |row| predicate.eval(row) } end end - + class Order < Compound def eval unoperated_rows.sort do |row1, row2| @@ -13,37 +13,37 @@ module Arel end end end - + class Project < Compound def eval unoperated_rows.collect { |r| r.slice(*projections) } end end - + class Take < Compound def eval unoperated_rows[0, taken] end end - + class Skip < Compound def eval unoperated_rows[skipped..-1] end end - + class Group < Compound def eval raise NotImplementedError end end - + class Alias < Compound def eval unoperated_rows end end - + class Join < Relation def eval result = [] @@ -58,4 +58,4 @@ module Arel result end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/memory/relations/writes.rb b/lib/arel/engines/memory/relations/writes.rb index fa8b84a32c..12c4f36c0d 100644 --- a/lib/arel/engines/memory/relations/writes.rb +++ b/lib/arel/engines/memory/relations/writes.rb @@ -1,7 +1,7 @@ module Arel class Insert < Compound def eval - unoperated_rows + [Row.new(self, record.values.collect(&:value))] + unoperated_rows + [Row.new(self, record.values.collect(&:value))] end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql.rb b/lib/arel/engines/sql.rb index aed1fd861e..f31cfc7dac 100644 --- a/lib/arel/engines/sql.rb +++ b/lib/arel/engines/sql.rb @@ -4,4 +4,4 @@ require 'arel/engines/sql/primitives' require 'arel/engines/sql/predicates' require 'arel/engines/sql/formatters' require 'arel/engines/sql/extensions' -require 'arel/engines/sql/christener' \ No newline at end of file +require 'arel/engines/sql/christener' diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index 5883a75f41..c1c9325208 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -10,4 +10,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index d27d93a5dc..5a8c9f16c5 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -21,11 +21,11 @@ module Arel def read(relation) # FIXME rows = connection.select_rows(relation.to_sql) - + class << rows include Enumerable end - + Array.new(rows, relation.attributes) end @@ -40,4 +40,4 @@ module Arel include CRUD end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions.rb b/lib/arel/engines/sql/extensions.rb index 6f4ad32148..1ea31bc140 100644 --- a/lib/arel/engines/sql/extensions.rb +++ b/lib/arel/engines/sql/extensions.rb @@ -1,4 +1,4 @@ require 'arel/engines/sql/extensions/object' require 'arel/engines/sql/extensions/array' require 'arel/engines/sql/extensions/range' -require 'arel/engines/sql/extensions/nil_class' \ No newline at end of file +require 'arel/engines/sql/extensions/nil_class' diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb index 1daa5abca7..d97dd1aa25 100644 --- a/lib/arel/engines/sql/extensions/array.rb +++ b/lib/arel/engines/sql/extensions/array.rb @@ -6,4 +6,4 @@ class Array def inclusion_predicate_sql "IN" end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb index 729c4cada7..6f38ecdf3a 100644 --- a/lib/arel/engines/sql/extensions/nil_class.rb +++ b/lib/arel/engines/sql/extensions/nil_class.rb @@ -2,4 +2,4 @@ class NilClass def equality_predicate_sql 'IS' end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb index ef990eee2f..65270ee3de 100644 --- a/lib/arel/engines/sql/extensions/object.rb +++ b/lib/arel/engines/sql/extensions/object.rb @@ -6,4 +6,4 @@ class Object def equality_predicate_sql '=' end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb index d7329efe34..946dbc2633 100644 --- a/lib/arel/engines/sql/extensions/range.rb +++ b/lib/arel/engines/sql/extensions/range.rb @@ -2,8 +2,8 @@ class Range def to_sql(formatter = nil) formatter.range self.begin, self.end end - + def inclusion_predicate_sql "BETWEEN" end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index bc5f0f7c64..08a32843c9 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -47,7 +47,7 @@ module Arel class WhereClause < PassThrough end - class OrderClause < PassThrough + class OrderClause < PassThrough def ordering(ordering) "#{quote_table_name(name_for(ordering.attribute.original_relation))}.#{quote_column_name(ordering.attribute.name)} #{ordering.direction_sql}" end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index dfeddb2de1..7e195c2605 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -34,4 +34,4 @@ module Arel class In < Binary def predicate_sql; operand2.inclusion_predicate_sql end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index 22ee19dcf0..f2e8e8dabe 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -7,7 +7,7 @@ module Arel def type_cast(value) root.relation.format(self, value) end - + def format(object) object.to_sql(Sql::Attribute.new(self)) end @@ -28,17 +28,17 @@ module Arel object.to_sql(Sql::Value.new(relation)) end end - + class Ordering def to_sql(formatter = Sql::OrderClause.new(relation)) formatter.ordering self end end - + class Ascending < Ordering def direction_sql; 'ASC' end end - + class Descending < Ordering def direction_sql; 'DESC' end end @@ -72,4 +72,4 @@ module Arel class Average < Expression def function_sql; 'AVG' end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations.rb b/lib/arel/engines/sql/relations.rb index 0eb1303ec9..8360a1f806 100644 --- a/lib/arel/engines/sql/relations.rb +++ b/lib/arel/engines/sql/relations.rb @@ -6,4 +6,4 @@ require 'arel/engines/sql/relations/relation' require 'arel/engines/sql/relations/table' require 'arel/engines/sql/relations/operations/join' require 'arel/engines/sql/relations/operations/alias' -require 'arel/engines/sql/relations/writes' \ No newline at end of file +require 'arel/engines/sql/relations/writes' diff --git a/lib/arel/engines/sql/relations/operations/alias.rb b/lib/arel/engines/sql/relations/operations/alias.rb index 32c9911a69..9b6a484463 100644 --- a/lib/arel/engines/sql/relations/operations/alias.rb +++ b/lib/arel/engines/sql/relations/operations/alias.rb @@ -2,4 +2,4 @@ module Arel class Alias < Compound include Recursion::BaseCase end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/operations/join.rb b/lib/arel/engines/sql/relations/operations/join.rb index f848fd3268..7c5e13510a 100644 --- a/lib/arel/engines/sql/relations/operations/join.rb +++ b/lib/arel/engines/sql/relations/operations/join.rb @@ -30,4 +30,4 @@ module Arel relation2 end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 5fd4121176..93c146352c 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -25,4 +25,4 @@ module Arel @christener ||= Sql::Christener.new end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index e842f85ed1..0b6574eedc 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -19,7 +19,7 @@ module Arel def format(attribute, value) attribute.column.type_cast(value) end - + def column_for(attribute) has_attribute?(attribute) and columns.detect { |c| c.name == attribute.name.to_s } end diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index 61df196d6e..b63a829c67 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -3,4 +3,4 @@ module Arel delegate :table, :table_sql, :to => :relation end end - \ No newline at end of file + diff --git a/lib/arel/engines/sql/relations/utilities/externalization.rb b/lib/arel/engines/sql/relations/utilities/externalization.rb index 1ac6f2de8e..7f937e8423 100644 --- a/lib/arel/engines/sql/relations/utilities/externalization.rb +++ b/lib/arel/engines/sql/relations/utilities/externalization.rb @@ -11,4 +11,4 @@ module Arel relation.name + '_external' end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/utilities/nil.rb b/lib/arel/engines/sql/relations/utilities/nil.rb index 77534b25ad..519ea8acf1 100644 --- a/lib/arel/engines/sql/relations/utilities/nil.rb +++ b/lib/arel/engines/sql/relations/utilities/nil.rb @@ -3,4 +3,4 @@ module Arel def table_sql(formatter = nil); '' end def name; '' end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/utilities/recursion.rb b/lib/arel/engines/sql/relations/utilities/recursion.rb index 848b059507..84a526f57c 100644 --- a/lib/arel/engines/sql/relations/utilities/recursion.rb +++ b/lib/arel/engines/sql/relations/utilities/recursion.rb @@ -10,4 +10,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index edfd9f7233..4d753f5fca 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -33,4 +33,4 @@ module Arel ].join("\n") end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/predicates/binary_spec.rb b/spec/arel/algebra/unit/predicates/binary_spec.rb index 9022a543d1..14fd7ab21b 100644 --- a/spec/arel/algebra/unit/predicates/binary_spec.rb +++ b/spec/arel/algebra/unit/predicates/binary_spec.rb @@ -9,19 +9,19 @@ module Arel class ConcreteBinary < Binary end end - + describe '#bind' do before do @another_relation = @relation.alias end - + describe 'when both operands are attributes' do it "manufactures an expression with the attributes bound to the relation" do ConcreteBinary.new(@attribute1, @attribute2).bind(@another_relation). \ should == ConcreteBinary.new(@another_relation[@attribute1], @another_relation[@attribute2]) end end - + describe 'when an operand is a value' do it "manufactures an expression with unmodified values" do ConcreteBinary.new(@attribute1, "asdf").bind(@another_relation). \ @@ -30,4 +30,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/predicates/equality_spec.rb b/spec/arel/algebra/unit/predicates/equality_spec.rb index 9a56ed5eaf..af91f8b51b 100644 --- a/spec/arel/algebra/unit/predicates/equality_spec.rb +++ b/spec/arel/algebra/unit/predicates/equality_spec.rb @@ -8,20 +8,20 @@ module Arel @attribute1 = @relation1[:id] @attribute2 = @relation2[:user_id] end - - describe '==' do + + describe '==' do it "obtains if attribute1 and attribute2 are identical" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute1, @attribute2) Equality.new(@attribute1, @attribute2).should_not == Equality.new(@attribute1, @attribute1) end - + it "obtains if the concrete type of the predicates are identical" do Equality.new(@attribute1, @attribute2).should_not == Binary.new(@attribute1, @attribute2) end - + it "is commutative on the attributes" do Equality.new(@attribute1, @attribute2).should == Equality.new(@attribute2, @attribute1) end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/predicates/in_spec.rb b/spec/arel/algebra/unit/predicates/in_spec.rb index 91c154763c..a8a15ce4e3 100644 --- a/spec/arel/algebra/unit/predicates/in_spec.rb +++ b/spec/arel/algebra/unit/predicates/in_spec.rb @@ -7,4 +7,4 @@ module Arel @attribute = @relation[:id] end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index dcac5abf65..89e338e377 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -6,32 +6,32 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do @attribute.as(:alias).should == Attribute.new(@relation, @attribute.name, :alias => :alias, :ancestor => @attribute) end end - + describe '#bind' do it "manufactures an attribute with the relation bound and self as an ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @attribute.bind(derived_relation).should == Attribute.new(derived_relation, @attribute.name, :ancestor => @attribute) end - + it "returns self if the substituting to the same relation" do @attribute.bind(@relation).should == @attribute end end - + describe '#to_attribute' do describe 'when the given relation is the same as the attributes relation' do it "returns self" do @attribute.to_attribute(@relation).should == @attribute end end - + describe 'when the given relation differs from the attributes relation' do it 'binds to the new relation' do @attribute.to_attribute(new_relation = @relation.alias).should == @attribute.bind(new_relation) @@ -39,32 +39,32 @@ module Arel end end end - + describe '#column' do it "returns the corresponding column in the relation" do @attribute.column.should == @relation.column_for(@attribute) end end - + describe '#engine' do it "delegates to its relation" do Attribute.new(@relation, :id).engine.should == @relation.engine end end - + describe Attribute::Congruence do describe '/' do before do @aliased_relation = @relation.alias @doubly_aliased_relation = @aliased_relation.alias end - + describe 'when dividing two unrelated attributes' do it "returns 0.0" do (@relation[:id] / @relation[:name]).should == 0.0 end end - + describe 'when dividing two matching attributes' do it 'returns a the highest score for the most similar attributes' do (@aliased_relation[:id] / @relation[:id]) \ @@ -75,98 +75,98 @@ module Arel end end end - + describe Attribute::Predications do before do @attribute = Attribute.new(@relation, :name) end - + describe '#eq' do it "manufactures an equality predicate" do @attribute.eq('name').should == Equality.new(@attribute, 'name') end end - + describe '#lt' do it "manufactures a less-than predicate" do @attribute.lt(10).should == LessThan.new(@attribute, 10) end end - + describe '#lteq' do it "manufactures a less-than or equal-to predicate" do @attribute.lteq(10).should == LessThanOrEqualTo.new(@attribute, 10) end end - + describe '#gt' do it "manufactures a greater-than predicate" do @attribute.gt(10).should == GreaterThan.new(@attribute, 10) end end - + describe '#gteq' do it "manufactures a greater-than or equal-to predicate" do @attribute.gteq(10).should == GreaterThanOrEqualTo.new(@attribute, 10) end end - + describe '#matches' do it "manufactures a match predicate" do @attribute.matches(/.*/).should == Match.new(@attribute, /.*/) end end - + describe '#in' do it "manufactures an in predicate" do @attribute.in(1..30).should == In.new(@attribute, (1..30)) end end end - + describe Attribute::Expressions do before do - @attribute = Attribute.new(@relation, :name) + @attribute = Attribute.new(@relation, :name) end - + describe '#count' do it "manufactures a count Expression" do @attribute.count.should == Count.new(@attribute) end end - + describe '#sum' do it "manufactures a sum Expression" do @attribute.sum.should == Sum.new(@attribute) end end - + describe '#maximum' do it "manufactures a maximum Expression" do @attribute.maximum.should == Maximum.new(@attribute) end end - + describe '#minimum' do it "manufactures a minimum Expression" do @attribute.minimum.should == Minimum.new(@attribute) end end - + describe '#average' do it "manufactures an average Expression" do @attribute.average.should == Average.new(@attribute) end - end + end end - + describe Attribute::Orderings do describe '#asc' do it 'manufactures an ascending ordering' do pending end end - + describe '#desc' do it 'manufactures a descending ordering' do pending @@ -174,4 +174,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index dfd2100048..82d12d53f9 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -6,29 +6,29 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe Expression::Transformations do before do @expression = Count.new(@attribute) end - + describe '#bind' do it "manufactures an attribute with a rebound relation and self as the ancestor" do derived_relation = @relation.where(@relation[:id].eq(1)) @expression.bind(derived_relation).should == Count.new(@attribute.bind(derived_relation), nil, @expression) end - + it "returns self if the substituting to the same relation" do @expression.bind(@relation).should == @expression end end - + describe '#as' do it "manufactures an aliased expression" do @expression.as(:alias).should == Expression.new(@attribute, :alias, @expression) end end - + describe '#to_attribute' do it "manufactures an attribute with the expression as an ancestor" do @expression.to_attribute(@relation).should == Attribute.new(@relation, @expression.alias, :ancestor => @expression) @@ -36,4 +36,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/primitives/value_spec.rb b/spec/arel/algebra/unit/primitives/value_spec.rb index 8774ca78c5..45208e6c5d 100644 --- a/spec/arel/algebra/unit/primitives/value_spec.rb +++ b/spec/arel/algebra/unit/primitives/value_spec.rb @@ -12,4 +12,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/alias_spec.rb b/spec/arel/algebra/unit/relations/alias_spec.rb index c87a0ca2dd..a5d716a638 100644 --- a/spec/arel/algebra/unit/relations/alias_spec.rb +++ b/spec/arel/algebra/unit/relations/alias_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '==' do it "obtains if the objects are the same" do Alias.new(@relation).should_not == Alias.new(@relation) @@ -13,4 +13,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/delete_spec.rb b/spec/arel/algebra/unit/relations/delete_spec.rb index 075e59e724..7578e12a3e 100644 --- a/spec/arel/algebra/unit/relations/delete_spec.rb +++ b/spec/arel/algebra/unit/relations/delete_spec.rb @@ -6,4 +6,4 @@ module Arel @relation = Table.new(:users) end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/group_spec.rb b/spec/arel/algebra/unit/relations/group_spec.rb index 050de2993d..58f9252356 100644 --- a/spec/arel/algebra/unit/relations/group_spec.rb +++ b/spec/arel/algebra/unit/relations/group_spec.rb @@ -7,4 +7,4 @@ module Arel @attribute = @relation[:id] end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/insert_spec.rb b/spec/arel/algebra/unit/relations/insert_spec.rb index 184cd2a926..feb1a5eae4 100644 --- a/spec/arel/algebra/unit/relations/insert_spec.rb +++ b/spec/arel/algebra/unit/relations/insert_spec.rb @@ -6,4 +6,4 @@ module Arel @relation = Table.new(:users) end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/join_spec.rb b/spec/arel/algebra/unit/relations/join_spec.rb index 5b512cc7f6..f5a8bd32aa 100644 --- a/spec/arel/algebra/unit/relations/join_spec.rb +++ b/spec/arel/algebra/unit/relations/join_spec.rb @@ -7,14 +7,14 @@ module Arel @relation2 = Table.new(:photos) @predicate = @relation1[:id].eq(@relation2[:user_id]) end - + describe 'hashing' do it 'implements hash equality' do InnerJoin.new(@relation1, @relation2, @predicate) \ .should hash_the_same_as(InnerJoin.new(@relation1, @relation2, @predicate)) end end - + describe '#attributes' do it 'combines the attributes of the two relations' do join = InnerJoin.new(@relation1, @relation2, @predicate) @@ -23,4 +23,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb index 0e1b1a0e54..4f163894c8 100644 --- a/spec/arel/algebra/unit/relations/order_spec.rb +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -8,4 +8,4 @@ module Arel end end end - \ No newline at end of file + diff --git a/spec/arel/algebra/unit/relations/project_spec.rb b/spec/arel/algebra/unit/relations/project_spec.rb index b71acf5e91..9f4358ea54 100644 --- a/spec/arel/algebra/unit/relations/project_spec.rb +++ b/spec/arel/algebra/unit/relations/project_spec.rb @@ -6,24 +6,24 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end - + describe '#attributes' do before do @projection = Project.new(@relation, @attribute) end - + it "manufactures attributes associated with the projection relation" do @projection.attributes.should == [@attribute].collect { |a| a.bind(@projection) } end end - + describe '#externalizable?' do describe 'when the projections are attributes' do it 'returns false' do Project.new(@relation, @attribute).should_not be_externalizable end end - + describe 'when the projections include an aggregation' do it "obtains" do Project.new(@relation, @attribute.sum).should be_externalizable @@ -31,4 +31,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/relation_spec.rb b/spec/arel/algebra/unit/relations/relation_spec.rb index 9707f2887c..adf82847ac 100644 --- a/spec/arel/algebra/unit/relations/relation_spec.rb +++ b/spec/arel/algebra/unit/relations/relation_spec.rb @@ -7,14 +7,14 @@ module Arel @attribute1 = @relation[:id] @attribute2 = @relation[:name] end - + describe '[]' do describe 'when given an', Attribute do it "return the attribute congruent to the provided attribute" do @relation[@attribute1].should == @attribute1 end end - + describe 'when given a', Symbol, String do it "returns the attribute with the same name, if it exists" do @relation[:id].should == @attribute1 @@ -23,13 +23,13 @@ module Arel end end end - + describe Relation::Operable do describe 'joins' do before do @predicate = @relation[:id].eq(@relation[:id]) end - + describe '#join' do describe 'when given a relation' do it "manufactures an inner join operation between those two relations" do @@ -37,13 +37,13 @@ module Arel should == InnerJoin.new(@relation, @relation, @predicate) end end - + describe "when given a string" do it "manufactures a join operation with the string passed through" do - @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) + @relation.join(arbitrary_string = "ASDF").should == StringJoin.new(@relation, arbitrary_string) end end - + describe "when given something blank" do it "returns self" do @relation.join.should == @relation @@ -64,7 +64,7 @@ module Arel @relation.project(@attribute1, @attribute2). \ should == Project.new(@relation, @attribute1, @attribute2) end - + describe "when given blank attributes" do it "returns self" do @relation.project.should == @relation @@ -97,36 +97,36 @@ module Arel end end end - + describe '#order' do it "manufactures an order relation" do @relation.order(@attribute1, @attribute2).should == Order.new(@relation, @attribute1, @attribute2) end - + describe 'when given a blank ordering' do it 'returns self' do @relation.order.should == @relation end end end - + describe '#take' do it "manufactures a take relation" do @relation.take(5).should == Take.new(@relation, 5) end - + describe 'when given a blank number of items' do it 'returns self' do @relation.take.should == @relation end end end - + describe '#skip' do it "manufactures a skip relation" do @relation.skip(4).should == Skip.new(@relation, 4) end - + describe 'when given a blank number of items' do it 'returns self' do @relation.skip.should == @relation @@ -138,14 +138,14 @@ module Arel it 'manufactures a group relation' do @relation.group(@attribute1, @attribute2).should == Group.new(@relation, @attribute1, @attribute2) end - + describe 'when given blank groupings' do it 'returns self' do @relation.group.should == @relation end end end - + describe Relation::Operable::Writable do describe '#delete' do it 'manufactures a deletion relation' do @@ -177,7 +177,7 @@ module Arel end end end - + describe Relation::Enumerable do it "implements enumerable" do @relation.collect.should == @relation.session.read(@relation).collect @@ -185,4 +185,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/skip_spec.rb b/spec/arel/algebra/unit/relations/skip_spec.rb index ff57e03d1c..a41913436e 100644 --- a/spec/arel/algebra/unit/relations/skip_spec.rb +++ b/spec/arel/algebra/unit/relations/skip_spec.rb @@ -7,4 +7,4 @@ module Arel @skipped = 4 end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/table_spec.rb b/spec/arel/algebra/unit/relations/table_spec.rb index 4821d92299..dfe457043c 100644 --- a/spec/arel/algebra/unit/relations/table_spec.rb +++ b/spec/arel/algebra/unit/relations/table_spec.rb @@ -5,7 +5,7 @@ module Arel before do @relation = Table.new(:users) end - + describe '[]' do describe 'when given a', Symbol do it "manufactures an attribute if the symbol names an attribute within the relation" do @@ -18,22 +18,22 @@ module Arel it "returns the attribute if the attribute is within the relation" do @relation[@relation[:id]].should == @relation[:id] end - + it "returns nil if the attribtue is not within the relation" do another_relation = Table.new(:photos) @relation[another_relation[:id]].should be_nil end end - + describe 'when given an', Expression do before do @expression = @relation[:id].count end - + it "returns the Expression if the Expression is within the relation" do @relation[@expression].should be_nil end end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/take_spec.rb b/spec/arel/algebra/unit/relations/take_spec.rb index 6f8b4fd36e..2bc17db5a1 100644 --- a/spec/arel/algebra/unit/relations/take_spec.rb +++ b/spec/arel/algebra/unit/relations/take_spec.rb @@ -7,4 +7,4 @@ module Arel @taken = 4 end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/update_spec.rb b/spec/arel/algebra/unit/relations/update_spec.rb index c27afb48b2..e9642ffc99 100644 --- a/spec/arel/algebra/unit/relations/update_spec.rb +++ b/spec/arel/algebra/unit/relations/update_spec.rb @@ -6,4 +6,4 @@ module Arel @relation = Table.new(:users) end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/relations/where_spec.rb b/spec/arel/algebra/unit/relations/where_spec.rb index 3f37b53138..6c3074a3a5 100644 --- a/spec/arel/algebra/unit/relations/where_spec.rb +++ b/spec/arel/algebra/unit/relations/where_spec.rb @@ -6,13 +6,13 @@ module Arel @relation = Table.new(:users) @predicate = @relation[:id].eq(1) end - + describe '#initialize' do it "manufactures nested where relations if multiple predicates are provided" do - another_predicate = @relation[:name].lt(2) + another_predicate = @relation[:name].lt(2) Where.new(@relation, @predicate, another_predicate). \ should == Where.new(Where.new(@relation, another_predicate), @predicate) end end end -end \ No newline at end of file +end diff --git a/spec/arel/algebra/unit/session/session_spec.rb b/spec/arel/algebra/unit/session/session_spec.rb index e17b5d638a..ca0a43f278 100644 --- a/spec/arel/algebra/unit/session/session_spec.rb +++ b/spec/arel/algebra/unit/session/session_spec.rb @@ -6,7 +6,7 @@ module Arel @relation = Table.new(:users) @session = Session.new end - + describe '::start' do describe '::instance' do it "it is a singleton within the started session" do @@ -23,13 +23,13 @@ module Arel end end end - + it "manufactures new sessions outside of the started session" do Session.new.should_not == Session.new end end end - + describe Session::CRUD do before do @insert = Insert.new(@relation, @relation[:name] => 'nick') @@ -37,34 +37,34 @@ module Arel @delete = Deletion.new(@relation) @read = @relation end - + describe '#create' do it "executes an insertion on the connection" do mock(@insert).call @session.create(@insert) end end - + describe '#read' do it "executes an selection on the connection" do mock(@read).call @session.read(@read) end - + it "is memoized" do mock(@read).call.once @session.read(@read) @session.read(@read) end end - + describe '#update' do it "executes an update on the connection" do mock(@update).call @session.update(@update) end end - + describe '#delete' do it "executes a delete on the connection" do mock(@delete).call @@ -72,13 +72,13 @@ module Arel end end end - + describe 'Transactions' do describe '#begin' do end - + describe '#end' do end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb index 4862300052..bffecc9182 100644 --- a/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +++ b/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb @@ -45,4 +45,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/array_spec.rb b/spec/arel/engines/memory/unit/relations/array_spec.rb index 4fe24c77fa..dd9da41569 100644 --- a/spec/arel/engines/memory/unit/relations/array_spec.rb +++ b/spec/arel/engines/memory/unit/relations/array_spec.rb @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/insert_spec.rb b/spec/arel/engines/memory/unit/relations/insert_spec.rb index 4b5e8833a0..59e43328a3 100644 --- a/spec/arel/engines/memory/unit/relations/insert_spec.rb +++ b/spec/arel/engines/memory/unit/relations/insert_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it "manufactures an array of hashes of attributes to values" do @relation \ @@ -25,4 +25,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb index 920cc55d0a..df08fd4a96 100644 --- a/spec/arel/engines/memory/unit/relations/join_spec.rb +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -11,7 +11,7 @@ module Arel @relation2 = @relation1.alias @relation3 = @relation1.alias end - + describe InnerJoin do describe '#call' do it 'combines the two tables where the predicate obtains' do @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/order_spec.rb b/spec/arel/engines/memory/unit/relations/order_spec.rb index 3ecb31068b..1e9690bbbf 100644 --- a/spec/arel/engines/memory/unit/relations/order_spec.rb +++ b/spec/arel/engines/memory/unit/relations/order_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'sorts the relation with the provided ordering' do @relation \ @@ -24,4 +24,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/project_spec.rb b/spec/arel/engines/memory/unit/relations/project_spec.rb index 1d1224cfdc..1690910026 100644 --- a/spec/arel/engines/memory/unit/relations/project_spec.rb +++ b/spec/arel/engines/memory/unit/relations/project_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'retains only the attributes that are provided' do @relation \ @@ -24,4 +24,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/skip_spec.rb b/spec/arel/engines/memory/unit/relations/skip_spec.rb index 86db45ef61..3411c5493b 100644 --- a/spec/arel/engines/memory/unit/relations/skip_spec.rb +++ b/spec/arel/engines/memory/unit/relations/skip_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'removes the first n rows' do @relation \ @@ -23,4 +23,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/take_spec.rb b/spec/arel/engines/memory/unit/relations/take_spec.rb index 8b774987e0..5e7c4fb462 100644 --- a/spec/arel/engines/memory/unit/relations/take_spec.rb +++ b/spec/arel/engines/memory/unit/relations/take_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'removes the rows after the first n' do @relation \ @@ -23,4 +23,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/memory/unit/relations/where_spec.rb b/spec/arel/engines/memory/unit/relations/where_spec.rb index d75ee5dcbe..1d2c2eb39c 100644 --- a/spec/arel/engines/memory/unit/relations/where_spec.rb +++ b/spec/arel/engines/memory/unit/relations/where_spec.rb @@ -9,7 +9,7 @@ module Arel [3, 'goose'] ], [:id, :name]) end - + describe '#call' do it 'filters the relation with the provided predicate' do @relation \ @@ -21,7 +21,7 @@ module Arel ] end end - + describe 'when filtering a where relation' do it 'further filters the already-filtered relation with the provided predicate' do @relation \ @@ -36,4 +36,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index 679147067e..befd2878d9 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -102,4 +102,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/predicates/equality_spec.rb b/spec/arel/engines/sql/unit/predicates/equality_spec.rb index e8c8c42675..688a6a20be 100644 --- a/spec/arel/engines/sql/unit/predicates/equality_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/equality_spec.rb @@ -43,4 +43,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/predicates/in_spec.rb b/spec/arel/engines/sql/unit/predicates/in_spec.rb index d977937e4e..d3e75cfb84 100644 --- a/spec/arel/engines/sql/unit/predicates/in_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/in_spec.rb @@ -83,4 +83,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb index e71ab949f1..6cb72f3c19 100644 --- a/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/attribute_spec.rb @@ -12,7 +12,7 @@ module Arel @attribute.column.should == @relation.column_for(@attribute) end end - + describe '#to_sql' do describe 'for a simple attribute' do it "manufactures sql with an alias" do @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/group_spec.rb b/spec/arel/engines/sql/unit/relations/group_spec.rb index b7279a23d9..5e0c675c8b 100644 --- a/spec/arel/engines/sql/unit/relations/group_spec.rb +++ b/spec/arel/engines/sql/unit/relations/group_spec.rb @@ -53,4 +53,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index 1f43101133..f904b61870 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -54,4 +54,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/skip_spec.rb b/spec/arel/engines/sql/unit/relations/skip_spec.rb index f8e5ceaad3..c14bd1ce95 100644 --- a/spec/arel/engines/sql/unit/relations/skip_spec.rb +++ b/spec/arel/engines/sql/unit/relations/skip_spec.rb @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 3f5a5ac248..9797b38822 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -66,4 +66,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/engines/sql/unit/relations/take_spec.rb b/spec/arel/engines/sql/unit/relations/take_spec.rb index 1263ed4795..8f1240fc17 100644 --- a/spec/arel/engines/sql/unit/relations/take_spec.rb +++ b/spec/arel/engines/sql/unit/relations/take_spec.rb @@ -29,4 +29,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb index 8f9cec5376..ac842998af 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -50,4 +50,4 @@ module Arel end end end -end \ No newline at end of file +end diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index 789628b95d..b4e27f2380 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -10,4 +10,4 @@ ActiveRecord::Base.configurations = { } } -ActiveRecord::Base.establish_connection 'unit' \ No newline at end of file +ActiveRecord::Base.establish_connection 'unit' diff --git a/spec/doubles/hash.rb b/spec/doubles/hash.rb index 97d25742cb..32c5b98058 100644 --- a/spec/doubles/hash.rb +++ b/spec/doubles/hash.rb @@ -2,19 +2,19 @@ class Hash def ordered_array to_a.sort { |(key1, value1), (key2, value2)| key1.hash <=> key2.hash } end - + def keys ordered_array.collect(&:first) end - + def values ordered_array.collect { |_, v| v } end - + def each(&block) ordered_array.each(&block) end - + def shift returning to_a.first do |k, v| delete(k) diff --git a/spec/matchers/be_like.rb b/spec/matchers/be_like.rb index 4ff5bc532f..c9d4d4b979 100644 --- a/spec/matchers/be_like.rb +++ b/spec/matchers/be_like.rb @@ -3,22 +3,22 @@ module BeLikeMatcher def initialize(expected) @expected = expected end - + def matches?(actual) @actual = actual @expected.gsub(/\s+/, ' ').strip == @actual.gsub(/\s+/, ' ').strip end - + def failure_message "expected\n#{@actual}\nto be like\n#{@expected}" end - + def negative_failure_message "expected\n#{@actual}\nto be unlike\n#{@expected}" end end - + def be_like(expected) BeLike.new(expected) end -end \ No newline at end of file +end diff --git a/spec/matchers/disambiguate_attributes.rb b/spec/matchers/disambiguate_attributes.rb index bee7d22b0c..bc4a5215d4 100644 --- a/spec/matchers/disambiguate_attributes.rb +++ b/spec/matchers/disambiguate_attributes.rb @@ -3,7 +3,7 @@ module DisambiguateAttributesMatcher def initialize(attributes) @attributes = attributes end - + def matches?(actual) @actual = actual attribute1, attribute2 = @attributes @@ -11,18 +11,18 @@ module DisambiguateAttributesMatcher !@actual[attribute1].descends_from?(attribute2) && @actual[attribute2].descends_from?(attribute2) end - + def failure_message "" # "expected #{@actual} to disambiguate its attributes" end - + def negative_failure_message "expected #{@actual} to not disambiguate its attributes" end end - + def disambiguate_attributes(*attributes) DisambiguateAttributes.new(attributes) end -end \ No newline at end of file +end diff --git a/spec/matchers/hash_the_same_as.rb b/spec/matchers/hash_the_same_as.rb index c1903b62b4..03e955a0cb 100644 --- a/spec/matchers/hash_the_same_as.rb +++ b/spec/matchers/hash_the_same_as.rb @@ -3,24 +3,24 @@ module HashTheSameAsMatcher def initialize(expected) @expected = expected end - + def matches?(actual) @actual = actual hash = {} hash[@expected] = :some_arbitrary_value hash[@actual] == :some_arbitrary_value end - + def failure_message "expected #{@actual} to hash the same as #{@expected}; they must be `eql?` and have the same `#hash` value" end - + def negative_failure_message "expected #{@actual} to hash differently than #{@expected}; they must not be `eql?` or have a differing `#hash` values" end end - + def hash_the_same_as(expected) HashTheSameAs.new(expected) end -end \ No newline at end of file +end diff --git a/spec/schemas/mysql_schema.rb b/spec/schemas/mysql_schema.rb index 1123f4582e..dc2558fd6a 100644 --- a/spec/schemas/mysql_schema.rb +++ b/spec/schemas/mysql_schema.rb @@ -15,4 +15,4 @@ SQL sql.split(/;/).select(&:present?).each do |sql_statement| ActiveRecord::Base.connection.execute sql_statement -end \ No newline at end of file +end diff --git a/spec/schemas/sqlite3_schema.rb b/spec/schemas/sqlite3_schema.rb index 6c98a4f934..94d224520e 100644 --- a/spec/schemas/sqlite3_schema.rb +++ b/spec/schemas/sqlite3_schema.rb @@ -15,4 +15,4 @@ SQL sql.split(/;/).select(&:present?).each do |sql_statement| ActiveRecord::Base.connection.execute sql_statement -end \ No newline at end of file +end -- cgit v1.2.3 From 0352d28a56de36946e691a0df390cfdfa7b1de7c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:31:16 -0400 Subject: Moving a few stray SQL references in the memory engine code --- lib/arel/engines/memory/predicates.rb | 15 --------------- lib/arel/engines/sql/predicates.rb | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/lib/arel/engines/memory/predicates.rb b/lib/arel/engines/memory/predicates.rb index e233f3ba39..03d4f25b0a 100644 --- a/lib/arel/engines/memory/predicates.rb +++ b/lib/arel/engines/memory/predicates.rb @@ -1,25 +1,10 @@ module Arel - class Binary < Predicate def eval(row) operand1.eval(row).send(operator, operand2.eval(row)) end end - class CompoundPredicate < Binary - def to_sql(formatter = nil) - "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" - end - end - - class Or < CompoundPredicate - def predicate_sql; "OR" end - end - - class And < CompoundPredicate - def predicate_sql; "AND" end - end - class Equality < Binary def operator; :== end end diff --git a/lib/arel/engines/sql/predicates.rb b/lib/arel/engines/sql/predicates.rb index 7e195c2605..b84c183c1d 100644 --- a/lib/arel/engines/sql/predicates.rb +++ b/lib/arel/engines/sql/predicates.rb @@ -5,6 +5,20 @@ module Arel end end + class CompoundPredicate < Binary + def to_sql(formatter = nil) + "(#{operand1.to_sql(formatter)} #{predicate_sql} #{operand2.to_sql(formatter)})" + end + end + + class Or < CompoundPredicate + def predicate_sql; "OR" end + end + + class And < CompoundPredicate + def predicate_sql; "AND" end + end + class Equality < Binary def predicate_sql operand2.equality_predicate_sql -- cgit v1.2.3 From ed8e0f9c02c291a51f93a2123e099d07756d75bb Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:42:17 -0400 Subject: Include modules to extend core classes to improve inspectability --- lib/arel/algebra/extensions/array.rb | 21 +++++---- lib/arel/algebra/extensions/class.rb | 65 +++++++++++++++------------- lib/arel/algebra/extensions/hash.rb | 12 +++-- lib/arel/algebra/extensions/object.rb | 31 +++++++------ lib/arel/algebra/extensions/pathname.rb | 12 +++-- lib/arel/algebra/extensions/symbol.rb | 10 +++-- lib/arel/engines/sql/extensions/array.rb | 19 +++++--- lib/arel/engines/sql/extensions/nil_class.rb | 12 +++-- lib/arel/engines/sql/extensions/object.rb | 18 +++++--- lib/arel/engines/sql/extensions/range.rb | 18 +++++--- 10 files changed, 134 insertions(+), 84 deletions(-) diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb index 48541a395e..e7e44ae909 100644 --- a/lib/arel/algebra/extensions/array.rb +++ b/lib/arel/algebra/extensions/array.rb @@ -1,12 +1,17 @@ -class Array - def to_hash - Hash[*flatten] - end +module Arel + module ArrayExtensions + def to_hash + Hash[*flatten] + end - def group_by - inject({}) do |groups, element| - (groups[yield(element)] ||= []) << element - groups + def group_by + inject({}) do |groups, element| + (groups[yield(element)] ||= []) << element + groups + end end + + Array.send(:include, self) end end + diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index 0a729d8255..d005814f91 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -1,37 +1,42 @@ -class Class - def attributes(*attrs) - @attributes = attrs - attr_reader *attrs - end - - def deriving(*methods) - methods.each { |m| derive m } - end +module Arel + module ClassExtensions + def attributes(*attrs) + @attributes = attrs + attr_reader *attrs + end - def derive(method_name) - methods = { - :initialize => " - def #{method_name}(#{@attributes.join(',')}) - #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} - end - ", - :== => " - def ==(other) - #{name} === other && - #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} - end - " - } - class_eval methods[method_name], __FILE__, __LINE__ - end + def deriving(*methods) + methods.each { |m| derive m } + end - def hash_on(delegatee) - define_method :eql? do |other| - self == other + def derive(method_name) + methods = { + :initialize => " + def #{method_name}(#{@attributes.join(',')}) + #{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")} + end + ", + :== => " + def ==(other) + #{name} === other && + #{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")} + end + " + } + class_eval methods[method_name], __FILE__, __LINE__ end - define_method :hash do - @hash ||= delegatee.hash + def hash_on(delegatee) + define_method :eql? do |other| + self == other + end + + define_method :hash do + @hash ||= delegatee.hash + end end + + Class.send(:include, self) end end + diff --git a/lib/arel/algebra/extensions/hash.rb b/lib/arel/algebra/extensions/hash.rb index 82cd5e11d3..05c15e7ebe 100644 --- a/lib/arel/algebra/extensions/hash.rb +++ b/lib/arel/algebra/extensions/hash.rb @@ -1,7 +1,11 @@ -class Hash - def bind(relation) - inject({}) do |bound, (key, value)| - bound.merge(key.bind(relation) => value.bind(relation)) +module Arel + module HashExtensions + def bind(relation) + inject({}) do |bound, (key, value)| + bound.merge(key.bind(relation) => value.bind(relation)) + end end + + Hash.send(:include, self) end end diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index efdbbf525f..80d68df177 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -1,20 +1,23 @@ -class Object - def bind(relation) - Arel::Value.new(self, relation) - end +module Arel + module ObjectExtensions + def bind(relation) + Arel::Value.new(self, relation) + end - def find_correlate_in(relation) - bind(relation) - end + def find_correlate_in(relation) + bind(relation) + end - def metaclass - class << self - self + def metaclass + class << self + self + end end - end - def let - yield(self) + def let + yield(self) + end + + Object.send(:include, self) end end - diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb index 45f1a5f6b3..829f692d79 100644 --- a/lib/arel/algebra/extensions/pathname.rb +++ b/lib/arel/algebra/extensions/pathname.rb @@ -1,5 +1,9 @@ -class Pathname - def /(path) - (self + path).expand_path +module Arel + module PathnameExtensions + def /(path) + (self + path).expand_path + end + + Pathname.send(:include, self) end -end +end \ No newline at end of file diff --git a/lib/arel/algebra/extensions/symbol.rb b/lib/arel/algebra/extensions/symbol.rb index 8d324a801c..9bb47ef7ab 100644 --- a/lib/arel/algebra/extensions/symbol.rb +++ b/lib/arel/algebra/extensions/symbol.rb @@ -1,5 +1,9 @@ -class Symbol - def to_attribute(relation) - Arel::Attribute.new(relation, self) +module Arel + module SymbolExtensions + def to_attribute(relation) + Arel::Attribute.new(relation, self) + end + + Symbol.send(:include, self) end end diff --git a/lib/arel/engines/sql/extensions/array.rb b/lib/arel/engines/sql/extensions/array.rb index d97dd1aa25..7f15179721 100644 --- a/lib/arel/engines/sql/extensions/array.rb +++ b/lib/arel/engines/sql/extensions/array.rb @@ -1,9 +1,16 @@ -class Array - def to_sql(formatter = nil) - "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" - end +module Arel + module Sql + module ArrayExtensions + def to_sql(formatter = nil) + "(" + collect { |e| e.to_sql(formatter) }.join(', ') + ")" + end - def inclusion_predicate_sql - "IN" + def inclusion_predicate_sql + "IN" + end + + Array.send(:include, self) + end end end + diff --git a/lib/arel/engines/sql/extensions/nil_class.rb b/lib/arel/engines/sql/extensions/nil_class.rb index 6f38ecdf3a..8c335f904a 100644 --- a/lib/arel/engines/sql/extensions/nil_class.rb +++ b/lib/arel/engines/sql/extensions/nil_class.rb @@ -1,5 +1,11 @@ -class NilClass - def equality_predicate_sql - 'IS' +module Arel + module Sql + module NilClassExtensions + def equality_predicate_sql + 'IS' + end + + NilClass.send(:include, self) + end end end diff --git a/lib/arel/engines/sql/extensions/object.rb b/lib/arel/engines/sql/extensions/object.rb index 65270ee3de..8fe63dba2f 100644 --- a/lib/arel/engines/sql/extensions/object.rb +++ b/lib/arel/engines/sql/extensions/object.rb @@ -1,9 +1,15 @@ -class Object - def to_sql(formatter) - formatter.scalar self - end +module Arel + module Sql + module ObjectExtensions + def to_sql(formatter) + formatter.scalar self + end - def equality_predicate_sql - '=' + def equality_predicate_sql + '=' + end + + Object.send(:include, self) + end end end diff --git a/lib/arel/engines/sql/extensions/range.rb b/lib/arel/engines/sql/extensions/range.rb index 946dbc2633..25bf1d01da 100644 --- a/lib/arel/engines/sql/extensions/range.rb +++ b/lib/arel/engines/sql/extensions/range.rb @@ -1,9 +1,15 @@ -class Range - def to_sql(formatter = nil) - formatter.range self.begin, self.end - end +module Arel + module Sql + module RangeExtensions + def to_sql(formatter = nil) + formatter.range self.begin, self.end + end - def inclusion_predicate_sql - "BETWEEN" + def inclusion_predicate_sql + "BETWEEN" + end + + Range.send(:include, self) + end end end -- cgit v1.2.3 From 16707d1b96365ab569e7a5e47a3d694c14d4132c Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:44:38 -0400 Subject: Add spec for Attribute#inspect --- spec/arel/algebra/unit/primitives/attribute_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index 89e338e377..afcf1237e0 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -7,6 +7,12 @@ module Arel @attribute = @relation[:id] end + describe "#inspect" do + it "returns a simple, short inspect string" do + @attribute.inspect.should == "" + end + end + describe Attribute::Transformations do describe '#as' do it "manufactures an aliased attributed" do -- cgit v1.2.3 From 605973614add20b504489e6fac086565717db14b Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:48:04 -0400 Subject: Removing unused array extensions --- lib/arel/algebra/extensions.rb | 1 - lib/arel/algebra/extensions/array.rb | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 lib/arel/algebra/extensions/array.rb diff --git a/lib/arel/algebra/extensions.rb b/lib/arel/algebra/extensions.rb index 694dc60a2a..bc8edd3274 100644 --- a/lib/arel/algebra/extensions.rb +++ b/lib/arel/algebra/extensions.rb @@ -1,5 +1,4 @@ require 'arel/algebra/extensions/object' require 'arel/algebra/extensions/class' -require 'arel/algebra/extensions/array' require 'arel/algebra/extensions/symbol' require 'arel/algebra/extensions/hash' diff --git a/lib/arel/algebra/extensions/array.rb b/lib/arel/algebra/extensions/array.rb deleted file mode 100644 index e7e44ae909..0000000000 --- a/lib/arel/algebra/extensions/array.rb +++ /dev/null @@ -1,17 +0,0 @@ -module Arel - module ArrayExtensions - def to_hash - Hash[*flatten] - end - - def group_by - inject({}) do |groups, element| - (groups[yield(element)] ||= []) << element - groups - end - end - - Array.send(:include, self) - end -end - -- cgit v1.2.3 From 7fc820501ce7b997da43c47ec189aaa0d40645e1 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 16:49:15 -0400 Subject: Removing two unused externalizable? methods --- lib/arel/algebra/relations/operations/group.rb | 4 ---- lib/arel/algebra/relations/operations/skip.rb | 4 ---- 2 files changed, 8 deletions(-) diff --git a/lib/arel/algebra/relations/operations/group.rb b/lib/arel/algebra/relations/operations/group.rb index b8975ed3d6..2bfc42214b 100644 --- a/lib/arel/algebra/relations/operations/group.rb +++ b/lib/arel/algebra/relations/operations/group.rb @@ -8,9 +8,5 @@ module Arel @groupings = (groupings + arguments_from_block(relation, &block)) \ .collect { |g| g.bind(relation) } end - - def externalizable? - true - end end end diff --git a/lib/arel/algebra/relations/operations/skip.rb b/lib/arel/algebra/relations/operations/skip.rb index 2dda191c35..689e06e1c3 100644 --- a/lib/arel/algebra/relations/operations/skip.rb +++ b/lib/arel/algebra/relations/operations/skip.rb @@ -2,9 +2,5 @@ module Arel class Skip < Compound attributes :relation, :skipped deriving :initialize, :== - - def externalizable? - true - end end end -- cgit v1.2.3 From d2988420fc6dd91ca751d96ed648fd1ed52ce342 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 17:53:40 -0400 Subject: Added PostgreSQL to build --- Rakefile | 4 +-- .../engines/sql/unit/predicates/binary_spec.rb | 18 ++++++++-- .../arel/engines/sql/unit/primitives/value_spec.rb | 9 ++++- .../arel/engines/sql/unit/relations/insert_spec.rb | 20 ++++++++++-- .../arel/engines/sql/unit/relations/update_spec.rb | 38 +++++++++++++++++++--- spec/arel/unit/predicates/predicates_spec.rb | 16 +++++++-- spec/connections/postgresql_connection.rb | 12 +++++++ spec/schemas/postgresql_schema.rb | 18 ++++++++++ spec/spec_helper.rb | 14 +++++++- 9 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 spec/connections/postgresql_connection.rb create mode 100644 spec/schemas/postgresql_schema.rb diff --git a/Rakefile b/Rakefile index cfae22260a..17a6f8d35d 100644 --- a/Rakefile +++ b/Rakefile @@ -17,7 +17,7 @@ Spec::Rake::SpecTask.new(:coverage) do |t| end namespace :spec do - for adapter in %w[mysql sqlite3] + for adapter in %w[mysql sqlite3 postgresql] desc "Run specs with the #{adapter} database adapter" Spec::Rake::SpecTask.new(adapter) do |t| t.spec_files = @@ -29,7 +29,7 @@ namespace :spec do end desc "Run specs with mysql and sqlite3 database adapters (default)" -task :spec => ["spec:sqlite3", "spec:mysql"] +task :spec => ["spec:sqlite3", "spec:mysql", "spec:postgresql"] desc "Default task is to run specs" task :default => :spec diff --git a/spec/arel/engines/sql/unit/predicates/binary_spec.rb b/spec/arel/engines/sql/unit/predicates/binary_spec.rb index befd2878d9..b1400e2588 100644 --- a/spec/arel/engines/sql/unit/predicates/binary_spec.rb +++ b/spec/arel/engines/sql/unit/predicates/binary_spec.rb @@ -28,7 +28,11 @@ module Arel sql.should be_like(%Q{(`users`.`id` <=> 1 OR `users`.`name` <=> 'name')}) end - adapter_is_not :mysql do + adapter_is :postgresql do + sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> E'name')}) + end + + adapter_is :sqlite3 do sql.should be_like(%Q{("users"."id" <=> 1 OR "users"."name" <=> 'name')}) end end @@ -44,9 +48,13 @@ module Arel sql.should be_like(%Q{(`users`.`id` <=> 1 AND `users`.`name` <=> 'name')}) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> 'name')}) end + + adapter_is :postgresql do + sql.should be_like(%Q{("users"."id" <=> 1 AND "users"."name" <=> E'name')}) + end end end end @@ -94,9 +102,13 @@ module Arel sql.should be_like(%Q{`users`.`name` <=> '1-asdf'}) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{"users"."name" <=> '1-asdf'}) end + + adapter_is :postgresql do + sql.should be_like(%Q{"users"."name" <=> E'1-asdf'}) + end end end end diff --git a/spec/arel/engines/sql/unit/primitives/value_spec.rb b/spec/arel/engines/sql/unit/primitives/value_spec.rb index da5a163d3b..ff3533f6ef 100644 --- a/spec/arel/engines/sql/unit/primitives/value_spec.rb +++ b/spec/arel/engines/sql/unit/primitives/value_spec.rb @@ -9,7 +9,14 @@ module Arel describe '#to_sql' do it "appropriately quotes the value" do Value.new(1, @relation).to_sql.should be_like('1') - Value.new('asdf', @relation).to_sql.should be_like("'asdf'") + + adapter_is_not :postgresql do + Value.new('asdf', @relation).to_sql.should be_like("'asdf'") + end + + adapter_is :postgresql do + Value.new('asdf', @relation).to_sql.should be_like("E'asdf'") + end end end diff --git a/spec/arel/engines/sql/unit/relations/insert_spec.rb b/spec/arel/engines/sql/unit/relations/insert_spec.rb index dd1995cced..29a5e0bf42 100644 --- a/spec/arel/engines/sql/unit/relations/insert_spec.rb +++ b/spec/arel/engines/sql/unit/relations/insert_spec.rb @@ -30,13 +30,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @insertion.to_sql.should be_like(%Q{ INSERT INTO "users" ("id", "name") VALUES (1, 'nick') }) end + + adapter_is :postgresql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("id", "name") VALUES (1, E'nick') + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -53,13 +61,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @insertion.to_sql.should be_like(%Q{ INSERT INTO "users" ("name") VALUES ('nick') }) end + + adapter_is :postgresql do + @insertion.to_sql.should be_like(%Q{ + INSERT + INTO "users" + ("name") VALUES (E'nick') + }) + end end end diff --git a/spec/arel/engines/sql/unit/relations/update_spec.rb b/spec/arel/engines/sql/unit/relations/update_spec.rb index f553490ef5..4d728eb241 100644 --- a/spec/arel/engines/sql/unit/relations/update_spec.rb +++ b/spec/arel/engines/sql/unit/relations/update_spec.rb @@ -17,12 +17,19 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ UPDATE "users" SET "id" = 1, "name" = 'nick' }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + UPDATE "users" + SET "id" = 1, "name" = E'nick' + }) + end end it "manufactures sql updating attributes when given a ranged relation" do @@ -36,13 +43,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ UPDATE "users" SET "name" = 'nick' LIMIT 1 }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + UPDATE "users" + SET "name" = E'nick' + LIMIT 1 + }) + end end describe 'when given values whose types correspond to the types of the attributes' do @@ -58,12 +73,19 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @update.to_sql.should be_like(%Q{ UPDATE "users" SET "name" = 'nick' }) end + + adapter_is :postgresql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = E'nick' + }) + end end end @@ -106,13 +128,21 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do @update.to_sql.should be_like(%Q{ UPDATE "users" SET "name" = 'nick' WHERE "users"."id" = 1 }) end + + adapter_is :postgresql do + @update.to_sql.should be_like(%Q{ + UPDATE "users" + SET "name" = E'nick' + WHERE "users"."id" = 1 + }) + end end end end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb index ac842998af..8e7e0b1d9f 100644 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ b/spec/arel/unit/predicates/predicates_spec.rb @@ -21,11 +21,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ ("users"."id" = 1 AND "users"."name" = 'name') }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = E'name') + }) + end end end end @@ -41,11 +47,17 @@ module Arel }) end - adapter_is_not :mysql do + adapter_is :sqlite3 do sql.should be_like(%Q{ ("users"."id" = 1 OR "users"."name" = 'name') }) end + + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = E'name') + }) + end end end end diff --git a/spec/connections/postgresql_connection.rb b/spec/connections/postgresql_connection.rb new file mode 100644 index 0000000000..505dcdd1ef --- /dev/null +++ b/spec/connections/postgresql_connection.rb @@ -0,0 +1,12 @@ +require "activerecord" +puts "Using native PostgreSQL" + +ActiveRecord::Base.configurations = { + 'unit' => { + :adapter => 'postgresql', + :encoding => 'utf8', + :database => 'arel_unit', + } +} + +ActiveRecord::Base.establish_connection 'unit' diff --git a/spec/schemas/postgresql_schema.rb b/spec/schemas/postgresql_schema.rb new file mode 100644 index 0000000000..30fa665902 --- /dev/null +++ b/spec/schemas/postgresql_schema.rb @@ -0,0 +1,18 @@ +sql = <<-SQL + DROP TABLE IF EXISTS users; + CREATE TABLE users ( + id SERIAL PRIMARY KEY NOT NULL, + name VARCHAR(255) NOT NULL + ); + + DROP TABLE IF EXISTS photos; + CREATE TABLE photos ( + id SERIAL PRIMARY KEY NOT NULL, + user_id INTEGER NOT NULL, + camera_id INTEGER NOT NULL + ); +SQL + +sql.split(/;/).select(&:present?).each do |sql_statement| + ActiveRecord::Base.connection.execute sql_statement +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6a9a2ef23c..beb634fbd3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -13,15 +13,27 @@ end module AdapterGuards def adapter_is(name) + verify_adapter_name(name) yield if name.to_s == adapter_name end def adapter_is_not(name) + verify_adapter_name(name) yield if name.to_s != adapter_name end def adapter_name - Arel::Table.engine.connection.class.name.underscore.split("/").last.gsub(/_adapter/, '') + name = ActiveRecord::Base.configurations["unit"][:adapter] + verify_adapter_name(name) + name + end + + def verify_adapter_name(name) + raise "Invalid adapter name: #{name}" unless valid_adapters.include?(name.to_s) + end + + def valid_adapters + %w[mysql postgresql sqlite3] end end -- cgit v1.2.3 From c106c1ef59527331c9945f5f95e6b4e27194ac06 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:08:13 -0400 Subject: Moving SQL predicates spec to correct dir --- .../engines/sql/unit/predicates/predicates_spec.rb | 65 ++++++++++++++++++++++ spec/arel/unit/predicates/predicates_spec.rb | 65 ---------------------- 2 files changed, 65 insertions(+), 65 deletions(-) create mode 100644 spec/arel/engines/sql/unit/predicates/predicates_spec.rb delete mode 100644 spec/arel/unit/predicates/predicates_spec.rb diff --git a/spec/arel/engines/sql/unit/predicates/predicates_spec.rb b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb new file mode 100644 index 0000000000..d55e178e43 --- /dev/null +++ b/spec/arel/engines/sql/unit/predicates/predicates_spec.rb @@ -0,0 +1,65 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Predicate do + before do + @relation = Table.new(:users) + @attribute1 = @relation[:id] + @attribute2 = @relation[:name] + @operand1 = Equality.new(@attribute1, 1) + @operand2 = Equality.new(@attribute2, "name") + end + + describe "when being combined with another predicate with AND logic" do + describe "#to_sql" do + it "manufactures sql with an AND operation" do + sql = @operand1.and(@operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 AND `users`.`name` = 'name') + }) + end + + adapter_is :sqlite3 do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = 'name') + }) + end + + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 AND "users"."name" = E'name') + }) + end + end + end + end + + describe "when being combined with another predicate with OR logic" do + describe "#to_sql" do + it "manufactures sql with an OR operation" do + sql = @operand1.or(@operand2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + (`users`.`id` = 1 OR `users`.`name` = 'name') + }) + end + + adapter_is :sqlite3 do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = 'name') + }) + end + + adapter_is :postgresql do + sql.should be_like(%Q{ + ("users"."id" = 1 OR "users"."name" = E'name') + }) + end + end + end + end + end +end diff --git a/spec/arel/unit/predicates/predicates_spec.rb b/spec/arel/unit/predicates/predicates_spec.rb deleted file mode 100644 index 8e7e0b1d9f..0000000000 --- a/spec/arel/unit/predicates/predicates_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') - -module Arel - describe Predicate do - before do - @relation = Table.new(:users) - @attribute1 = @relation[:id] - @attribute2 = @relation[:name] - @operand1 = Equality.new(@attribute1, 1) - @operand2 = Equality.new(@attribute2, "name") - end - - describe "when being combined with another predicate with AND logic" do - describe "#to_sql" do - it "manufactures sql with an AND operation" do - sql = @operand1.and(@operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - (`users`.`id` = 1 AND `users`.`name` = 'name') - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - ("users"."id" = 1 AND "users"."name" = 'name') - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - ("users"."id" = 1 AND "users"."name" = E'name') - }) - end - end - end - end - - describe "when being combined with another predicate with OR logic" do - describe "#to_sql" do - it "manufactures sql with an OR operation" do - sql = @operand1.or(@operand2).to_sql - - adapter_is :mysql do - sql.should be_like(%Q{ - (`users`.`id` = 1 OR `users`.`name` = 'name') - }) - end - - adapter_is :sqlite3 do - sql.should be_like(%Q{ - ("users"."id" = 1 OR "users"."name" = 'name') - }) - end - - adapter_is :postgresql do - sql.should be_like(%Q{ - ("users"."id" = 1 OR "users"."name" = E'name') - }) - end - end - end - end - end -end -- cgit v1.2.3 From 10c4b42c35f61145ac6ebb8d36f504344eef47cd Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:21:56 -0400 Subject: Fix bug in Order equality where Descending.new(attribute) was == Ascending.new(attribute) --- lib/arel/algebra/primitives/ordering.rb | 13 +++++++++---- spec/arel/algebra/unit/primitives/attribute_spec.rb | 4 ++-- spec/arel/algebra/unit/relations/order_spec.rb | 10 ++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/arel/algebra/primitives/ordering.rb b/lib/arel/algebra/primitives/ordering.rb index a60d794f27..3efb4c6280 100644 --- a/lib/arel/algebra/primitives/ordering.rb +++ b/lib/arel/algebra/primitives/ordering.rb @@ -1,7 +1,5 @@ module Arel class Ordering - attributes :attribute - deriving :initialize, :== delegate :relation, :to => :attribute def bind(relation) @@ -13,6 +11,13 @@ module Arel end end - class Ascending < Ordering; end - class Descending < Ordering; end + class Ascending < Ordering + attributes :attribute + deriving :initialize, :== + end + + class Descending < Ordering + attributes :attribute + deriving :initialize, :== + end end diff --git a/spec/arel/algebra/unit/primitives/attribute_spec.rb b/spec/arel/algebra/unit/primitives/attribute_spec.rb index afcf1237e0..2ca63ba48e 100644 --- a/spec/arel/algebra/unit/primitives/attribute_spec.rb +++ b/spec/arel/algebra/unit/primitives/attribute_spec.rb @@ -169,13 +169,13 @@ module Arel describe Attribute::Orderings do describe '#asc' do it 'manufactures an ascending ordering' do - pending + @attribute.asc.should == Ascending.new(@attribute) end end describe '#desc' do it 'manufactures a descending ordering' do - pending + @attribute.desc.should == Descending.new(@attribute) end end end diff --git a/spec/arel/algebra/unit/relations/order_spec.rb b/spec/arel/algebra/unit/relations/order_spec.rb index 4f163894c8..8b3c932fb9 100644 --- a/spec/arel/algebra/unit/relations/order_spec.rb +++ b/spec/arel/algebra/unit/relations/order_spec.rb @@ -6,6 +6,16 @@ module Arel @relation = Table.new(:users) @attribute = @relation[:id] end + + describe "#==" do + it "returns true when the Orders are for the same attribute and direction" do + Ascending.new(@attribute).should == Ascending.new(@attribute) + end + + it "returns false when the Orders are for a diferent direction" do + Ascending.new(@attribute).should_not == Descending.new(@attribute) + end + end end end -- cgit v1.2.3 From a842aa572af1e8fac48f8a73a2e2985fbe39e046 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:35:45 -0400 Subject: Removing Object#metaclass definition (it's already in ActiveSupport) --- lib/arel/algebra/extensions/object.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/algebra/extensions/object.rb b/lib/arel/algebra/extensions/object.rb index 80d68df177..d8c60b5dd5 100644 --- a/lib/arel/algebra/extensions/object.rb +++ b/lib/arel/algebra/extensions/object.rb @@ -8,12 +8,6 @@ module Arel bind(relation) end - def metaclass - class << self - self - end - end - def let yield(self) end -- cgit v1.2.3 From 9560650fa79212b33d6ab349ff83b4f617d395b7 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:36:08 -0400 Subject: Adding skeleton of spec for CRUD operations in Sql::Engine --- spec/arel/engines/sql/unit/engine_spec.rb | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 spec/arel/engines/sql/unit/engine_spec.rb diff --git a/spec/arel/engines/sql/unit/engine_spec.rb b/spec/arel/engines/sql/unit/engine_spec.rb new file mode 100644 index 0000000000..67a5d62320 --- /dev/null +++ b/spec/arel/engines/sql/unit/engine_spec.rb @@ -0,0 +1,36 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') + +module Arel + describe Sql::Engine do + before do + @relation = Table.new(:users) + end + + describe "CRUD" do + describe "#create" do + it "inserts into the relation" do + @relation.insert @relation[:name] => "Bryan" + end + end + + describe "#read" do + it "reads from the relation" do + @relation.each do |row| + end + end + end + + describe "#update" do + it "updates the relation" do + @relation.update @relation[:name] => "Bryan" + end + end + + describe "#delete" do + it "deletes from the relation" do + @relation.delete + end + end + end + end +end -- cgit v1.2.3 From 982f100d49095614df320d449f66f69aa827a763 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:40:24 -0400 Subject: Refactor #select_sql. Extract methods to generate clauses --- lib/arel/engines/sql/relations/relation.rb | 34 ++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index 93c146352c..c8a4d952fe 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -6,17 +6,18 @@ module Arel def select_sql [ - "SELECT #{attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) }.join(', ')}", + "SELECT #{select_clauses.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", - (joins(self) unless joins(self).blank? ), - ("WHERE #{wheres .collect { |w| w.to_sql(Sql::WhereClause.new(self)) }.join("\n\tAND ")}" unless wheres.blank? ), - ("GROUP BY #{groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) }.join(', ')}" unless groupings.blank? ), - ("ORDER BY #{orders .collect { |o| o.to_sql(Sql::OrderClause.new(self)) }.join(', ')}" unless orders.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ("OFFSET #{skipped}" unless skipped.blank? ) + (joins(self) unless joins(self).blank? ), + ("WHERE #{where_clauses.join("\n\tAND ")}" unless wheres.blank? ), + ("GROUP BY #{group_clauses.join(', ')}" unless groupings.blank? ), + ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), + ("LIMIT #{taken}" unless taken.blank? ), + ("OFFSET #{skipped}" unless skipped.blank? ) ].compact.join("\n") end + def inclusion_predicate_sql "IN" end @@ -24,5 +25,24 @@ module Arel def christener @christener ||= Sql::Christener.new end + + protected + + def select_clauses + attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } + end + + def where_clauses + wheres.collect { |w| w.to_sql(Sql::WhereClause.new(self)) } + end + + def group_clauses + groupings.collect { |g| g.to_sql(Sql::GroupClause.new(self)) } + end + + def order_clauses + orders.collect { |o| o.to_sql(Sql::OrderClause.new(self)) } + end + end end -- cgit v1.2.3 From 2e6fbf4f75c8e33380623b52e86ca8b90037712f Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Sun, 17 May 2009 18:47:45 -0400 Subject: Extracting #build_query method for creating SQL from parts --- lib/arel/engines/sql/relations/relation.rb | 8 +++--- .../engines/sql/relations/utilities/compound.rb | 4 +++ lib/arel/engines/sql/relations/writes.rb | 29 ++++++++++++---------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/lib/arel/engines/sql/relations/relation.rb b/lib/arel/engines/sql/relations/relation.rb index c8a4d952fe..4cfb83a601 100644 --- a/lib/arel/engines/sql/relations/relation.rb +++ b/lib/arel/engines/sql/relations/relation.rb @@ -5,7 +5,7 @@ module Arel end def select_sql - [ + build_query \ "SELECT #{select_clauses.join(', ')}", "FROM #{table_sql(Sql::TableReference.new(self))}", (joins(self) unless joins(self).blank? ), @@ -14,10 +14,8 @@ module Arel ("ORDER BY #{order_clauses.join(', ')}" unless orders.blank? ), ("LIMIT #{taken}" unless taken.blank? ), ("OFFSET #{skipped}" unless skipped.blank? ) - ].compact.join("\n") end - def inclusion_predicate_sql "IN" end @@ -28,6 +26,10 @@ module Arel protected + def build_query(*parts) + parts.compact.join("\n") + end + def select_clauses attributes.collect { |a| a.to_sql(Sql::SelectClause.new(self)) } end diff --git a/lib/arel/engines/sql/relations/utilities/compound.rb b/lib/arel/engines/sql/relations/utilities/compound.rb index b63a829c67..f8ce4033fd 100644 --- a/lib/arel/engines/sql/relations/utilities/compound.rb +++ b/lib/arel/engines/sql/relations/utilities/compound.rb @@ -1,6 +1,10 @@ module Arel class Compound < Relation delegate :table, :table_sql, :to => :relation + + def build_query(*parts) + parts.compact.join("\n") + end end end diff --git a/lib/arel/engines/sql/relations/writes.rb b/lib/arel/engines/sql/relations/writes.rb index 4d753f5fca..f1a9bfd2ac 100644 --- a/lib/arel/engines/sql/relations/writes.rb +++ b/lib/arel/engines/sql/relations/writes.rb @@ -1,36 +1,39 @@ module Arel class Deletion < Compound def to_sql(formatter = nil) - [ + build_query \ "DELETE", "FROM #{table_sql}", - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ), - ].compact.join("\n") + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) end end class Insert < Compound def to_sql(formatter = nil) - [ + build_query \ "INSERT", "INTO #{table_sql}", "(#{record.keys.collect { |key| engine.quote_column_name(key.name) }.join(', ')})", "VALUES (#{record.collect { |key, value| key.format(value) }.join(', ')})" - ].join("\n") end end class Update < Compound def to_sql(formatter = nil) - [ + build_query \ "UPDATE #{table_sql} SET", - assignments.collect do |attribute, value| - "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" - end.join(",\n"), - ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), - ("LIMIT #{taken}" unless taken.blank? ) - ].join("\n") + assignment_sql, + ("WHERE #{wheres.collect(&:to_sql).join('\n\tAND ')}" unless wheres.blank? ), + ("LIMIT #{taken}" unless taken.blank? ) + end + + protected + + def assignment_sql + assignments.collect do |attribute, value| + "#{engine.quote_column_name(attribute.name)} = #{attribute.format(value)}" + end.join(",\n") end end end -- cgit v1.2.3 From d3c343c6afdc65ca959beaeb20d71dd9f2fcf93f Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 00:59:01 -0400 Subject: Remvoing unused variable from spec --- spec/arel/engines/memory/unit/relations/join_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/arel/engines/memory/unit/relations/join_spec.rb b/spec/arel/engines/memory/unit/relations/join_spec.rb index df08fd4a96..110fdb03b7 100644 --- a/spec/arel/engines/memory/unit/relations/join_spec.rb +++ b/spec/arel/engines/memory/unit/relations/join_spec.rb @@ -9,7 +9,6 @@ module Arel [3, 'goose'] ], [:id, :name]) @relation2 = @relation1.alias - @relation3 = @relation1.alias end describe InnerJoin do -- cgit v1.2.3 From 1234c926cce2a979ec967a8c5bc6ba58cda1ce71 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 00:59:08 -0400 Subject: Cleaning up Sql::Engine#read --- lib/arel/engines/sql/engine.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/arel/engines/sql/engine.rb b/lib/arel/engines/sql/engine.rb index 5a8c9f16c5..7d2926040c 100644 --- a/lib/arel/engines/sql/engine.rb +++ b/lib/arel/engines/sql/engine.rb @@ -19,13 +19,7 @@ module Arel end def read(relation) - # FIXME rows = connection.select_rows(relation.to_sql) - - class << rows - include Enumerable - end - Array.new(rows, relation.attributes) end -- cgit v1.2.3 From 930c9f90a03729bdc380ab84882a118d8c17e54d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:11:40 -0400 Subject: Cleanup Sql formatters a bit --- lib/arel/engines/sql/formatters.rb | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/arel/engines/sql/formatters.rb b/lib/arel/engines/sql/formatters.rb index 08a32843c9..ae80feb18e 100644 --- a/lib/arel/engines/sql/formatters.rb +++ b/lib/arel/engines/sql/formatters.rb @@ -14,18 +14,17 @@ module Arel class SelectClause < Formatter def attribute(attribute) # FIXME this should check that the column exists - if attribute.name.to_s =~ /^\w*$/ - "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - else - attribute.name.to_s + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") - end + "#{quote_table_name(name_for(attribute.original_relation))}.#{quote_column_name(attribute.name)}" + + (attribute.alias ? " AS #{quote(attribute.alias.to_s)}" : "") end def expression(expression) if expression.function_sql == "DISTINCT" - "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') + "#{expression.function_sql} #{expression.attribute.to_sql(self)}" + + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : '') else - "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") + "#{expression.function_sql}(#{expression.attribute.to_sql(self)})" + + (expression.alias ? " AS #{quote_column_name(expression.alias)}" : " AS #{expression.function_sql.to_s.downcase}_id") end end @@ -93,11 +92,8 @@ module Arel end def table(table) - if table.name =~ /^(\w|-)*$/ - quote_table_name(table.name) + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') - else - table.name + (table.name != name_for(table) ? " AS " + (name_for(table)) : '') - end + quote_table_name(table.name) + + (table.name != name_for(table) ? " AS " + quote_table_name(name_for(table)) : '') end end @@ -106,10 +102,6 @@ module Arel quote(scalar, environment.column) end - def array(array) - "(" + array.collect { |e| e.to_sql(self) }.join(', ') + ")" - end - def range(left, right) "#{left} AND #{right}" end -- cgit v1.2.3 From 65e419c172217f9747e2e56b36fcc4b6089a0d6d Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:25:09 -0400 Subject: Expand usages of #hash_on. The #hash definition it produces looks broken, but leaving it for now --- lib/arel/algebra/extensions/class.rb | 10 ---------- lib/arel/algebra/relations/operations/join.rb | 9 ++++++++- lib/arel/algebra/relations/utilities/compound.rb | 12 ++++++++++-- lib/arel/engines/sql/relations/table.rb | 9 ++++++++- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/lib/arel/algebra/extensions/class.rb b/lib/arel/algebra/extensions/class.rb index d005814f91..520111b90f 100644 --- a/lib/arel/algebra/extensions/class.rb +++ b/lib/arel/algebra/extensions/class.rb @@ -25,16 +25,6 @@ module Arel } class_eval methods[method_name], __FILE__, __LINE__ end - - def hash_on(delegatee) - define_method :eql? do |other| - self == other - end - - define_method :hash do - @hash ||= delegatee.hash - end - end Class.send(:include, self) end diff --git a/lib/arel/algebra/relations/operations/join.rb b/lib/arel/algebra/relations/operations/join.rb index e47d9fa9e0..e9320f28e1 100644 --- a/lib/arel/algebra/relations/operations/join.rb +++ b/lib/arel/algebra/relations/operations/join.rb @@ -3,12 +3,19 @@ module Arel attributes :relation1, :relation2, :predicates deriving :== delegate :name, :to => :relation1 - hash_on :relation1 def initialize(relation1, relation2 = Nil.instance, *predicates) @relation1, @relation2, @predicates = relation1, relation2, predicates end + def hash + @hash ||= :relation1.hash + end + + def eql?(other) + self == other + end + def attributes @attributes ||= (relation1.externalize.attributes + relation2.externalize.attributes).collect { |a| a.bind(self) } diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 676d80a737..5e775618f1 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -1,7 +1,6 @@ module Arel class Compound < Relation attr_reader :relation - hash_on :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, :column_for, :engine, :to => :relation @@ -14,7 +13,16 @@ module Arel OPERATION end - private + def hash + @hash ||= :relation.hash + end + + def eql?(other) + self == other + end + + private + def arguments_from_block(relation, &block) block_given?? [yield(relation)] : [] end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index 0b6574eedc..dd22f44226 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -4,7 +4,6 @@ module Arel cattr_accessor :engine attr_reader :name, :engine - hash_on :name def initialize(name, engine = Table.engine) @name, @engine = name.to_s, engine @@ -16,6 +15,14 @@ module Arel end end + def eql?(other) + self == other + end + + def hash + @hash ||= :name.hash + end + def format(attribute, value) attribute.column.type_cast(value) end -- cgit v1.2.3 From fbfbf1adcb2252c326aa869a6f94bd3269565ba2 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:36:12 -0400 Subject: Removing unused Pathname extension --- lib/arel/algebra/extensions/pathname.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 lib/arel/algebra/extensions/pathname.rb diff --git a/lib/arel/algebra/extensions/pathname.rb b/lib/arel/algebra/extensions/pathname.rb deleted file mode 100644 index 829f692d79..0000000000 --- a/lib/arel/algebra/extensions/pathname.rb +++ /dev/null @@ -1,9 +0,0 @@ -module Arel - module PathnameExtensions - def /(path) - (self + path).expand_path - end - - Pathname.send(:include, self) - end -end \ No newline at end of file -- cgit v1.2.3 From 8feb358bd00cea30eb677e32f10995f5eddc167a Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:47:42 -0400 Subject: Ignore debug.log --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index da2f440bad..c6dd721751 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ coverage/* config/database.yml spec/fixtures/*database* *.DS_Store +debug.log -- cgit v1.2.3 From 082079169caab2a00f62d9de9c4bdb5dcbc591aa Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:49:50 -0400 Subject: Better inspect output for Expressions --- lib/arel/algebra/primitives/expression.rb | 4 ++++ spec/arel/algebra/unit/primitives/expression_spec.rb | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/lib/arel/algebra/primitives/expression.rb b/lib/arel/algebra/primitives/expression.rb index 5566e2d0b7..875498c282 100644 --- a/lib/arel/algebra/primitives/expression.rb +++ b/lib/arel/algebra/primitives/expression.rb @@ -13,6 +13,10 @@ module Arel true end + def inspect + "<#{self.class.name} #{attribute.inspect}>" + end + module Transformations def as(aliaz) self.class.new(attribute, aliaz, self) diff --git a/spec/arel/algebra/unit/primitives/expression_spec.rb b/spec/arel/algebra/unit/primitives/expression_spec.rb index 82d12d53f9..768bb492a7 100644 --- a/spec/arel/algebra/unit/primitives/expression_spec.rb +++ b/spec/arel/algebra/unit/primitives/expression_spec.rb @@ -7,6 +7,12 @@ module Arel @attribute = @relation[:id] end + describe "#inspect" do + it "returns a simple, short inspect string" do + @attribute.count.inspect.should == ">" + end + end + describe Expression::Transformations do before do @expression = Count.new(@attribute) -- cgit v1.2.3 From eede6962a8c1ee86b49907c1937fb0e3a38cf819 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:50:39 -0400 Subject: Log queries to debug.log when running specs --- spec/connections/mysql_connection.rb | 2 ++ spec/connections/postgresql_connection.rb | 2 ++ spec/connections/sqlite3_connection.rb | 2 ++ 3 files changed, 6 insertions(+) diff --git a/spec/connections/mysql_connection.rb b/spec/connections/mysql_connection.rb index b4e27f2380..a58ddc35ef 100644 --- a/spec/connections/mysql_connection.rb +++ b/spec/connections/mysql_connection.rb @@ -1,6 +1,8 @@ require "activerecord" puts "Using native MySQL" +ActiveRecord::Base.logger = Logger.new("debug.log") + ActiveRecord::Base.configurations = { 'unit' => { :adapter => 'mysql', diff --git a/spec/connections/postgresql_connection.rb b/spec/connections/postgresql_connection.rb index 505dcdd1ef..e376d33ec6 100644 --- a/spec/connections/postgresql_connection.rb +++ b/spec/connections/postgresql_connection.rb @@ -1,6 +1,8 @@ require "activerecord" puts "Using native PostgreSQL" +ActiveRecord::Base.logger = Logger.new("debug.log") + ActiveRecord::Base.configurations = { 'unit' => { :adapter => 'postgresql', diff --git a/spec/connections/sqlite3_connection.rb b/spec/connections/sqlite3_connection.rb index bae077711d..649492f804 100644 --- a/spec/connections/sqlite3_connection.rb +++ b/spec/connections/sqlite3_connection.rb @@ -1,6 +1,8 @@ require "activerecord" puts "Using native SQLite3" +ActiveRecord::Base.logger = Logger.new("debug.log") + db_file = "spec/fixtures/fixture_database.sqlite3" ActiveRecord::Base.configurations = { -- cgit v1.2.3 From 976fb01a5dd812bcb50cc7b576941c76657908f9 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Mon, 18 May 2009 01:50:50 -0400 Subject: Expand sql engine CRUD specs --- spec/arel/engines/sql/unit/engine_spec.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/spec/arel/engines/sql/unit/engine_spec.rb b/spec/arel/engines/sql/unit/engine_spec.rb index 67a5d62320..c607abcfa1 100644 --- a/spec/arel/engines/sql/unit/engine_spec.rb +++ b/spec/arel/engines/sql/unit/engine_spec.rb @@ -3,32 +3,41 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper') module Arel describe Sql::Engine do before do - @relation = Table.new(:users) + @users = Table.new(:users) + @users.delete end describe "CRUD" do describe "#create" do it "inserts into the relation" do - @relation.insert @relation[:name] => "Bryan" + @users.insert @users[:name] => "Bryan" + @users.first[@users[:name]].should == "Bryan" end end describe "#read" do it "reads from the relation" do - @relation.each do |row| + @users.insert @users[:name] => "Bryan" + + @users.each do |row| + row[@users[:name]].should == "Bryan" end end end describe "#update" do it "updates the relation" do - @relation.update @relation[:name] => "Bryan" + @users.insert @users[:name] => "Nick" + @users.update @users[:name] => "Bryan" + @users.first[@users[:name]].should == "Bryan" end end describe "#delete" do it "deletes from the relation" do - @relation.delete + @users.insert @users[:name] => "Bryan" + @users.delete + @users.first.should == nil end end end -- cgit v1.2.3 From 86364591af807ed3fa4a7304f53e6f3458cb4961 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 19 May 2009 21:36:34 -0400 Subject: Adding SqlLiteral with spec for counts --- lib/arel/engines/sql/primitives.rb | 10 ++++++++++ .../engines/sql/unit/primitives/literal_spec.rb | 23 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 spec/arel/engines/sql/unit/primitives/literal_spec.rb diff --git a/lib/arel/engines/sql/primitives.rb b/lib/arel/engines/sql/primitives.rb index f2e8e8dabe..bb3bed78e6 100644 --- a/lib/arel/engines/sql/primitives.rb +++ b/lib/arel/engines/sql/primitives.rb @@ -1,4 +1,14 @@ module Arel + class SqlLiteral < String + def relation + nil + end + + def to_sql(formatter = nil) + self + end + end + class Attribute def column original_relation.column_for(self) diff --git a/spec/arel/engines/sql/unit/primitives/literal_spec.rb b/spec/arel/engines/sql/unit/primitives/literal_spec.rb new file mode 100644 index 0000000000..c7ff1cf879 --- /dev/null +++ b/spec/arel/engines/sql/unit/primitives/literal_spec.rb @@ -0,0 +1,23 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', '..', '..', 'spec_helper') + +module Arel + describe SqlLiteral do + before do + @relation = Table.new(:users) + end + + describe '#to_sql' do + it "manufactures sql with a literal SQL fragment" do + sql = @relation.project(Count.new(SqlLiteral.new("*"))).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM `users`}) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{SELECT COUNT(*) AS count_id FROM "users"}) + end + end + end + end +end -- cgit v1.2.3