arel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/README.markdown +184 -0
- data/Rakefile +60 -0
- data/VERSION +1 -0
- data/arel.gemspec +233 -0
- data/doc/CONVENTIONS +17 -0
- data/doc/TODO +118 -0
- data/lib/arel.rb +10 -0
- data/lib/arel/algebra.rb +4 -0
- data/lib/arel/algebra/extensions.rb +4 -0
- data/lib/arel/algebra/extensions/class.rb +32 -0
- data/lib/arel/algebra/extensions/hash.rb +11 -0
- data/lib/arel/algebra/extensions/object.rb +17 -0
- data/lib/arel/algebra/extensions/symbol.rb +9 -0
- data/lib/arel/algebra/predicates.rb +41 -0
- data/lib/arel/algebra/primitives.rb +5 -0
- data/lib/arel/algebra/primitives/attribute.rb +150 -0
- data/lib/arel/algebra/primitives/expression.rb +43 -0
- data/lib/arel/algebra/primitives/ordering.rb +23 -0
- data/lib/arel/algebra/primitives/value.rb +14 -0
- data/lib/arel/algebra/relations.rb +14 -0
- data/lib/arel/algebra/relations/operations/alias.rb +7 -0
- data/lib/arel/algebra/relations/operations/group.rb +12 -0
- data/lib/arel/algebra/relations/operations/join.rb +64 -0
- data/lib/arel/algebra/relations/operations/order.rb +18 -0
- data/lib/arel/algebra/relations/operations/project.rb +20 -0
- data/lib/arel/algebra/relations/operations/skip.rb +6 -0
- data/lib/arel/algebra/relations/operations/take.rb +10 -0
- data/lib/arel/algebra/relations/operations/where.rb +16 -0
- data/lib/arel/algebra/relations/relation.rb +136 -0
- data/lib/arel/algebra/relations/row.rb +26 -0
- data/lib/arel/algebra/relations/utilities/compound.rb +30 -0
- data/lib/arel/algebra/relations/utilities/externalization.rb +24 -0
- data/lib/arel/algebra/relations/utilities/nil.rb +7 -0
- data/lib/arel/algebra/relations/writes.rb +36 -0
- data/lib/arel/engines.rb +2 -0
- data/lib/arel/engines/memory.rb +4 -0
- data/lib/arel/engines/memory/engine.rb +16 -0
- data/lib/arel/engines/memory/predicates.rb +35 -0
- data/lib/arel/engines/memory/primitives.rb +27 -0
- data/lib/arel/engines/memory/relations.rb +5 -0
- data/lib/arel/engines/memory/relations/array.rb +25 -0
- data/lib/arel/engines/memory/relations/compound.rb +9 -0
- data/lib/arel/engines/memory/relations/operations.rb +61 -0
- data/lib/arel/engines/memory/relations/writes.rb +7 -0
- data/lib/arel/engines/sql.rb +7 -0
- data/lib/arel/engines/sql/christener.rb +13 -0
- data/lib/arel/engines/sql/engine.rb +37 -0
- data/lib/arel/engines/sql/extensions.rb +4 -0
- data/lib/arel/engines/sql/extensions/array.rb +16 -0
- data/lib/arel/engines/sql/extensions/nil_class.rb +11 -0
- data/lib/arel/engines/sql/extensions/object.rb +15 -0
- data/lib/arel/engines/sql/extensions/range.rb +15 -0
- data/lib/arel/engines/sql/formatters.rb +113 -0
- data/lib/arel/engines/sql/predicates.rb +51 -0
- data/lib/arel/engines/sql/primitives.rb +85 -0
- data/lib/arel/engines/sql/relations.rb +9 -0
- data/lib/arel/engines/sql/relations/operations/alias.rb +5 -0
- data/lib/arel/engines/sql/relations/operations/join.rb +33 -0
- data/lib/arel/engines/sql/relations/relation.rb +50 -0
- data/lib/arel/engines/sql/relations/table.rb +52 -0
- data/lib/arel/engines/sql/relations/utilities/compound.rb +10 -0
- data/lib/arel/engines/sql/relations/utilities/externalization.rb +14 -0
- data/lib/arel/engines/sql/relations/utilities/nil.rb +6 -0
- data/lib/arel/engines/sql/relations/utilities/recursion.rb +13 -0
- data/lib/arel/engines/sql/relations/writes.rb +39 -0
- data/lib/arel/session.rb +48 -0
- data/spec/arel/algebra/unit/predicates/binary_spec.rb +33 -0
- data/spec/arel/algebra/unit/predicates/equality_spec.rb +27 -0
- data/spec/arel/algebra/unit/predicates/in_spec.rb +10 -0
- data/spec/arel/algebra/unit/primitives/attribute_spec.rb +183 -0
- data/spec/arel/algebra/unit/primitives/expression_spec.rb +45 -0
- data/spec/arel/algebra/unit/primitives/value_spec.rb +15 -0
- data/spec/arel/algebra/unit/relations/alias_spec.rb +16 -0
- data/spec/arel/algebra/unit/relations/delete_spec.rb +9 -0
- data/spec/arel/algebra/unit/relations/group_spec.rb +10 -0
- data/spec/arel/algebra/unit/relations/insert_spec.rb +9 -0
- data/spec/arel/algebra/unit/relations/join_spec.rb +26 -0
- data/spec/arel/algebra/unit/relations/order_spec.rb +21 -0
- data/spec/arel/algebra/unit/relations/project_spec.rb +34 -0
- data/spec/arel/algebra/unit/relations/relation_spec.rb +188 -0
- data/spec/arel/algebra/unit/relations/skip_spec.rb +10 -0
- data/spec/arel/algebra/unit/relations/table_spec.rb +39 -0
- data/spec/arel/algebra/unit/relations/take_spec.rb +10 -0
- data/spec/arel/algebra/unit/relations/update_spec.rb +9 -0
- data/spec/arel/algebra/unit/relations/where_spec.rb +18 -0
- data/spec/arel/algebra/unit/session/session_spec.rb +84 -0
- data/spec/arel/engines/memory/integration/joins/cross_engine_spec.rb +48 -0
- data/spec/arel/engines/memory/unit/relations/array_spec.rb +32 -0
- data/spec/arel/engines/memory/unit/relations/insert_spec.rb +28 -0
- data/spec/arel/engines/memory/unit/relations/join_spec.rb +31 -0
- data/spec/arel/engines/memory/unit/relations/order_spec.rb +27 -0
- data/spec/arel/engines/memory/unit/relations/project_spec.rb +27 -0
- data/spec/arel/engines/memory/unit/relations/skip_spec.rb +26 -0
- data/spec/arel/engines/memory/unit/relations/take_spec.rb +26 -0
- data/spec/arel/engines/memory/unit/relations/where_spec.rb +39 -0
- data/spec/arel/engines/sql/integration/joins/with_adjacency_spec.rb +209 -0
- data/spec/arel/engines/sql/integration/joins/with_aggregations_spec.rb +167 -0
- data/spec/arel/engines/sql/integration/joins/with_compounds_spec.rb +107 -0
- data/spec/arel/engines/sql/unit/engine_spec.rb +45 -0
- data/spec/arel/engines/sql/unit/predicates/binary_spec.rb +117 -0
- data/spec/arel/engines/sql/unit/predicates/equality_spec.rb +46 -0
- data/spec/arel/engines/sql/unit/predicates/in_spec.rb +86 -0
- data/spec/arel/engines/sql/unit/predicates/predicates_spec.rb +65 -0
- data/spec/arel/engines/sql/unit/primitives/attribute_spec.rb +32 -0
- data/spec/arel/engines/sql/unit/primitives/expression_spec.rb +24 -0
- data/spec/arel/engines/sql/unit/primitives/literal_spec.rb +23 -0
- data/spec/arel/engines/sql/unit/primitives/value_spec.rb +29 -0
- data/spec/arel/engines/sql/unit/relations/alias_spec.rb +43 -0
- data/spec/arel/engines/sql/unit/relations/delete_spec.rb +63 -0
- data/spec/arel/engines/sql/unit/relations/group_spec.rb +56 -0
- data/spec/arel/engines/sql/unit/relations/insert_spec.rb +107 -0
- data/spec/arel/engines/sql/unit/relations/join_spec.rb +57 -0
- data/spec/arel/engines/sql/unit/relations/order_spec.rb +113 -0
- data/spec/arel/engines/sql/unit/relations/project_spec.rb +110 -0
- data/spec/arel/engines/sql/unit/relations/skip_spec.rb +32 -0
- data/spec/arel/engines/sql/unit/relations/table_spec.rb +69 -0
- data/spec/arel/engines/sql/unit/relations/take_spec.rb +32 -0
- data/spec/arel/engines/sql/unit/relations/update_spec.rb +151 -0
- data/spec/arel/engines/sql/unit/relations/where_spec.rb +56 -0
- data/spec/connections/mysql_connection.rb +16 -0
- data/spec/connections/postgresql_connection.rb +15 -0
- data/spec/connections/sqlite3_connection.rb +25 -0
- data/spec/doubles/hash.rb +23 -0
- data/spec/matchers/be_like.rb +24 -0
- data/spec/matchers/disambiguate_attributes.rb +28 -0
- data/spec/matchers/hash_the_same_as.rb +26 -0
- data/spec/schemas/mysql_schema.rb +18 -0
- data/spec/schemas/postgresql_schema.rb +18 -0
- data/spec/schemas/sqlite3_schema.rb +18 -0
- data/spec/spec_helper.rb +47 -0
- metadata +250 -0
data/doc/CONVENTIONS
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
This file should ultimately be replaced by a series of tests, something like a lint tool.
|
2
|
+
|
3
|
+
- all describes and its should use single quotes unless they have nested quotes.
|
4
|
+
- object instantiation in tests for all objects that are not the SUT should be manufactured in a before
|
5
|
+
- 'should' and other counterfactuals/subjunctive forms should not be used in tests
|
6
|
+
- no doubles should be used except for behaviorist testing
|
7
|
+
- behaviorist testing is desirable only when interacting with the database or the session
|
8
|
+
- 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.
|
9
|
+
- use collect rather than map
|
10
|
+
- jargon:
|
11
|
+
- 'obtains' is preferred to 'returns true'
|
12
|
+
- 'manufactures'
|
13
|
+
- in tests
|
14
|
+
- 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.
|
15
|
+
- the SUT should be manufactured inline inside the test, not in a before
|
16
|
+
- dependencies for the SUT should be manufactured using convenience methods (or whatever is most terse).
|
17
|
+
- group conceptually related methods in a class within an inline module; immediately include that module.
|
data/doc/TODO
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
todo:
|
2
|
+
- fix AR again
|
3
|
+
- blocks for joins
|
4
|
+
- fix sql insertions
|
5
|
+
- implement mnesia adapter
|
6
|
+
|
7
|
+
- CLEANUP!!!!!
|
8
|
+
- rename externalize to derived.
|
9
|
+
- deal with table tests in algebra
|
10
|
+
- fix grouping
|
11
|
+
- audit unit coverage of algebra
|
12
|
+
- data objects
|
13
|
+
- remove all explicit aliasing
|
14
|
+
- scoped writes
|
15
|
+
- refactor adapter pattern
|
16
|
+
- break out adapters into sep modules
|
17
|
+
- projection is by definition distincting?
|
18
|
+
- union/intersection
|
19
|
+
- cache expiry on write
|
20
|
+
- transactions
|
21
|
+
|
22
|
+
done:
|
23
|
+
- and/or w/ predicates
|
24
|
+
. Relation <=> Relation -> InnerJoinOperation
|
25
|
+
. Relation << Relation -> LeftOuterJoinOperation
|
26
|
+
. InnerJoinOperation.on(*Predicate) -> InnerJoinRelation
|
27
|
+
. LeftOuterJoinOperation.on(*Predicate) -> LeftOuterJoinRelation
|
28
|
+
. Relation[Symbol] -> Attribute
|
29
|
+
. Relation[Range] -> Relation
|
30
|
+
. Attribute == Attribute -> EqualityPredicate
|
31
|
+
. Attribute >= Attribute -> GreaterThanOrEqualToPredicate
|
32
|
+
. Relation.include?(Column) -> Predicate
|
33
|
+
. Relation.project(*Column) -> ProjectRelation
|
34
|
+
. Relation.select(*Predicate) -> SelectionRelation
|
35
|
+
. Relation.order(*Column) -> OrderRelation
|
36
|
+
. #to_sql
|
37
|
+
. Remove Builder
|
38
|
+
. Namespace
|
39
|
+
. Audit SqlAlchemy for missing features
|
40
|
+
- Generalized denormalizations on any aggregation (count, yes, but also max, min, average)
|
41
|
+
- Remove operator overloading of << and <=> for joins. Make it just foo.join(bar) and foo.outer_join(bar).
|
42
|
+
- Remove operator overloading of == for predicates. make it a.eq(b) (note lack of question mark).
|
43
|
+
- hookup more predicates (=, <=, =>)
|
44
|
+
- get some basic aggregations working: users.project(user[:points].max)
|
45
|
+
- Alias Table Names
|
46
|
+
- When joining with any sort of aggregation, it needs to be a nested select
|
47
|
+
- get a value select working: users.project(users[:name], addresses.select(addresses[:user_id] == users[:id]).project(addresses[:id].count))
|
48
|
+
- Session
|
49
|
+
- sublimate values to deal with the fact that they must be quoted per engine
|
50
|
+
- clean-up singleton monstrosity
|
51
|
+
- extract hashing module
|
52
|
+
- hash custom matcher
|
53
|
+
- make session engine stuff follow laws of demeter - currently doing some odd method chaining? rethink who is responsible for what
|
54
|
+
- session just calls execute, passing in a connection; by default it gets a connection from the relation.
|
55
|
+
- #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
|
56
|
+
- renamed to #format: operand1.format(operand2)
|
57
|
+
- rename sql strategies
|
58
|
+
- need to_sql for ranges
|
59
|
+
- {:conditions=>{:id=>2..3}}
|
60
|
+
- nested orderings
|
61
|
+
- string passthrough
|
62
|
+
- conditions
|
63
|
+
- orderings
|
64
|
+
- relation inclusion when given an array (1,2,3,4) should quote the elements using the appropriate quoting formatter taken from the attribute
|
65
|
+
- descend on array, along with bind written in terms of it
|
66
|
+
- re-evaluate bind -- does bind belong inside the relation / predicate classes or in the factory methods?
|
67
|
+
- string passthrough:
|
68
|
+
:joins=>"INNER JOIN posts ON comments.post_id = posts.id"
|
69
|
+
- finish pending tests
|
70
|
+
- test relation, table reset
|
71
|
+
- test Value, in particular bind.
|
72
|
+
- test blank checks in relation.rb
|
73
|
+
- rename active_relation to arel
|
74
|
+
- mock out database
|
75
|
+
- fix complex joining cases:
|
76
|
+
- active record query adapter
|
77
|
+
- anonymous table names
|
78
|
+
- Explicitly model recursive structural decomposition / polymorphism
|
79
|
+
- Explicitly model the namer/externalizer using interpreter jargon
|
80
|
+
- All Sql Strategies should be accumulations with the top-level relation?
|
81
|
+
- instance methodify externalize
|
82
|
+
- test: find_attribute_given_attribute and all @attribute ||= everywhere and memoization of table class.
|
83
|
+
- rename select to where
|
84
|
+
- rename all ion classes
|
85
|
+
- joining with LIMIT is like aggregations!!
|
86
|
+
- blocks for non-joins
|
87
|
+
- expressions should be class-based, and joins too, anything _sql should be renamed
|
88
|
+
- implement in memory adapter
|
89
|
+
- clean up block_given stuff
|
90
|
+
- reorganize sql tests
|
91
|
+
- recursive memory operations
|
92
|
+
- reorganize memory tests
|
93
|
+
- result sets to attr correlation too
|
94
|
+
- implement joins in memory
|
95
|
+
- result sets should be array relations
|
96
|
+
- fix AR
|
97
|
+
- insertions for in memory
|
98
|
+
- cross-engine joins
|
99
|
+
|
100
|
+
icebox:
|
101
|
+
- #bind in Attribute and Expression should be doing a descend?
|
102
|
+
- try to make aggegration testing in join spec to be a bit more unit-like
|
103
|
+
- standardize quoting
|
104
|
+
- use strings everywhere, not symbols ?
|
105
|
+
- "unit" test sql strategies
|
106
|
+
- use real world examples, so they should be like a tutorial.
|
107
|
+
- rename the tion (Selection) classes so that words that don't end in tion don't seem inconsistent
|
108
|
+
- consider this code from has_many:
|
109
|
+
# replace the SELECT clause with COUNT(*), preserving any hints within /* ... */
|
110
|
+
@reflection.options[:counter_sql] = @reflection.options[:finder_sql].sub(/SELECT (\/\*.*?\*\/ )?(.*)\bFROM\b/im) { "SELECT #{$1}COUNT(*) FROM" }
|
111
|
+
- lock
|
112
|
+
- SELECT suchandsuch FOR UPDATE
|
113
|
+
- joins become subselects in writes:
|
114
|
+
users.delete().where(
|
115
|
+
addresses.c.user_id==
|
116
|
+
select([users.c.id]).
|
117
|
+
where(users.c.name=='jack')
|
118
|
+
)
|
data/lib/arel.rb
ADDED
data/lib/arel/algebra.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Arel
|
2
|
+
module ClassExtensions
|
3
|
+
def attributes(*attrs)
|
4
|
+
@attributes = attrs
|
5
|
+
attr_reader *attrs
|
6
|
+
end
|
7
|
+
|
8
|
+
def deriving(*methods)
|
9
|
+
methods.each { |m| derive m }
|
10
|
+
end
|
11
|
+
|
12
|
+
def derive(method_name)
|
13
|
+
methods = {
|
14
|
+
:initialize => "
|
15
|
+
def #{method_name}(#{@attributes.join(',')})
|
16
|
+
#{@attributes.collect { |a| "@#{a} = #{a}" }.join("\n")}
|
17
|
+
end
|
18
|
+
",
|
19
|
+
:== => "
|
20
|
+
def ==(other)
|
21
|
+
#{name} === other &&
|
22
|
+
#{@attributes.collect { |a| "@#{a} == other.#{a}" }.join(" &&\n")}
|
23
|
+
end
|
24
|
+
"
|
25
|
+
}
|
26
|
+
class_eval methods[method_name], __FILE__, __LINE__
|
27
|
+
end
|
28
|
+
|
29
|
+
Class.send(:include, self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Arel
|
2
|
+
class Predicate
|
3
|
+
def or(other_predicate)
|
4
|
+
Or.new(self, other_predicate)
|
5
|
+
end
|
6
|
+
|
7
|
+
def and(other_predicate)
|
8
|
+
And.new(self, other_predicate)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Binary < Predicate
|
13
|
+
attributes :operand1, :operand2
|
14
|
+
deriving :initialize
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
self.class === other and
|
18
|
+
@operand1 == other.operand1 and
|
19
|
+
@operand2 == other.operand2
|
20
|
+
end
|
21
|
+
|
22
|
+
def bind(relation)
|
23
|
+
self.class.new(operand1.find_correlate_in(relation), operand2.find_correlate_in(relation))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Equality < Binary
|
28
|
+
def ==(other)
|
29
|
+
Equality === other and
|
30
|
+
((operand1 == other.operand1 and operand2 == other.operand2) or
|
31
|
+
(operand1 == other.operand2 and operand2 == other.operand1))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class GreaterThanOrEqualTo < Binary; end
|
36
|
+
class GreaterThan < Binary; end
|
37
|
+
class LessThanOrEqualTo < Binary; end
|
38
|
+
class LessThan < Binary; end
|
39
|
+
class Match < Binary; end
|
40
|
+
class In < Binary; end
|
41
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
class Attribute
|
5
|
+
attributes :relation, :name, :alias, :ancestor
|
6
|
+
deriving :==
|
7
|
+
delegate :engine, :christener, :to => :relation
|
8
|
+
|
9
|
+
def initialize(relation, name, options = {})
|
10
|
+
@relation, @name, @alias, @ancestor = relation, name, options[:alias], options[:ancestor]
|
11
|
+
end
|
12
|
+
|
13
|
+
def named?(hypothetical_name)
|
14
|
+
(@alias || name).to_s == hypothetical_name.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def aggregation?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspect
|
22
|
+
"<Attribute #{name}>"
|
23
|
+
end
|
24
|
+
|
25
|
+
module Transformations
|
26
|
+
def self.included(klass)
|
27
|
+
klass.send :alias_method, :eql?, :==
|
28
|
+
end
|
29
|
+
|
30
|
+
def hash
|
31
|
+
@hash ||= history.size + name.hash + relation.hash
|
32
|
+
end
|
33
|
+
|
34
|
+
def as(aliaz = nil)
|
35
|
+
Attribute.new(relation, name, :alias => aliaz, :ancestor => self)
|
36
|
+
end
|
37
|
+
|
38
|
+
def bind(new_relation)
|
39
|
+
relation == new_relation ? self : Attribute.new(new_relation, name, :alias => @alias, :ancestor => self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_attribute(relation)
|
43
|
+
bind(relation)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
include Transformations
|
47
|
+
|
48
|
+
module Congruence
|
49
|
+
def history
|
50
|
+
@history ||= [self] + (ancestor ? ancestor.history : [])
|
51
|
+
end
|
52
|
+
|
53
|
+
def join?
|
54
|
+
relation.join?
|
55
|
+
end
|
56
|
+
|
57
|
+
def root
|
58
|
+
history.last
|
59
|
+
end
|
60
|
+
|
61
|
+
def original_relation
|
62
|
+
@original_relation ||= original_attribute.relation
|
63
|
+
end
|
64
|
+
|
65
|
+
def original_attribute
|
66
|
+
@original_attribute ||= history.detect { |a| !a.join? }
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_correlate_in(relation)
|
70
|
+
relation[self] || self
|
71
|
+
end
|
72
|
+
|
73
|
+
def descends_from?(other)
|
74
|
+
history.include?(other)
|
75
|
+
end
|
76
|
+
|
77
|
+
def /(other)
|
78
|
+
other ? (history & other.history).size : 0
|
79
|
+
end
|
80
|
+
end
|
81
|
+
include Congruence
|
82
|
+
|
83
|
+
module Predications
|
84
|
+
def eq(other)
|
85
|
+
Equality.new(self, other)
|
86
|
+
end
|
87
|
+
|
88
|
+
def lt(other)
|
89
|
+
LessThan.new(self, other)
|
90
|
+
end
|
91
|
+
|
92
|
+
def lteq(other)
|
93
|
+
LessThanOrEqualTo.new(self, other)
|
94
|
+
end
|
95
|
+
|
96
|
+
def gt(other)
|
97
|
+
GreaterThan.new(self, other)
|
98
|
+
end
|
99
|
+
|
100
|
+
def gteq(other)
|
101
|
+
GreaterThanOrEqualTo.new(self, other)
|
102
|
+
end
|
103
|
+
|
104
|
+
def matches(regexp)
|
105
|
+
Match.new(self, regexp)
|
106
|
+
end
|
107
|
+
|
108
|
+
def in(array)
|
109
|
+
In.new(self, array)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
include Predications
|
113
|
+
|
114
|
+
module Expressions
|
115
|
+
def count(distinct = false)
|
116
|
+
distinct ? Distinct.new(self).count : Count.new(self)
|
117
|
+
end
|
118
|
+
|
119
|
+
def sum
|
120
|
+
Sum.new(self)
|
121
|
+
end
|
122
|
+
|
123
|
+
def maximum
|
124
|
+
Maximum.new(self)
|
125
|
+
end
|
126
|
+
|
127
|
+
def minimum
|
128
|
+
Minimum.new(self)
|
129
|
+
end
|
130
|
+
|
131
|
+
def average
|
132
|
+
Average.new(self)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
include Expressions
|
136
|
+
|
137
|
+
module Orderings
|
138
|
+
def asc
|
139
|
+
Ascending.new(self)
|
140
|
+
end
|
141
|
+
|
142
|
+
def desc
|
143
|
+
Descending.new(self)
|
144
|
+
end
|
145
|
+
|
146
|
+
alias_method :to_ordering, :asc
|
147
|
+
end
|
148
|
+
include Orderings
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Arel
|
2
|
+
class Expression < Attribute
|
3
|
+
attributes :attribute, :alias, :ancestor
|
4
|
+
deriving :==
|
5
|
+
delegate :relation, :to => :attribute
|
6
|
+
alias_method :name, :alias
|
7
|
+
|
8
|
+
def initialize(attribute, aliaz = nil, ancestor = nil)
|
9
|
+
@attribute, @alias, @ancestor = attribute, aliaz, ancestor
|
10
|
+
end
|
11
|
+
|
12
|
+
def aggregation?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
"<#{self.class.name} #{attribute.inspect}>"
|
18
|
+
end
|
19
|
+
|
20
|
+
module Transformations
|
21
|
+
def as(aliaz)
|
22
|
+
self.class.new(attribute, aliaz, self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def bind(new_relation)
|
26
|
+
new_relation == relation ? self : self.class.new(attribute.bind(new_relation), @alias, self)
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_attribute(relation)
|
30
|
+
Attribute.new(relation, @alias, :ancestor => self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
include Transformations
|
34
|
+
end
|
35
|
+
|
36
|
+
class Count < Expression; end
|
37
|
+
class Distinct < Expression; end
|
38
|
+
class Sum < Expression; end
|
39
|
+
class Maximum < Expression; end
|
40
|
+
class Minimum < Expression; end
|
41
|
+
class Average < Expression; end
|
42
|
+
end
|
43
|
+
|