aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Manifest.txt100
-rw-r--r--README.markdown18
-rw-r--r--Rakefile29
-rw-r--r--arel.gemspec50
-rw-r--r--doc/CONVENTIONS17
-rw-r--r--doc/TODO118
6 files changed, 156 insertions, 176 deletions
diff --git a/Manifest.txt b/Manifest.txt
new file mode 100644
index 0000000000..b7e600f1a9
--- /dev/null
+++ b/Manifest.txt
@@ -0,0 +1,100 @@
+History.txt
+Manifest.txt
+README.markdown
+Rakefile
+arel.gemspec
+lib/arel.rb
+lib/arel/attributes.rb
+lib/arel/attributes/attribute.rb
+lib/arel/compatibility/wheres.rb
+lib/arel/crud.rb
+lib/arel/delete_manager.rb
+lib/arel/deprecated.rb
+lib/arel/expression.rb
+lib/arel/expressions.rb
+lib/arel/insert_manager.rb
+lib/arel/nodes.rb
+lib/arel/nodes/and.rb
+lib/arel/nodes/assignment.rb
+lib/arel/nodes/avg.rb
+lib/arel/nodes/between.rb
+lib/arel/nodes/binary.rb
+lib/arel/nodes/count.rb
+lib/arel/nodes/delete_statement.rb
+lib/arel/nodes/equality.rb
+lib/arel/nodes/exists.rb
+lib/arel/nodes/function.rb
+lib/arel/nodes/greater_than.rb
+lib/arel/nodes/greater_than_or_equal.rb
+lib/arel/nodes/group.rb
+lib/arel/nodes/grouping.rb
+lib/arel/nodes/having.rb
+lib/arel/nodes/in.rb
+lib/arel/nodes/inner_join.rb
+lib/arel/nodes/insert_statement.rb
+lib/arel/nodes/join.rb
+lib/arel/nodes/less_than.rb
+lib/arel/nodes/less_than_or_equal.rb
+lib/arel/nodes/lock.rb
+lib/arel/nodes/max.rb
+lib/arel/nodes/min.rb
+lib/arel/nodes/node.rb
+lib/arel/nodes/not_equal.rb
+lib/arel/nodes/offset.rb
+lib/arel/nodes/on.rb
+lib/arel/nodes/or.rb
+lib/arel/nodes/outer_join.rb
+lib/arel/nodes/select_core.rb
+lib/arel/nodes/select_statement.rb
+lib/arel/nodes/sql_literal.rb
+lib/arel/nodes/string_join.rb
+lib/arel/nodes/sum.rb
+lib/arel/nodes/table_alias.rb
+lib/arel/nodes/unqualified_column.rb
+lib/arel/nodes/update_statement.rb
+lib/arel/nodes/values.rb
+lib/arel/relation.rb
+lib/arel/select_manager.rb
+lib/arel/sql/engine.rb
+lib/arel/sql_literal.rb
+lib/arel/table.rb
+lib/arel/tree_manager.rb
+lib/arel/update_manager.rb
+lib/arel/version.rb
+lib/arel/visitors.rb
+lib/arel/visitors/dot.rb
+lib/arel/visitors/join_sql.rb
+lib/arel/visitors/mysql.rb
+lib/arel/visitors/oracle.rb
+lib/arel/visitors/order_clauses.rb
+lib/arel/visitors/postgresql.rb
+lib/arel/visitors/to_sql.rb
+spec/activerecord_compat_spec.rb
+spec/attributes/attribute_spec.rb
+spec/attributes_spec.rb
+spec/crud_spec.rb
+spec/delete_manager_spec.rb
+spec/insert_manager_spec.rb
+spec/nodes/count_spec.rb
+spec/nodes/delete_statement_spec.rb
+spec/nodes/equality_spec.rb
+spec/nodes/insert_statement_spec.rb
+spec/nodes/or_spec.rb
+spec/nodes/select_core_spec.rb
+spec/nodes/select_statement_spec.rb
+spec/nodes/sql_literal_spec.rb
+spec/nodes/sum_spec.rb
+spec/nodes/update_statement_spec.rb
+spec/select_manager_spec.rb
+spec/spec.opts
+spec/spec_helper.rb
+spec/support/check.rb
+spec/support/fake_record.rb
+spec/support/matchers.rb
+spec/support/matchers/be_like.rb
+spec/support/shared/tree_manager_shared.rb
+spec/table_spec.rb
+spec/update_manager_spec.rb
+spec/visitors/join_sql_spec.rb
+spec/visitors/oracle_spec.rb
+spec/visitors/to_sql_spec.rb
diff --git a/README.markdown b/README.markdown
index f28ed1e0a1..10d3f0a021 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,14 +1,18 @@
-## Abstract ##
+# ARel
+
+* http://github.com/rails/arel
+
+## DESCRIPTION
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 ##
+## Status
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 ##
+## A Gentle Introduction
Generating a query with ARel is simple. For example, in order to produce
@@ -29,7 +33,7 @@ In other words, Arel relations implement Ruby's Enumerable interface. Let's have
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 <strike>Queries</strike> Relations ###
+### More Sophisticated Queries
Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database.
@@ -85,11 +89,11 @@ Finally, most operations take a block form. For example:
This provides a (sometimes) convenient alternative syntax.
-### The Crazy Features ###
+### 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 ####
+#### 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:
@@ -124,7 +128,7 @@ Note that you do NOT want to do something like:
This does NOT have the same meaning as the previous query, since the comments[:parent_id] reference is effectively ambiguous.
-#### Complex Aggregations ####
+#### 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.
diff --git a/Rakefile b/Rakefile
index 50948d2c51..893b143866 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,18 +1,19 @@
require "rubygems"
+gem 'hoe', '>= 2.1.0'
+require 'hoe'
-begin
- require "spec/rake/spectask"
-rescue LoadError
- desc "Run specs"
- task(:spec) { $stderr.puts '`gem install rspec` to run specs' }
-else
- Spec::Rake::SpecTask.new do |t|
- t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
- t.libs << "spec"
- t.warning = true
- t.spec_files = FileList['spec/**/*_spec.rb']
- end
+Hoe.plugin :gemspec # install hoe-gemspec
- desc "Default task is to run specs"
- task :default => :spec
+Hoe.spec 'arel' do
+ developer('Aaron Patterson', 'aaron@tenderlovemaking.com')
+ developer('Bryan Halmkamp', 'bryan@brynary.com')
+ developer('Emilio Tagua', 'miloops@gmail.com')
+ developer('Nick Kallen', 'nick@example.org') # FIXME: need Nick's email
+
+ self.readme_file = 'README.markdown'
+ self.extra_rdoc_files = FileList['README.markdown']
+ self.testlib = :rspec
end
+
+desc "Default task is to run specs"
+task :default => :spec
diff --git a/arel.gemspec b/arel.gemspec
index de63a1d120..a93d922a1b 100644
--- a/arel.gemspec
+++ b/arel.gemspec
@@ -1,26 +1,36 @@
# -*- encoding: utf-8 -*-
-require 'arel/version'
Gem::Specification.new do |s|
- s.name = "arel"
- s.version = Arel::VERSION
- s.authors = ["Bryan Helmkamp", "Nick Kallen", "Emilio Tagua"]
- s.date = %q{2010-06-08}
- s.email = "bryan@brynary.com"
- s.homepage = "http://github.com/brynary/arel"
- s.summary = "Arel is a relational algebra engine for Ruby"
- s.description = <<-EOS.strip
-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.
- EOS
- s.rubyforge_project = "arel"
+ s.name = %q{arel}
+ s.version = "1.0.1.beta.1.20100924164427"
- s.files = Dir['lib/**/*']
- s.test_files = Dir['spec/**/*.rb'] - Dir['spec/support/fixtures/**/*.rb']
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Aaron Patterson", "Bryan Halmkamp", "Emilio Tagua", "Nick Kallen"]
+ s.date = %q{2010-09-24}
+ s.description = %q{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.}
+ s.email = ["aaron@tenderlovemaking.com", "bryan@brynary.com", "miloops@gmail.com", "nick@example.org"]
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.markdown"]
+ s.files = ["History.txt", "Manifest.txt", "README.markdown", "Rakefile", "arel.gemspec", "lib/arel.rb", "lib/arel/attributes.rb", "lib/arel/attributes/attribute.rb", "lib/arel/compatibility/wheres.rb", "lib/arel/crud.rb", "lib/arel/delete_manager.rb", "lib/arel/deprecated.rb", "lib/arel/expression.rb", "lib/arel/expressions.rb", "lib/arel/insert_manager.rb", "lib/arel/nodes.rb", "lib/arel/nodes/and.rb", "lib/arel/nodes/assignment.rb", "lib/arel/nodes/avg.rb", "lib/arel/nodes/between.rb", "lib/arel/nodes/binary.rb", "lib/arel/nodes/count.rb", "lib/arel/nodes/delete_statement.rb", "lib/arel/nodes/equality.rb", "lib/arel/nodes/exists.rb", "lib/arel/nodes/function.rb", "lib/arel/nodes/greater_than.rb", "lib/arel/nodes/greater_than_or_equal.rb", "lib/arel/nodes/group.rb", "lib/arel/nodes/grouping.rb", "lib/arel/nodes/having.rb", "lib/arel/nodes/in.rb", "lib/arel/nodes/inner_join.rb", "lib/arel/nodes/insert_statement.rb", "lib/arel/nodes/join.rb", "lib/arel/nodes/less_than.rb", "lib/arel/nodes/less_than_or_equal.rb", "lib/arel/nodes/lock.rb", "lib/arel/nodes/max.rb", "lib/arel/nodes/min.rb", "lib/arel/nodes/node.rb", "lib/arel/nodes/not_equal.rb", "lib/arel/nodes/offset.rb", "lib/arel/nodes/on.rb", "lib/arel/nodes/or.rb", "lib/arel/nodes/outer_join.rb", "lib/arel/nodes/select_core.rb", "lib/arel/nodes/select_statement.rb", "lib/arel/nodes/sql_literal.rb", "lib/arel/nodes/string_join.rb", "lib/arel/nodes/sum.rb", "lib/arel/nodes/table_alias.rb", "lib/arel/nodes/unqualified_column.rb", "lib/arel/nodes/update_statement.rb", "lib/arel/nodes/values.rb", "lib/arel/relation.rb", "lib/arel/select_manager.rb", "lib/arel/sql/engine.rb", "lib/arel/sql_literal.rb", "lib/arel/table.rb", "lib/arel/tree_manager.rb", "lib/arel/update_manager.rb", "lib/arel/version.rb", "lib/arel/visitors.rb", "lib/arel/visitors/dot.rb", "lib/arel/visitors/join_sql.rb", "lib/arel/visitors/mysql.rb", "lib/arel/visitors/oracle.rb", "lib/arel/visitors/order_clauses.rb", "lib/arel/visitors/postgresql.rb", "lib/arel/visitors/to_sql.rb", "spec/activerecord_compat_spec.rb", "spec/attributes/attribute_spec.rb", "spec/attributes_spec.rb", "spec/crud_spec.rb", "spec/delete_manager_spec.rb", "spec/insert_manager_spec.rb", "spec/nodes/count_spec.rb", "spec/nodes/delete_statement_spec.rb", "spec/nodes/equality_spec.rb", "spec/nodes/insert_statement_spec.rb", "spec/nodes/or_spec.rb", "spec/nodes/select_core_spec.rb", "spec/nodes/select_statement_spec.rb", "spec/nodes/sql_literal_spec.rb", "spec/nodes/sum_spec.rb", "spec/nodes/update_statement_spec.rb", "spec/select_manager_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/support/check.rb", "spec/support/fake_record.rb", "spec/support/matchers.rb", "spec/support/matchers/be_like.rb", "spec/support/shared/tree_manager_shared.rb", "spec/table_spec.rb", "spec/update_manager_spec.rb", "spec/visitors/join_sql_spec.rb", "spec/visitors/oracle_spec.rb", "spec/visitors/to_sql_spec.rb"]
+ s.homepage = %q{http://github.com/rails/arel}
+ s.rdoc_options = ["--main", "README.markdown"]
+ s.require_paths = ["lib"]
+ s.rubyforge_project = %q{arel}
+ s.rubygems_version = %q{1.3.7}
+ s.summary = %q{Arel is a Relational Algebra for Ruby}
- s.has_rdoc = true
- s.extra_rdoc_files = %w[History.txt README.markdown]
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_development_dependency(%q<rubyforge>, [">= 2.0.4"])
+ s.add_development_dependency(%q<hoe>, [">= 2.6.0"])
+ else
+ s.add_dependency(%q<rubyforge>, [">= 2.0.4"])
+ s.add_dependency(%q<hoe>, [">= 2.6.0"])
+ end
+ else
+ s.add_dependency(%q<rubyforge>, [">= 2.0.4"])
+ s.add_dependency(%q<hoe>, [">= 2.6.0"])
+ end
end
diff --git a/doc/CONVENTIONS b/doc/CONVENTIONS
deleted file mode 100644
index c415a527e1..0000000000
--- a/doc/CONVENTIONS
+++ /dev/null
@@ -1,17 +0,0 @@
-This file should ultimately be replaced by a series of tests, something like a lint tool.
-
-- all describes and its should use single quotes unless they have nested quotes.
-- object instantiation in tests for all objects that are not the SUT should be manufactured in a before
-- 'should' and other counterfactuals/subjunctive forms should not be used in tests
-- no doubles should be used except for behaviorist testing
- - behaviorist testing is desirable only when interacting with the database or the session
-- when unit testing, always demonstrate behavior by using a real world example (as in, a public use of the API), so as to provide documentation.
-- use collect rather than map
-- jargon:
- - 'obtains' is preferred to 'returns true'
- - 'manufactures'
-- in tests
- - when manufacturing expected values (right-hand-side of should), avoid convenience methods -- construct it by initializing the object directly (Foo.new(...)). This ensures equality expectations in tests are rigorous.
- - the SUT should be manufactured inline inside the test, not in a before
- - dependencies for the SUT should be manufactured using convenience methods (or whatever is most terse).
-- group conceptually related methods in a class within an inline module; immediately include that module. \ No newline at end of file
diff --git a/doc/TODO b/doc/TODO
deleted file mode 100644
index 61ff24f4a0..0000000000
--- a/doc/TODO
+++ /dev/null
@@ -1,118 +0,0 @@
-todo:
-- 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
-- audit unit coverage of algebra
-- data objects
-- remove all explicit aliasing
-- scoped writes
-- refactor adapter pattern
-- break out adapters into sep modules
-- projection is by definition distincting?
-- union/intersection
-- cache expiry on write
-- transactions
-
-done:
-- and/or w/ predicates
-. Relation <=> Relation -> InnerJoinOperation
-. Relation << Relation -> LeftOuterJoinOperation
-. InnerJoinOperation.on(*Predicate) -> InnerJoinRelation
-. LeftOuterJoinOperation.on(*Predicate) -> LeftOuterJoinRelation
-. Relation[Symbol] -> Attribute
-. Relation[Range] -> Relation
-. Attribute == Attribute -> EqualityPredicate
-. Attribute >= Attribute -> GreaterThanOrEqualToPredicate
-. Relation.include?(Column) -> Predicate
-. Relation.project(*Column) -> ProjectRelation
-. Relation.select(*Predicate) -> SelectionRelation
-. Relation.order(*Column) -> OrderRelation
-. #to_sql
-. Remove Builder
-. Namespace
-. Audit SqlAlchemy for missing features
-- Generalized denormalizations on any aggregation (count, yes, but also max, min, average)
-- Remove operator overloading of << and <=> for joins. Make it just foo.join(bar) and foo.outer_join(bar).
-- Remove operator overloading of == for predicates. make it a.eq(b) (note lack of question mark).
-- hookup more predicates (=, <=, =>)
-- get some basic aggregations working: users.project(user[:points].max)
-- Alias Table Names
-- When joining with any sort of aggregation, it needs to be a nested select
-- get a value select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count))
-- Session
-- sublimate values to deal with the fact that they must be quoted per engine
-- clean-up singleton monstrosity
-- extract hashing module
-- hash custom matcher
-- make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what
- - session just calls execute, passing in a connection; by default it gets a connection from the relation.
-- #formatter is now on value, attribute and relation; you must admit it's name is confusing given that e.g., relation already has a formatter (Sql::Relation) ... should it be called predicate formatter? operand1.to_sql(operand2.predicate) maybe prefer operand1.cast(operand2) or project or in light of
- - renamed to #format: operand1.format(operand2)
-- rename sql strategies
-- need to_sql for ranges
- - {:conditions=>{:id=>2..3}}
-- nested orderings
-- string passthrough
- - conditions
- - orderings
-- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute
- - descend on array, along with bind written in terms of it
-- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods?
-- string passthrough:
- :joins=>"INNER JOIN posts ON comments.post_id = posts.id"
-- finish pending tests
-- test relation, table reset
-- 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
-- Explicitly model recursive structural decomposition / polymorphism
-- Explicitly model the namer/externalizer using interpreter jargon
-- All Sql Strategies should be accumulations with the top-level relation?
-- instance methodify externalize
-- 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!!
-- 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
-- reorganize sql tests
-- recursive memory operations
-- reorganize memory tests
-- result sets to attr correlation too
-- implement joins in memory
-- 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?
-- try to make aggegration testing in join spec to be a bit more unit-like
-- standardize quoting
- - use strings everywhere, not symbols ?
-- "unit" test sql strategies
- - use real world examples, so they should be like a tutorial.
-- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent
-- consider this code from has_many:
- # replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
- @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