johnbender-rquery 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +14 -29
- data/lib/rquery.rb +7 -13
- data/lib/rquery/active_record/base.rb +9 -20
- data/lib/rquery/adapters/sqlite.rb +1 -1
- data/lib/rquery/attribute_collection.rb +25 -3
- data/lib/rquery/operation_collector.rb +175 -0
- data/rakefile.rb +2 -1
- data/spec/active_record_base_spec_attribute_collection.rb +41 -62
- data/spec/or_and_operations_spec.rb +11 -11
- data/spec/sqlite_adapter_spec.rb +1 -1
- metadata +7 -12
- data/examples/user.rb +0 -49
- data/lib/rquery/attribute.rb +0 -14
- data/lib/rquery/declarations.rb +0 -34
- data/lib/rquery/serializers.rb +0 -184
- data/spec/active_record_base_spec_symbols.rb +0 -214
- data/spec/declarations_spec.rb +0 -23
- data/spec/serializers_spec.rb +0 -34
data/README.markdown
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
RQuery
|
2
3
|
======
|
3
4
|
|
@@ -8,35 +9,25 @@ Currently only the ActiveRecord extension is implemented with a Sqlite adapter.
|
|
8
9
|
ActiveRecord
|
9
10
|
------------
|
10
11
|
|
11
|
-
###Setup/Config
|
12
|
+
###Setup/Config
|
12
13
|
|
13
14
|
In you're rails environment file simply require rquery. The default adapter is the included Sqlite adapter but you can created and set your own with
|
14
15
|
|
15
|
-
RQuery.adapter = class
|
16
|
+
RQuery::Config.adapter = class
|
16
17
|
|
17
18
|
You can view both Sql and Sqlite in the adapters directory if you are interested in writing your own (mysql?). As a side note it would be nice at some point to decide the adapter based on the db chosen for a given environment.
|
18
19
|
|
19
|
-
Also, you can choose to use symbols as the attribute names in the block or you can use an option block argument to represent an ActiveRecord object. To use the symbols make sure to add the following to your environment.rb
|
20
|
-
|
21
|
-
RQuery.use_symbols
|
22
|
-
|
23
|
-
Using the block parameter instead has two benefits. 1: you won't be poluting the Symbol objects with my hackery, and 2: RQuery will tell you when you are attempting use an attribute for the object that doesn't exist. Examples of both below.
|
24
|
-
|
25
20
|
###Examples
|
26
21
|
|
27
22
|
RQuery extend ActiveRecord to provide the `where` method. `where` accepts a single optional argument and a block that represents the query statements
|
28
23
|
|
29
24
|
In a given UsersController your `show` action might find the User like so:
|
30
25
|
|
31
|
-
@user = User.find(params[:
|
26
|
+
@user = User.find(params[:age])
|
32
27
|
|
33
28
|
Using RQuery:
|
34
29
|
|
35
|
-
@user = User.where {
|
36
|
-
|
37
|
-
Or
|
38
|
-
|
39
|
-
@user = User.where { |user| user.id.is == params[:id] }
|
30
|
+
@user = User.where { |user| user.age == params[:age] }
|
40
31
|
|
41
32
|
In the above case, RQuery doesn't provide much of an improvement over the traditional `find` method, but as the query becomes more complex its expressiveness begins to shine through:
|
42
33
|
|
@@ -44,12 +35,6 @@ In the above case, RQuery doesn't provide much of an improvement over the tradit
|
|
44
35
|
|
45
36
|
RQuery:
|
46
37
|
|
47
|
-
@users = User.where do
|
48
|
-
:age.from 10..20
|
49
|
-
end
|
50
|
-
|
51
|
-
Or:
|
52
|
-
|
53
38
|
@users = User.where do |user|
|
54
39
|
user.age.between 10..20
|
55
40
|
end
|
@@ -58,28 +43,28 @@ Both the `from` and `between` methods accept argument lists `10,20` or an array
|
|
58
43
|
|
59
44
|
###Other Examples
|
60
45
|
|
61
|
-
RQuery supports most of the common SQL operations: =, <>, >, <, >=, <= as well as in, like (see below for specifics), and between.
|
46
|
+
RQuery supports most of the common SQL operations: =, <>, >, <, >=, <= as well as in, like (see below for specifics), and between. `obj.foo.not_<operation>` works for `.in` and `.between` with the negation of == being `obj.foo.not = ` and the negation of `obj.foo.contains` as `obj.foo.without`.
|
62
47
|
|
63
48
|
Operators:
|
64
49
|
|
65
50
|
@obj = ActiveRecordObject.where do |obj|
|
66
|
-
obj.foo
|
67
|
-
obj.foo.
|
51
|
+
obj.foo > 2
|
52
|
+
obj.foo.not = 4
|
68
53
|
end
|
69
54
|
|
70
55
|
#=> conditions array: ["foo > ? and foo <> ?", 2, 4]
|
71
56
|
|
72
57
|
Contains:
|
73
58
|
|
74
|
-
@obj = ActiveRecordObject.where do
|
75
|
-
|
59
|
+
@obj = ActiveRecordObject.where do |obj|
|
60
|
+
obj.foo.contains "bar"
|
76
61
|
end
|
77
62
|
#=> conditions array: ["foo like '%' || ? || '%'", "bar"]
|
78
63
|
#using the default sqlite adapter
|
79
64
|
|
80
65
|
In:
|
81
66
|
|
82
|
-
|
67
|
+
@obj = ActiveRecordObject.where do |obj|
|
83
68
|
obj.foo.in "bar", "baz", "bak"
|
84
69
|
end
|
85
70
|
#=> conditions array: ["foo in (?)", ["bar", "baz", "bak"]]
|
@@ -90,8 +75,8 @@ You can also limit the results returned in a similar manner to the `find` method
|
|
90
75
|
|
91
76
|
First:
|
92
77
|
|
93
|
-
@obj = ActiveRecordObject.where(:first) do
|
94
|
-
|
78
|
+
@obj = ActiveRecordObject.where(:first) do |obj|
|
79
|
+
obj.foo == "bar"
|
95
80
|
end
|
96
81
|
|
97
82
|
is equivalent to the find call:
|
@@ -103,7 +88,7 @@ is equivalent to the find call:
|
|
103
88
|
RQuery supports relatively complex queries including | and & operation groupings. All operations need to be on the same line and in parens and either the | operator or the & operator can be used on a singel line
|
104
89
|
|
105
90
|
User.where do |user|
|
106
|
-
(
|
91
|
+
(user.age > 20) | (user.age.in 16,18)
|
107
92
|
end
|
108
93
|
|
109
94
|
In the following example the & takes precedence and will be grouped with the contains "Alice" which will be or'd with the contains "George"
|
data/lib/rquery.rb
CHANGED
@@ -3,23 +3,17 @@ $: << File.expand_path(File.dirname(__FILE__) + "/../lib/")
|
|
3
3
|
#RQuery is a small DSL for building queries in query languages like SQL. It is meant to be concise, easy to read
|
4
4
|
#and expressive.
|
5
5
|
|
6
|
-
require "rquery/
|
7
|
-
require "rquery/declarations.rb"
|
8
|
-
require "rquery/attribute.rb"
|
6
|
+
require "rquery/operation_collector.rb"
|
9
7
|
require "rquery/attribute_collection.rb"
|
10
8
|
require "rquery/adapters.rb"
|
11
9
|
require "rquery/active_record.rb"
|
12
10
|
|
13
11
|
module RQuery
|
14
|
-
class
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
Symbol.send(:include, RQuery::Declarations)
|
12
|
+
class Config
|
13
|
+
@@adapter = RQuery::Adapters::Sqlite
|
14
|
+
def self.adapter=(value)
|
15
|
+
@@adapter = value
|
19
16
|
end
|
20
|
-
|
21
|
-
end
|
17
|
+
def self.adapter; @@adapter end
|
18
|
+
end
|
22
19
|
end
|
23
|
-
|
24
|
-
##default adapter
|
25
|
-
RQuery.adapter = RQuery::Adapters::Sqlite
|
@@ -1,26 +1,15 @@
|
|
1
1
|
module RQuery
|
2
2
|
module ActiveRecord
|
3
|
-
@@where_mutex = Mutex.new
|
4
3
|
def where(*args, &block)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#if RQuery.use_symbols has been called it may not be used
|
15
|
-
#but otherwise will take the form attr_coll_object.attribute.is ...
|
16
|
-
yield(RQuery::AttributeCollection.new(self.new.attribute_names))
|
17
|
-
|
18
|
-
#record altered conditions and values
|
19
|
-
conditions = ::RQuery::Serializers::Operations.conditions
|
20
|
-
|
21
|
-
#clear the alterations
|
22
|
-
RQuery::Serializers::Operations.clear
|
23
|
-
end
|
4
|
+
collector = RQuery::AttributeCollection.new(self.new.attribute_names)
|
5
|
+
|
6
|
+
#Passes a new AttributeCollection object to the block
|
7
|
+
#if RQuery.use_symbols has been called it may not be used
|
8
|
+
#but otherwise will take the form attr_coll_object.attribute.is ...
|
9
|
+
yield(collector)
|
10
|
+
|
11
|
+
#record altered conditions and values
|
12
|
+
conditions = collector.clauses.to_conditions
|
24
13
|
|
25
14
|
#limit the records returned (:first, :all, :last)
|
26
15
|
limit = args.first ? args.first : :all
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module RQuery
|
2
2
|
class AttributeCollection
|
3
|
+
attr_reader :clauses
|
3
4
|
|
4
5
|
def initialize(fields)
|
5
6
|
@fields = fields.map{ |x| x.to_s }
|
7
|
+
@clauses = OperationCollector.new
|
6
8
|
end
|
7
|
-
|
9
|
+
|
8
10
|
#if the field was added upon initialization its a valid call
|
9
11
|
#otherwise report to the user it is invalid. Reports errors at the ruby level
|
10
12
|
#instead of the data store level with something like "column doesn't exist"
|
@@ -22,11 +24,31 @@ module RQuery
|
|
22
24
|
# from /Users/johnbender/Projects/rquery/lib/rquery/where_clause.rb:20:in `method_missing'
|
23
25
|
# from (irb):5
|
24
26
|
def method_missing(symbol, *args)
|
25
|
-
|
26
|
-
|
27
|
+
attr_str = symbol.to_s
|
28
|
+
eq_str = attr_str.gsub(/=/, '')
|
29
|
+
|
30
|
+
if @fields.include?(attr_str) #if the method is part of the attributes
|
31
|
+
add_clause(attr_str)
|
32
|
+
elsif @fields.include?(eq_str) #if the method sans '=' is part of the attributes
|
33
|
+
add_clause(eq_str)
|
34
|
+
eq(*args)
|
27
35
|
else
|
28
36
|
raise AttributeNotFoundError, "The field '#{symbol.to_s}' doesn't exist for this object"
|
29
37
|
end
|
38
|
+
|
39
|
+
#explicit return of OperationCollector, same instance returned by methods of Operation collector
|
40
|
+
#but included here for clarity
|
41
|
+
@clauses
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
def add_clause(str)
|
47
|
+
@clauses.add_operation(str)
|
48
|
+
end
|
49
|
+
|
50
|
+
def eq(*args)
|
51
|
+
@clauses.send(:==, *args)
|
30
52
|
end
|
31
53
|
|
32
54
|
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module RQuery
|
2
|
+
class OperationCollector
|
3
|
+
NOT_PREFIX = 'not_'
|
4
|
+
NIL_PREFIX = ''
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
# @name, @prefix = optns[:name], optns[:prefix]
|
8
|
+
@operations = []
|
9
|
+
@values = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
RQuery::Config.adapter.join(@operations)
|
14
|
+
end
|
15
|
+
|
16
|
+
#return a conditions array for use with ActiveRecord.find
|
17
|
+
def to_conditions
|
18
|
+
[to_s] + @values
|
19
|
+
end
|
20
|
+
|
21
|
+
#add and operation to the @operations array which will be popped
|
22
|
+
#and pushed depending on the operations sequence and arrangement
|
23
|
+
def add_operation(val)
|
24
|
+
@operations << val.to_s
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
#grouping is done by using the | and & operators between multiple operations
|
29
|
+
#objects on a single line.
|
30
|
+
#
|
31
|
+
#This works because each operation ie (user.age.is == 2) is
|
32
|
+
#evaluated before these two operators thus pushing
|
33
|
+
#the equivelant operation string onto the @operations array (ie 'age = ?').
|
34
|
+
#When an operation is evaluated it returns the Operations class which can be compared
|
35
|
+
#using the aforementioned operators. Those operators call the group method
|
36
|
+
#popping the last two arguments off the stack and dealing with them in one of two ways
|
37
|
+
#
|
38
|
+
#1. if the second object popped is a string both objects should be
|
39
|
+
# added to a new OperationGroup which is then put back onto the stack
|
40
|
+
#
|
41
|
+
#2. if the second object popped is an OperationGroup the firest belongs to this group as
|
42
|
+
# well (it was on the same line). It is added to the OperationGroup and put back on the
|
43
|
+
# stack
|
44
|
+
#
|
45
|
+
#TODO requires refactoring
|
46
|
+
def group(type)
|
47
|
+
second_op, first_op = @operations.pop, @operations.pop
|
48
|
+
|
49
|
+
#if the previous operation on the stack is an Operation Group we need to add to it
|
50
|
+
#and push it back on the @operations stack
|
51
|
+
if first_op.class == OperationsGroup
|
52
|
+
if first_op.type == type
|
53
|
+
first_op.ops << second_op
|
54
|
+
@operations << first_op
|
55
|
+
else
|
56
|
+
@operations << OperationsGroup.new(first_op.to_s, second_op, type)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
@operations << OperationsGroup.new(first_op, second_op, type)
|
60
|
+
end
|
61
|
+
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
#used to group operations for anding on a single line
|
66
|
+
#example with sqlite adapter
|
67
|
+
#(user.age.in [1,2,3]) | (user.name.contains "foo")
|
68
|
+
#=>(age in (?) and name like '%' || 'foo' || '%')
|
69
|
+
def &(second)
|
70
|
+
group :and
|
71
|
+
end
|
72
|
+
|
73
|
+
def |(second)
|
74
|
+
group :or
|
75
|
+
end
|
76
|
+
|
77
|
+
def in(*args)
|
78
|
+
call_in(NIL_PREFIX, *args)
|
79
|
+
end
|
80
|
+
|
81
|
+
def not_in(*args)
|
82
|
+
call_in(NOT_PREFIX, *args)
|
83
|
+
end
|
84
|
+
|
85
|
+
def between(*args)
|
86
|
+
call_between(NIL_PREFIX, *args)
|
87
|
+
end
|
88
|
+
|
89
|
+
def not_between(*args)
|
90
|
+
call_between(NOT_PREFIX, *args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def contains(str)
|
94
|
+
@values << str
|
95
|
+
chain :contains
|
96
|
+
end
|
97
|
+
|
98
|
+
def without(str)
|
99
|
+
@values << str
|
100
|
+
chain :without
|
101
|
+
end
|
102
|
+
|
103
|
+
def not=(arg)
|
104
|
+
@values << arg
|
105
|
+
chain :neq
|
106
|
+
end
|
107
|
+
|
108
|
+
[:==, :>, :>=, :<, :<=, :neq].each do |operator|
|
109
|
+
define_method(operator) do |val|
|
110
|
+
@values << val
|
111
|
+
chain operator
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
#allows for is.from
|
116
|
+
#examples:
|
117
|
+
#
|
118
|
+
#:id.is.from 1,2
|
119
|
+
#:is.is.from 2..10
|
120
|
+
alias :from :between
|
121
|
+
alias :not_from :not_between
|
122
|
+
|
123
|
+
private
|
124
|
+
def chain(method)
|
125
|
+
@operations[@operations.length-1] += " #{RQuery::Config.adapter.send(method)}"
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
def call_in(prefix=nil, *args)
|
130
|
+
#flatten our args to prevent having to check for an array first arg
|
131
|
+
args.flatten!
|
132
|
+
|
133
|
+
#if a range is passed as the first argument
|
134
|
+
#use it alone, otherwise use the args array
|
135
|
+
#examples:
|
136
|
+
#ruby => args.flatten! => stored values
|
137
|
+
#:id.between 1..100 => [1..100] => 1..100
|
138
|
+
#:id.between [1, 2, 3] => [1, 2, 3] => [1, 2, 3]
|
139
|
+
#:id.between 1, 2 => [1, 2] => [1, 2]
|
140
|
+
@values << (args.first.class == Range ? args.first : args)
|
141
|
+
chain :"#{prefix}in"
|
142
|
+
end
|
143
|
+
|
144
|
+
def call_between(prefix=nil, *args)
|
145
|
+
#flatten our args to prevent having to check for an array first arg
|
146
|
+
args.flatten!
|
147
|
+
|
148
|
+
#if a range is passed use its first/last element
|
149
|
+
#otherwise use the first and last element of the flattened args array
|
150
|
+
#examples:
|
151
|
+
#ruby => args.flatten! => stored values
|
152
|
+
#:id.between 1..100 => [1..100] => 1 100
|
153
|
+
#:id.between [1, 2, 3] => [1, 2, 3] => 1 3
|
154
|
+
#:id.between 1, 2 => [1, 2] => 1 2
|
155
|
+
|
156
|
+
@values += (args.first.class == Range ? [args.first.first, args.first.last] : [args.first, args.last])
|
157
|
+
chain :"#{prefix}between"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class OperationsGroup
|
162
|
+
attr_accessor :ops, :type
|
163
|
+
|
164
|
+
def initialize(left, right, type)
|
165
|
+
@ops = Array.new
|
166
|
+
@ops << left
|
167
|
+
@ops << right
|
168
|
+
@type = type
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_s
|
172
|
+
RQuery::Config.adapter.send("#{type.to_s}_group", @ops)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
data/rakefile.rb
CHANGED
@@ -4,74 +4,71 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/rquery.rb")
|
|
4
4
|
describe ActiveRecord do
|
5
5
|
|
6
6
|
before(:all) do
|
7
|
-
RQuery.adapter = RQuery::Adapters::Sqlite
|
7
|
+
RQuery::Config.adapter = RQuery::Adapters::Sqlite
|
8
8
|
end
|
9
9
|
|
10
|
-
#should really set up the find method defined above to use the ruby db libraries and
|
11
|
-
#create the final sql string
|
12
|
-
#all run with default adapter
|
13
|
-
|
14
10
|
it "should set up a where method" do
|
15
11
|
ActiveRecord::MockObject.respond_to?(:where).should == true
|
16
12
|
end
|
17
13
|
|
18
|
-
it "should return sql with foo, the operations, and the values for mock.foo
|
19
|
-
|
14
|
+
it "should return sql with foo, the operations, and the values for mock.foo <operation> <value>" do
|
20
15
|
ActiveRecord::MockObject.where{ |mock|
|
21
|
-
mock.foo
|
22
|
-
|
16
|
+
mock.foo == "bar"
|
17
|
+
mock.foo = "bar"
|
18
|
+
}.should == [:all, {:conditions => ["(foo = ? and foo = ?)", "bar", "bar"]}]
|
23
19
|
|
24
20
|
ActiveRecord::MockObject.where{ |mock|
|
25
|
-
mock.foo
|
21
|
+
mock.foo > 1
|
26
22
|
}.should == [:all, {:conditions => ["(foo > ?)", 1]}]
|
27
23
|
|
28
24
|
ActiveRecord::MockObject.where{ |mock|
|
29
|
-
mock.foo
|
25
|
+
mock.foo < 2
|
30
26
|
}.should == [:all, {:conditions => ["(foo < ?)", 2]}]
|
31
27
|
|
32
28
|
ActiveRecord::MockObject.where{ |mock|
|
33
|
-
mock.foo
|
29
|
+
mock.foo >= 3
|
34
30
|
}.should == [:all, {:conditions => ["(foo >= ?)", 3]}]
|
35
31
|
|
36
32
|
ActiveRecord::MockObject.where{ |mock|
|
37
|
-
mock.foo
|
33
|
+
mock.foo <= 4
|
38
34
|
}.should == [:all, {:conditions => ["(foo <= ?)", 4]}]
|
39
|
-
|
40
35
|
end
|
41
36
|
|
42
|
-
it "should return sql with foo, the operations, and the values for mock.foo.
|
37
|
+
it "should return sql with foo, the operations, and the values for mock.foo.not_<operation> <value>" do
|
43
38
|
ActiveRecord::MockObject.where{ |mock|
|
44
|
-
mock.foo.
|
39
|
+
mock.foo.not = "bar"
|
45
40
|
}.should == [:all, {:conditions => ["(foo <> ?)", "bar"]}]
|
46
41
|
|
47
42
|
ActiveRecord::MockObject.where{ |mock|
|
48
|
-
mock.foo.
|
43
|
+
mock.foo.not_in 1,2
|
49
44
|
}.should == [:all, {:conditions => ["(foo not in (?))", [1,2]]}]
|
50
45
|
|
51
46
|
ActiveRecord::MockObject.where{ |mock|
|
52
|
-
mock.foo.
|
47
|
+
mock.foo.not_between 1..3
|
53
48
|
}.should == [:all, {:conditions => ["(foo not between ? and ?)", 1, 3]}]
|
54
49
|
|
55
50
|
ActiveRecord::MockObject.where{ |mock|
|
56
|
-
mock.foo.
|
51
|
+
mock.foo.not_from 1..3
|
57
52
|
}.should == [:all, {:conditions => ["(foo not between ? and ?)", 1, 3]}]
|
58
|
-
|
53
|
+
|
54
|
+
ActiveRecord::MockObject.where{ |mock|
|
55
|
+
mock.foo.without "bar"
|
56
|
+
}.should == [:all, {:conditions => ["(foo not like '%' || ? || '%')", "bar"]}]
|
59
57
|
end
|
60
58
|
|
61
|
-
it "should return sql with foo, the operations, and values for mock.foo.
|
62
|
-
|
59
|
+
it "should return sql with foo, the operations, and values for mock.foo.in and mock.foo.in when used with a list of args, array, and range" do
|
63
60
|
resulting_conditions = [:all, {:conditions => ["(foo in (?))", [1,2,3,4]]}]
|
64
61
|
|
65
62
|
ActiveRecord::MockObject.where{ |mock|
|
66
|
-
mock.foo.
|
63
|
+
mock.foo.in 1,2,3,4
|
67
64
|
}.should == resulting_conditions
|
68
65
|
|
69
66
|
ActiveRecord::MockObject.where{ |mock|
|
70
|
-
mock.foo.
|
67
|
+
mock.foo.in [1,2,3,4]
|
71
68
|
}.should == resulting_conditions
|
72
69
|
|
73
70
|
ActiveRecord::MockObject.where{ |mock|
|
74
|
-
mock.foo.
|
71
|
+
mock.foo.in 1..4
|
75
72
|
}.should == [:all, {:conditions => ["(foo in (?))", 1..4]}]
|
76
73
|
|
77
74
|
ActiveRecord::MockObject.where{ |mock|
|
@@ -85,23 +82,21 @@ describe ActiveRecord do
|
|
85
82
|
ActiveRecord::MockObject.where{ |mock|
|
86
83
|
mock.foo.in 1..4
|
87
84
|
}.should == [:all, {:conditions => ["(foo in (?))", 1..4]}]
|
88
|
-
|
89
85
|
end
|
90
86
|
|
91
|
-
it "should return sql with foo, operations, and values for mock.foo.
|
92
|
-
|
87
|
+
it "should return sql with foo, operations, and values for mock.foo.between and mock.foo.between when used with a list of args, array, and range" do
|
93
88
|
resulting_conditions = [:all, {:conditions => ["(foo between ? and ?)", 1, 2]}]
|
94
89
|
|
95
90
|
ActiveRecord::MockObject.where{ |mock|
|
96
|
-
mock.foo.
|
91
|
+
mock.foo.between 1,2
|
97
92
|
}.should == resulting_conditions
|
98
93
|
|
99
94
|
ActiveRecord::MockObject.where{ |mock|
|
100
|
-
mock.foo.
|
95
|
+
mock.foo.between [1,2]
|
101
96
|
}.should == resulting_conditions
|
102
97
|
|
103
98
|
ActiveRecord::MockObject.where{ |mock|
|
104
|
-
mock.foo.
|
99
|
+
mock.foo.between 1..2
|
105
100
|
}.should == resulting_conditions
|
106
101
|
|
107
102
|
ActiveRecord::MockObject.where{ |mock|
|
@@ -115,23 +110,21 @@ describe ActiveRecord do
|
|
115
110
|
ActiveRecord::MockObject.where{ |mock|
|
116
111
|
mock.foo.between 1..2
|
117
112
|
}.should == resulting_conditions
|
118
|
-
|
119
113
|
end
|
120
114
|
|
121
|
-
it "should return sql with foo, operations, and values for mock.foo.
|
122
|
-
|
115
|
+
it "should return sql with foo, operations, and values for mock.foo.from when used with a list of args, array, and range" do
|
123
116
|
resulting_conditions = [:all, {:conditions => ["(foo between ? and ?)", 1, 2]}]
|
124
117
|
|
125
118
|
ActiveRecord::MockObject.where{ |mock|
|
126
|
-
mock.foo.
|
119
|
+
mock.foo.from 1,2
|
127
120
|
}.should == resulting_conditions
|
128
121
|
|
129
122
|
ActiveRecord::MockObject.where{ |mock|
|
130
|
-
mock.foo.
|
123
|
+
mock.foo.from [1,2]
|
131
124
|
}.should == resulting_conditions
|
132
125
|
|
133
126
|
ActiveRecord::MockObject.where{ |mock|
|
134
|
-
mock.foo.
|
127
|
+
mock.foo.from 1..2
|
135
128
|
}.should == resulting_conditions
|
136
129
|
|
137
130
|
ActiveRecord::MockObject.where{ |mock|
|
@@ -145,72 +138,58 @@ describe ActiveRecord do
|
|
145
138
|
ActiveRecord::MockObject.where{ |mock|
|
146
139
|
mock.foo.from 1..2
|
147
140
|
}.should == resulting_conditions
|
148
|
-
|
149
|
-
|
150
141
|
end
|
151
142
|
|
152
143
|
it "should return sql with foo, operations, and values for mock.foo.contains when used with a range, array, and list" do
|
153
|
-
|
154
144
|
resulting_conditions = [:all, {:conditions => ["(foo like '%' || ? || '%')", "bar"]}]
|
155
145
|
|
156
146
|
ActiveRecord::MockObject.where{ |mock|
|
157
147
|
mock.foo.contains "bar"
|
158
148
|
}.should == resulting_conditions
|
159
|
-
|
160
149
|
end
|
161
150
|
|
162
|
-
|
163
151
|
it "should return return the correct group of joined sql after multiple operations" do
|
164
|
-
|
165
152
|
ActiveRecord::MockObject.where{ |mock|
|
166
|
-
mock.foo
|
167
|
-
mock.foo.
|
153
|
+
mock.foo == "bar"
|
154
|
+
mock.foo.not_in 1,2,3,4,5
|
168
155
|
}.should == [:all, {:conditions => ["(foo = ? and foo not in (?))", "bar", [1,2,3,4,5]]}]
|
169
|
-
|
170
156
|
end
|
171
157
|
|
172
158
|
it "should return return the correct limit value passed" do
|
173
|
-
|
174
159
|
ActiveRecord::MockObject.where(:first){ |mock|
|
175
|
-
mock.foo
|
176
|
-
mock.foo.
|
160
|
+
mock.foo == "bar"
|
161
|
+
mock.foo.not_in 1,2,3,4,5
|
177
162
|
}.should == [:first, {:conditions => ["(foo = ? and foo not in (?))", "bar", [1,2,3,4,5]]}]
|
178
|
-
|
179
163
|
end
|
180
164
|
|
181
165
|
it "should have the correct 'not' keywords in alternating operations" do
|
182
|
-
|
183
166
|
ActiveRecord::MockObject.where(:first){ |mock|
|
184
|
-
mock.foo
|
185
|
-
mock.foo.
|
186
|
-
mock.foo
|
167
|
+
mock.foo == "bar"
|
168
|
+
mock.foo.not_in 1,2,3,4,5
|
169
|
+
mock.foo > 3
|
187
170
|
}.should == [:first, {:conditions => ["(foo = ? and foo not in (?) and foo > ?)", "bar", [1,2,3,4,5], 3]}]
|
188
|
-
|
189
171
|
end
|
190
172
|
|
191
173
|
it "should return return strings as arguments when passed to between, in, and from (used for date strings)" do
|
192
|
-
|
193
174
|
ActiveRecord::MockObject.where{ |mock|
|
194
|
-
mock.foo.
|
175
|
+
mock.foo.between "some string", "2007-01-01"
|
195
176
|
}.should == [:all, {:conditions => ["(foo between ? and ?)", "some string", "2007-01-01"]}]
|
196
177
|
|
197
178
|
ActiveRecord::MockObject.where{ |mock|
|
198
|
-
mock.foo.
|
179
|
+
mock.foo.not_between "some string", "2007-01-01"
|
199
180
|
}.should == [:all, {:conditions => ["(foo not between ? and ?)", "some string", "2007-01-01"]}]
|
200
181
|
|
201
182
|
ActiveRecord::MockObject.where{ |mock|
|
202
|
-
mock.foo.
|
183
|
+
mock.foo.from "some string", "2007-01-01"
|
203
184
|
}.should == [:all, {:conditions => ["(foo between ? and ?)", "some string", "2007-01-01"]}]
|
204
185
|
|
205
186
|
ActiveRecord::MockObject.where{ |mock|
|
206
187
|
mock.foo.in "some string", "2007-01-01"
|
207
188
|
}.should == [:all, {:conditions => ["(foo in (?))", ["some string", "2007-01-01"]]}]
|
208
|
-
|
209
189
|
end
|
210
190
|
|
211
191
|
it "should throw and exception when trying to use a field not in the objects attributes" do
|
212
192
|
attribute = "arbitrary_attribute_name"
|
213
|
-
lambda { ActiveRecord::MockObject.where{ |mock| mock.send(attribute)
|
193
|
+
lambda { ActiveRecord::MockObject.where{ |mock| mock.send(attribute) == 2 }}.should raise_error(RQuery::AttributeNotFoundError)
|
214
194
|
end
|
215
|
-
|
216
195
|
end
|