squeel 0.5.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 +4 -0
- data/Gemfile +8 -0
- data/LICENSE +20 -0
- data/README.rdoc +41 -0
- data/Rakefile +19 -0
- data/lib/core_ext/hash.rb +13 -0
- data/lib/core_ext/symbol.rb +36 -0
- data/lib/squeel.rb +26 -0
- data/lib/squeel/adapters/active_record.rb +6 -0
- data/lib/squeel/adapters/active_record/join_association.rb +90 -0
- data/lib/squeel/adapters/active_record/join_dependency.rb +68 -0
- data/lib/squeel/adapters/active_record/relation.rb +292 -0
- data/lib/squeel/configuration.rb +25 -0
- data/lib/squeel/constants.rb +23 -0
- data/lib/squeel/contexts/join_dependency_context.rb +74 -0
- data/lib/squeel/dsl.rb +31 -0
- data/lib/squeel/nodes.rb +10 -0
- data/lib/squeel/nodes/and.rb +8 -0
- data/lib/squeel/nodes/binary.rb +23 -0
- data/lib/squeel/nodes/function.rb +84 -0
- data/lib/squeel/nodes/join.rb +51 -0
- data/lib/squeel/nodes/key_path.rb +127 -0
- data/lib/squeel/nodes/nary.rb +35 -0
- data/lib/squeel/nodes/not.rb +8 -0
- data/lib/squeel/nodes/operation.rb +23 -0
- data/lib/squeel/nodes/operators.rb +27 -0
- data/lib/squeel/nodes/or.rb +8 -0
- data/lib/squeel/nodes/order.rb +35 -0
- data/lib/squeel/nodes/predicate.rb +49 -0
- data/lib/squeel/nodes/predicate_operators.rb +17 -0
- data/lib/squeel/nodes/stub.rb +113 -0
- data/lib/squeel/nodes/unary.rb +22 -0
- data/lib/squeel/predicate_methods.rb +22 -0
- data/lib/squeel/predicate_methods/function.rb +9 -0
- data/lib/squeel/predicate_methods/predicate.rb +11 -0
- data/lib/squeel/predicate_methods/stub.rb +9 -0
- data/lib/squeel/predicate_methods/symbol.rb +9 -0
- data/lib/squeel/version.rb +3 -0
- data/lib/squeel/visitors.rb +3 -0
- data/lib/squeel/visitors/base.rb +46 -0
- data/lib/squeel/visitors/order_visitor.rb +107 -0
- data/lib/squeel/visitors/predicate_visitor.rb +179 -0
- data/lib/squeel/visitors/select_visitor.rb +103 -0
- data/spec/blueprints/articles.rb +5 -0
- data/spec/blueprints/comments.rb +5 -0
- data/spec/blueprints/notes.rb +3 -0
- data/spec/blueprints/people.rb +4 -0
- data/spec/blueprints/tags.rb +3 -0
- data/spec/console.rb +22 -0
- data/spec/core_ext/symbol_spec.rb +68 -0
- data/spec/helpers/squeel_helper.rb +5 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/squeel/adapters/active_record/join_association_spec.rb +18 -0
- data/spec/squeel/adapters/active_record/join_depdendency_spec.rb +60 -0
- data/spec/squeel/adapters/active_record/relation_spec.rb +437 -0
- data/spec/squeel/contexts/join_dependency_context_spec.rb +43 -0
- data/spec/squeel/dsl_spec.rb +73 -0
- data/spec/squeel/nodes/function_spec.rb +149 -0
- data/spec/squeel/nodes/join_spec.rb +27 -0
- data/spec/squeel/nodes/key_path_spec.rb +92 -0
- data/spec/squeel/nodes/operation_spec.rb +149 -0
- data/spec/squeel/nodes/operators_spec.rb +87 -0
- data/spec/squeel/nodes/order_spec.rb +30 -0
- data/spec/squeel/nodes/predicate_operators_spec.rb +88 -0
- data/spec/squeel/nodes/predicate_spec.rb +92 -0
- data/spec/squeel/nodes/stub_spec.rb +178 -0
- data/spec/squeel/visitors/order_visitor_spec.rb +128 -0
- data/spec/squeel/visitors/predicate_visitor_spec.rb +267 -0
- data/spec/squeel/visitors/select_visitor_spec.rb +115 -0
- data/spec/support/schema.rb +101 -0
- data/squeel.gemspec +44 -0
- metadata +221 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module Squeel
|
2
|
+
module Nodes
|
3
|
+
class Nary
|
4
|
+
include PredicateOperators
|
5
|
+
|
6
|
+
attr_reader :children
|
7
|
+
|
8
|
+
def initialize(children)
|
9
|
+
raise ArgumentError, '#{self.class} requires an array' unless Array === children
|
10
|
+
# We don't dup here, as incoming arrays should be created by the
|
11
|
+
# Operators#& method on other nodes. If you're creating And nodes
|
12
|
+
# manually, by sure that they're new arays.
|
13
|
+
@children = children
|
14
|
+
end
|
15
|
+
|
16
|
+
def &(other)
|
17
|
+
@children << other
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def -(other)
|
22
|
+
@children << Not.new(other)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def eql?(other)
|
27
|
+
self.class == other.class &&
|
28
|
+
self.children == other.children
|
29
|
+
end
|
30
|
+
|
31
|
+
alias :== :eql?
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'squeel/nodes/function'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Nodes
|
5
|
+
class Operation < Function
|
6
|
+
|
7
|
+
def initialize(left, operator, right)
|
8
|
+
super(operator, [left, right])
|
9
|
+
end
|
10
|
+
|
11
|
+
alias :operator :name
|
12
|
+
|
13
|
+
def left
|
14
|
+
args[0]
|
15
|
+
end
|
16
|
+
|
17
|
+
def right
|
18
|
+
args[1]
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Squeel
|
2
|
+
module Nodes
|
3
|
+
module Operators
|
4
|
+
|
5
|
+
def +(value)
|
6
|
+
Operation.new(self, :+, value)
|
7
|
+
end
|
8
|
+
|
9
|
+
def -(value)
|
10
|
+
Operation.new(self, :-, value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def *(value)
|
14
|
+
Operation.new(self, :*, value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def /(value)
|
18
|
+
Operation.new(self, :/, value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def op(operator, value)
|
22
|
+
Operation.new(self, operator, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Squeel
|
2
|
+
module Nodes
|
3
|
+
class Order
|
4
|
+
attr_reader :expr, :direction
|
5
|
+
|
6
|
+
def initialize(expr, direction = 1)
|
7
|
+
raise ArgumentError, "Direction #{direction} is not valid. Must be -1 or 1." unless [-1,1].include? direction
|
8
|
+
@expr, @direction = expr, direction
|
9
|
+
end
|
10
|
+
|
11
|
+
def asc
|
12
|
+
@direction = 1
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def desc
|
17
|
+
@direction = -1
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def ascending?
|
22
|
+
@direction == 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def descending?
|
26
|
+
@direction == -1
|
27
|
+
end
|
28
|
+
|
29
|
+
def reverse!
|
30
|
+
@direction = - @direction
|
31
|
+
self
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'squeel/predicate_methods'
|
2
|
+
require 'squeel/nodes/predicate_operators'
|
3
|
+
|
4
|
+
module Squeel
|
5
|
+
module Nodes
|
6
|
+
class Predicate
|
7
|
+
|
8
|
+
include PredicateMethods
|
9
|
+
include PredicateOperators
|
10
|
+
|
11
|
+
attr_accessor :value
|
12
|
+
attr_reader :expr, :method_name
|
13
|
+
|
14
|
+
def initialize(expr, method_name = :eq, value = :__undefined__)
|
15
|
+
@expr, @method_name, @value = expr, method_name, value
|
16
|
+
end
|
17
|
+
|
18
|
+
def eql?(other)
|
19
|
+
self.class.eql?(other.class) &&
|
20
|
+
self.expr.eql?(other.expr) &&
|
21
|
+
self.method_name.eql?(other.method_name) &&
|
22
|
+
self.value.eql?(other.value)
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :== :eql?
|
26
|
+
|
27
|
+
def hash
|
28
|
+
[self.class, expr, method_name, value].hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def value?
|
32
|
+
@value != :__undefined__
|
33
|
+
end
|
34
|
+
|
35
|
+
def %(val)
|
36
|
+
@value = val
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
# expand_hash_conditions_for_aggregates assumes our hash keys can be
|
41
|
+
# converted to symbols, so this has to be implemented, but it doesn't
|
42
|
+
# really have to do anything useful.
|
43
|
+
def to_sym
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'squeel/predicate_methods'
|
2
|
+
require 'squeel/nodes/operators'
|
3
|
+
|
4
|
+
module Squeel
|
5
|
+
module Nodes
|
6
|
+
class Stub
|
7
|
+
|
8
|
+
include PredicateMethods
|
9
|
+
include Operators
|
10
|
+
|
11
|
+
attr_reader :symbol
|
12
|
+
|
13
|
+
def initialize(symbol)
|
14
|
+
@symbol = symbol
|
15
|
+
end
|
16
|
+
|
17
|
+
def eql?(other)
|
18
|
+
self.class == other.class &&
|
19
|
+
self.symbol == other.symbol
|
20
|
+
end
|
21
|
+
|
22
|
+
def hash
|
23
|
+
symbol.hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_sym
|
27
|
+
symbol
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
symbol.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method_id, *args)
|
35
|
+
super if method_id == :to_ary
|
36
|
+
KeyPath.new(self.symbol, method_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ==(value)
|
40
|
+
Predicate.new self.symbol, :eq, value
|
41
|
+
end
|
42
|
+
|
43
|
+
# Won't work on Ruby 1.8.x so need to do this conditionally
|
44
|
+
define_method('!=') do |value|
|
45
|
+
Predicate.new(self.symbol, :not_eq, value)
|
46
|
+
end if respond_to?('!=')
|
47
|
+
|
48
|
+
def ^(value)
|
49
|
+
Predicate.new self.symbol, :not_eq, value
|
50
|
+
end
|
51
|
+
|
52
|
+
def >>(value)
|
53
|
+
Predicate.new self.symbol, :in, value
|
54
|
+
end
|
55
|
+
|
56
|
+
def <<(value)
|
57
|
+
Predicate.new self.symbol, :not_in, value
|
58
|
+
end
|
59
|
+
|
60
|
+
def =~(value)
|
61
|
+
Predicate.new self.symbol, :matches, value
|
62
|
+
end
|
63
|
+
|
64
|
+
# Won't work on Ruby 1.8.x so need to do this conditionally
|
65
|
+
define_method('!~') do |value|
|
66
|
+
Predicate.new(self.symbol, :does_not_match, value)
|
67
|
+
end if respond_to?('!~')
|
68
|
+
|
69
|
+
def >(value)
|
70
|
+
Predicate.new self.symbol, :gt, value
|
71
|
+
end
|
72
|
+
|
73
|
+
def >=(value)
|
74
|
+
Predicate.new self.symbol, :gteq, value
|
75
|
+
end
|
76
|
+
|
77
|
+
def <(value)
|
78
|
+
Predicate.new self.symbol, :lt, value
|
79
|
+
end
|
80
|
+
|
81
|
+
def <=(value)
|
82
|
+
Predicate.new self.symbol, :lteq, value
|
83
|
+
end
|
84
|
+
|
85
|
+
def asc
|
86
|
+
Order.new self.symbol, 1
|
87
|
+
end
|
88
|
+
|
89
|
+
def desc
|
90
|
+
Order.new self.symbol, -1
|
91
|
+
end
|
92
|
+
|
93
|
+
def func(*args)
|
94
|
+
Function.new(self.symbol, args)
|
95
|
+
end
|
96
|
+
|
97
|
+
alias :[] :func
|
98
|
+
|
99
|
+
def inner
|
100
|
+
Join.new(self.symbol, Arel::InnerJoin)
|
101
|
+
end
|
102
|
+
|
103
|
+
def outer
|
104
|
+
Join.new(self.symbol, Arel::OuterJoin)
|
105
|
+
end
|
106
|
+
|
107
|
+
def of_class(klass)
|
108
|
+
Join.new(self.symbol, Arel::InnerJoin, klass)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'squeel/nodes/predicate_operators'
|
2
|
+
|
3
|
+
module Squeel
|
4
|
+
module Nodes
|
5
|
+
class Unary
|
6
|
+
include PredicateOperators
|
7
|
+
|
8
|
+
attr_reader :expr
|
9
|
+
|
10
|
+
def initialize(expr)
|
11
|
+
@expr = expr
|
12
|
+
end
|
13
|
+
|
14
|
+
def eql?(other)
|
15
|
+
self.class == other.class &&
|
16
|
+
self.expr == other.expr
|
17
|
+
end
|
18
|
+
|
19
|
+
alias :== :eql?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'squeel/predicate_methods/symbol'
|
2
|
+
require 'squeel/predicate_methods/stub'
|
3
|
+
require 'squeel/predicate_methods/predicate'
|
4
|
+
require 'squeel/predicate_methods/function'
|
5
|
+
|
6
|
+
module Squeel
|
7
|
+
module PredicateMethods
|
8
|
+
|
9
|
+
def self.included(base)
|
10
|
+
base.send :include, const_get(base.name.split(/::/)[-1].to_sym)
|
11
|
+
end
|
12
|
+
|
13
|
+
Constants::PREDICATES.each do |method_name|
|
14
|
+
class_eval <<-RUBY
|
15
|
+
def #{method_name}(value = :__undefined__)
|
16
|
+
predicate :#{method_name}, value
|
17
|
+
end
|
18
|
+
RUBY
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'active_support/core_ext/module'
|
2
|
+
require 'squeel/nodes'
|
3
|
+
|
4
|
+
module Squeel
|
5
|
+
module Visitors
|
6
|
+
class Base
|
7
|
+
attr_accessor :context
|
8
|
+
delegate :contextualize, :find, :traverse, :sanitize_sql, :engine, :arel_visitor, :to => :context
|
9
|
+
|
10
|
+
def initialize(context = nil)
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
def accept(object, parent = context.base)
|
15
|
+
visit(object, parent)
|
16
|
+
end
|
17
|
+
|
18
|
+
def can_accept?(object)
|
19
|
+
respond_to? DISPATCH[object.class]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.can_accept?(object)
|
23
|
+
method_defined? DISPATCH[object.class]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
DISPATCH = Hash.new do |hash, klass|
|
29
|
+
hash[klass] = "visit_#{klass.name.gsub('::', '_')}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def quoted?(object)
|
33
|
+
case object
|
34
|
+
when Arel::Nodes::SqlLiteral, Bignum, Fixnum
|
35
|
+
false
|
36
|
+
else
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def visit(object, parent)
|
42
|
+
send(DISPATCH[object.class], object, parent)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|