crud-service 0.0.9 → 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.
- checksums.yaml +6 -14
- data/lib/crud-service.rb +6 -3
- data/lib/crud-service/api.rb +152 -0
- data/lib/{dal.rb → crud-service/dal.rb} +25 -5
- data/lib/{service.rb → crud-service/service.rb} +7 -1
- data/lib/crud-service/version.rb +5 -0
- data/spec/api_spec.rb +609 -0
- data/spec/dal_spec.rb +1363 -0
- data/spec/{unit/service_spec.rb → service_spec.rb} +23 -23
- data/spec/spec_helper.rb +58 -0
- metadata +70 -106
- data/lib/api.rb +0 -129
- data/spec/helper.rb +0 -12
- data/spec/helpers_spec.rb +0 -30
- data/spec/unit/dal_spec.rb +0 -1174
data/lib/api.rb
DELETED
@@ -1,129 +0,0 @@
|
|
1
|
-
module CrudService
|
2
|
-
module Api
|
3
|
-
# This mixin provides a static method, crud_api, to configure a sinatra class with the
|
4
|
-
# provided resource name, service and api_options
|
5
|
-
def crud_api(resource_name, service_name, primary_key_name, api_options = {})
|
6
|
-
|
7
|
-
defaults = {
|
8
|
-
:enable_read => true,
|
9
|
-
:enable_write => true,
|
10
|
-
:enable_options => true,
|
11
|
-
:enable_get_all => true,
|
12
|
-
:enable_get => true,
|
13
|
-
:enable_post => true,
|
14
|
-
:enable_put => true,
|
15
|
-
:enable_delete => true,
|
16
|
-
}
|
17
|
-
api_options.merge!(defaults) { |key, v1, v2| v1 }
|
18
|
-
|
19
|
-
if api_options[:enable_options]
|
20
|
-
options '/'+resource_name do
|
21
|
-
204
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
if api_options[:enable_write]
|
26
|
-
|
27
|
-
if api_options[:enable_post]
|
28
|
-
post '/'+resource_name do
|
29
|
-
service = settings.send(service_name)
|
30
|
-
|
31
|
-
# Get The data
|
32
|
-
begin
|
33
|
-
data = JSON.parse(request.body.read)
|
34
|
-
rescue Exception => e
|
35
|
-
return 400
|
36
|
-
end
|
37
|
-
|
38
|
-
# Valid POST?
|
39
|
-
return 400 unless service.valid_insert?(data)
|
40
|
-
|
41
|
-
# Already Exists?
|
42
|
-
return 409 if service.exists_by_primary_key?(data[primary_key_name])
|
43
|
-
|
44
|
-
# Do Insert
|
45
|
-
record = service.insert(data)
|
46
|
-
|
47
|
-
# Other Error
|
48
|
-
return 500 if record == false
|
49
|
-
|
50
|
-
# Output new record
|
51
|
-
JSON.fast_generate record
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
if api_options[:enable_put]
|
56
|
-
put '/'+resource_name+'/:'+primary_key_name do
|
57
|
-
service = settings.send(service_name)
|
58
|
-
|
59
|
-
# Must Exist
|
60
|
-
return 404 unless service.exists_by_primary_key?(params[primary_key_name.to_sym])
|
61
|
-
|
62
|
-
# Get The Data
|
63
|
-
begin
|
64
|
-
data = JSON.parse(request.body.read)
|
65
|
-
rescue Exception => e
|
66
|
-
return 400
|
67
|
-
end
|
68
|
-
|
69
|
-
# Valid Update?
|
70
|
-
return 400 unless service.valid_update?(data)
|
71
|
-
|
72
|
-
# Do Update
|
73
|
-
record = service.update_by_primary_key(params[primary_key_name.to_sym],data)
|
74
|
-
|
75
|
-
# Other Error
|
76
|
-
return 500 if record.nil?
|
77
|
-
|
78
|
-
# Return new Region
|
79
|
-
JSON.fast_generate record
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
if api_options[:enable_delete]
|
84
|
-
delete '/'+resource_name+'/:'+primary_key_name do
|
85
|
-
service = settings.send(service_name)
|
86
|
-
|
87
|
-
# Must Exist
|
88
|
-
return 404 unless service.exists_by_primary_key?(params[primary_key_name.to_sym])
|
89
|
-
|
90
|
-
# Do Delete
|
91
|
-
return 400 unless service.delete_by_primary_key(params[primary_key_name.to_sym])
|
92
|
-
|
93
|
-
204
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
if api_options[:enable_read]
|
100
|
-
|
101
|
-
if api_options[:enable_get]
|
102
|
-
get '/'+resource_name do
|
103
|
-
service = settings.send(service_name)
|
104
|
-
|
105
|
-
sanitize_params(params)
|
106
|
-
# Check query validity
|
107
|
-
return 400 unless service.valid_query?(params)
|
108
|
-
|
109
|
-
# Return Regions on Query
|
110
|
-
JSON.fast_generate service.get_all_by_query(params)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
if api_options[:enable_get_all]
|
115
|
-
get '/'+resource_name+'/:'+primary_key_name do
|
116
|
-
service = self.settings.send(service_name)
|
117
|
-
|
118
|
-
sanitize_params(params)
|
119
|
-
return 400 unless service.valid_query?(params)
|
120
|
-
|
121
|
-
record = service.get_one_by_query(params)
|
122
|
-
return 404 if record.nil?
|
123
|
-
JSON.fast_generate record
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
data/spec/helper.rb
DELETED
data/spec/helpers_spec.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
module Helpers
|
2
|
-
def mysql_mock
|
3
|
-
mysql = double("Mysql2")
|
4
|
-
mysql.stub(:escape) do |s|
|
5
|
-
Mysql2::Client.escape(s)
|
6
|
-
end
|
7
|
-
mysql
|
8
|
-
end
|
9
|
-
|
10
|
-
# Mock a Mysql Result object that returns each_hash
|
11
|
-
def mysql_result_mock(data)
|
12
|
-
result = double(result)
|
13
|
-
mock = result.stub(:each)
|
14
|
-
|
15
|
-
data.each do |hash|
|
16
|
-
mock = mock.and_yield(hash)
|
17
|
-
end
|
18
|
-
|
19
|
-
result.stub(:count).and_return(data.length)
|
20
|
-
|
21
|
-
result
|
22
|
-
end
|
23
|
-
|
24
|
-
# Make the supplied memcache_mock null (no hits, null write)
|
25
|
-
def memcache_null(memcache_mock)
|
26
|
-
@mock_memcache.stub(:get).and_return(nil)
|
27
|
-
@mock_memcache.stub(:set).and_return(nil)
|
28
|
-
@mock_memcache.stub(:incr).and_return(nil)
|
29
|
-
end
|
30
|
-
end
|
data/spec/unit/dal_spec.rb
DELETED
@@ -1,1174 +0,0 @@
|
|
1
|
-
require "helper"
|
2
|
-
|
3
|
-
describe CrudService::Dal do
|
4
|
-
before(:each) do
|
5
|
-
@mock_mysql = mysql_mock
|
6
|
-
@mock_memcache = double('Memcache')
|
7
|
-
@mock_log = double('Log')
|
8
|
-
|
9
|
-
@generic_dal = CrudService::Dal.new(@mock_mysql, @mock_memcache, @mock_log)
|
10
|
-
@generic_dal.table_name = "testtable"
|
11
|
-
@generic_dal.cache_prefix = "prefix"
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '#initialize' do
|
15
|
-
it 'should inject dependencies correctly' do
|
16
|
-
@generic_dal.mysql.should eq @mock_mysql
|
17
|
-
@generic_dal.memcache.should eq @mock_memcache
|
18
|
-
@generic_dal.log.should eq @mock_log
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#cached_query' do
|
23
|
-
it 'should attempt to query the cache before the database' do
|
24
|
-
|
25
|
-
testdata = [ { "field_one" => "one" } ]
|
26
|
-
|
27
|
-
mock_result = mysql_result_mock(testdata)
|
28
|
-
|
29
|
-
query = 'test invalid query'
|
30
|
-
query_hash = "prefix-"+Digest::MD5.hexdigest(query+":testtable-1")
|
31
|
-
|
32
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(1)
|
33
|
-
@mock_memcache.should_receive(:get).ordered.with(query_hash).and_return(nil)
|
34
|
-
@mock_mysql.should_receive(:query).with(query).and_return(mock_result)
|
35
|
-
@mock_memcache.should_receive(:set).ordered.with(query_hash, testdata)
|
36
|
-
|
37
|
-
@generic_dal.cached_query(query,[]).should eq testdata
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should not attempt to query the database on a cache hit' do
|
41
|
-
testdata = [ { "field_one" => "one" } ]
|
42
|
-
query = 'test invalid query'
|
43
|
-
query_hash = "prefix-"+Digest::MD5.hexdigest(query+":testtable-1")
|
44
|
-
|
45
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(1)
|
46
|
-
@mock_memcache.should_receive(:get).ordered.with(query_hash).and_return(testdata)
|
47
|
-
@mock_mysql.should_not_receive(:query)
|
48
|
-
@mock_memcache.should_not_receive(:set).ordered
|
49
|
-
|
50
|
-
@generic_dal.cached_query(query,[]).should eq testdata
|
51
|
-
end
|
52
|
-
|
53
|
-
it 'should handle zero record return' do
|
54
|
-
memcache_null(@mock_memcache)
|
55
|
-
|
56
|
-
query = 'test invalid query'
|
57
|
-
|
58
|
-
@mock_mysql.should_receive(:query).with(query).and_return(mysql_result_mock([]))
|
59
|
-
|
60
|
-
@generic_dal.cached_query(query,[]).should eq([])
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'should write a new table version to cache when not found' do
|
64
|
-
testdata = [ { "field_one" => "one" } ]
|
65
|
-
|
66
|
-
mock_result = mysql_result_mock(testdata)
|
67
|
-
|
68
|
-
query = 'test invalid query'
|
69
|
-
query_hash = "prefix-"+Digest::MD5.hexdigest(query+":testtable-1")
|
70
|
-
|
71
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(nil)
|
72
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(nil)
|
73
|
-
@mock_memcache.should_receive(:set).ordered.with("prefix-testtable-version",1,nil,{:raw=>true})
|
74
|
-
@mock_memcache.should_receive(:get).ordered.with(query_hash).and_return(nil)
|
75
|
-
@mock_mysql.should_receive(:query).ordered.with(query).and_return(mock_result)
|
76
|
-
@mock_memcache.should_receive(:set).ordered.with(query_hash, testdata)
|
77
|
-
|
78
|
-
@generic_dal.cached_query(query,[]).should eq testdata
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'should miss the cache when a table version has changed' do
|
82
|
-
testdata = [ { "field_one" => "one" } ]
|
83
|
-
|
84
|
-
mock_result = mysql_result_mock(testdata)
|
85
|
-
|
86
|
-
query = 'test invalid query'
|
87
|
-
query_hash = "prefix-"+Digest::MD5.hexdigest(query+":testtable-1")
|
88
|
-
|
89
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(1)
|
90
|
-
@mock_memcache.should_receive(:get).ordered.with(query_hash).and_return(nil)
|
91
|
-
@mock_mysql.should_receive(:query).with(query).and_return(mock_result)
|
92
|
-
@mock_memcache.should_receive(:set).ordered.with(query_hash, testdata)
|
93
|
-
|
94
|
-
@generic_dal.cached_query(query,[]).should eq testdata
|
95
|
-
|
96
|
-
query_hash = "prefix-"+Digest::MD5.hexdigest(query+":testtable-2")
|
97
|
-
|
98
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(2)
|
99
|
-
@mock_memcache.should_receive(:get).ordered.with(query_hash).and_return(nil)
|
100
|
-
@mock_mysql.should_receive(:query).with(query).and_return(mock_result)
|
101
|
-
@mock_memcache.should_receive(:set).ordered.with(query_hash, testdata)
|
102
|
-
|
103
|
-
@generic_dal.cached_query(query,[]).should eq testdata
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
describe '#build_where' do
|
109
|
-
it 'should return an empty string when called with no query' do
|
110
|
-
query = { }
|
111
|
-
@generic_dal.build_where(query).should eq ""
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'should return a valid where clause when called with a single field query string value' do
|
115
|
-
query = { "one" => "two" }
|
116
|
-
@generic_dal.build_where(query).should eq "(`one` = 'two')"
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'should return a valid where clause when called with a single field query integer value' do
|
120
|
-
query = { "one" => 2 }
|
121
|
-
@generic_dal.build_where(query).should eq "(`one` = 2)"
|
122
|
-
end
|
123
|
-
|
124
|
-
it 'should return a valid where clause when called with a single field query float value' do
|
125
|
-
query = { "one" => 2.123 }
|
126
|
-
@generic_dal.build_where(query).should eq "(`one` = 2.123)"
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'should return a valid where clause when called with a multiple field query' do
|
130
|
-
query = { "one" => "two", "three" => "four" }
|
131
|
-
@generic_dal.build_where(query).should eq "(`one` = 'two') AND (`three` = 'four')"
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'should return a valid where clause when called with a query with a nil value' do
|
135
|
-
query = { "one" => "two", "three" => nil}
|
136
|
-
@generic_dal.build_where(query).should eq "(`one` = 'two') AND (`three` IS NULL)"
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'should escape field names' do
|
140
|
-
query = { "on`=1; DROP TABLE countries" => "two" }
|
141
|
-
@generic_dal.build_where(query).should eq "(`on=1; DROP TABLE countries` = 'two')"
|
142
|
-
end
|
143
|
-
|
144
|
-
it 'should escape field values when string based' do
|
145
|
-
query = { "one" => "two'; DROP TABLE countries;" }
|
146
|
-
@generic_dal.build_where(query).should eq "(`one` = 'two\\'; DROP TABLE countries;')"
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'should not build include or exclude into queries' do
|
150
|
-
query = { "one" => 2, "include" => "subdivisions", "exclude" => "countries", "two"=>3 }
|
151
|
-
@generic_dal.build_where(query).should eq "(`one` = 2) AND (`two` = 3)"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
describe '#build_where_ns_ns' do
|
156
|
-
it 'should return an empty string when called with no query' do
|
157
|
-
query = { }
|
158
|
-
@generic_dal.build_where_ns(query,'a').should eq ""
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'should return a valid where clause when called with a single field query string value' do
|
162
|
-
query = { "one" => "two" }
|
163
|
-
@generic_dal.build_where_ns(query,'b').should eq "(`b`.`one` = 'two')"
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'should return a valid where clause when called with a single field query integer value' do
|
167
|
-
query = { "one" => 2 }
|
168
|
-
@generic_dal.build_where_ns(query,'c').should eq "(`c`.`one` = 2)"
|
169
|
-
end
|
170
|
-
|
171
|
-
it 'should return a valid where clause when called with a single field query float value' do
|
172
|
-
query = { "one" => 2.123 }
|
173
|
-
@generic_dal.build_where_ns(query,'d').should eq "(`d`.`one` = 2.123)"
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'should return a valid where clause when called with a multiple field query' do
|
177
|
-
query = { "one" => "two", "three" => "four" }
|
178
|
-
@generic_dal.build_where_ns(query,'e').should eq "(`e`.`one` = 'two') AND (`e`.`three` = 'four')"
|
179
|
-
end
|
180
|
-
|
181
|
-
it 'should return a valid where clause when called with a query with a nil value' do
|
182
|
-
query = { "one" => "two", "three" => nil}
|
183
|
-
@generic_dal.build_where_ns(query,'f').should eq "(`f`.`one` = 'two') AND (`f`.`three` IS NULL)"
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'should escape field names' do
|
187
|
-
query = { "on`=1; DROP TABLE countries" => "two" }
|
188
|
-
@generic_dal.build_where_ns(query,'g').should eq "(`g`.`on=1; DROP TABLE countries` = 'two')"
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'should escape field values when string based' do
|
192
|
-
query = { "one" => "two'; DROP TABLE countries;" }
|
193
|
-
@generic_dal.build_where_ns(query,'h').should eq "(`h`.`one` = 'two\\'; DROP TABLE countries;')"
|
194
|
-
end
|
195
|
-
|
196
|
-
it 'should not build include or exclude into queries' do
|
197
|
-
query = { "one" => 2, "include" => "subdivisions", "exclude" => "countries", "two"=>3 }
|
198
|
-
@generic_dal.build_where_ns(query,'i').should eq "(`i`.`one` = 2) AND (`i`.`two` = 3)"
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
describe '#build_fields' do
|
203
|
-
it 'should return an empty string with no fields' do
|
204
|
-
@generic_dal.build_select_fields([],nil).should eq ""
|
205
|
-
end
|
206
|
-
|
207
|
-
it 'should return fields correctly' do
|
208
|
-
@generic_dal.build_select_fields(['one','two'],nil).should eq "`one`,`two`"
|
209
|
-
end
|
210
|
-
|
211
|
-
it 'should return namespaced fields correctly' do
|
212
|
-
@generic_dal.build_select_fields(['one','two'],'a').should eq "`a`.`one`,`a`.`two`"
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
describe '#build_fields' do
|
217
|
-
before(:each) do
|
218
|
-
@generic_dal.fields = {
|
219
|
-
"test1" => { :type=>:string },
|
220
|
-
"test2" => { :type=>:string },
|
221
|
-
"testX" => { :type=>:string },
|
222
|
-
}
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'should return all fields with nil excludes' do
|
226
|
-
@generic_dal.build_fields({}).should eq "`test1`,`test2`,`testX`"
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'should return all fields with empty excludes' do
|
230
|
-
@generic_dal.build_fields({"exclude"=>nil}).should eq "`test1`,`test2`,`testX`"
|
231
|
-
end
|
232
|
-
|
233
|
-
it 'should exclude a single field' do
|
234
|
-
@generic_dal.build_fields({"exclude"=>'test1'}).should eq "`test2`,`testX`"
|
235
|
-
end
|
236
|
-
|
237
|
-
it 'should exclude multiple fields' do
|
238
|
-
@generic_dal.build_fields({"exclude"=>'test1,testX'}).should eq "`test2`"
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
describe '#build_fields_with_ns' do
|
243
|
-
before(:each) do
|
244
|
-
@generic_dal.fields = {
|
245
|
-
"test1" => { :type=>:string },
|
246
|
-
"test2" => { :type=>:string },
|
247
|
-
"testX" => { :type=>:string },
|
248
|
-
}
|
249
|
-
end
|
250
|
-
|
251
|
-
it 'should return all fields with nil excludes' do
|
252
|
-
@generic_dal.build_fields_with_ns({},'a').should eq "`a`.`test1`,`a`.`test2`,`a`.`testX`"
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'should return all fields with empty excludes' do
|
256
|
-
@generic_dal.build_fields_with_ns({"exclude"=>nil},'b').should eq "`b`.`test1`,`b`.`test2`,`b`.`testX`"
|
257
|
-
end
|
258
|
-
|
259
|
-
it 'should exclude a single field' do
|
260
|
-
@generic_dal.build_fields_with_ns({"exclude"=>'test1'},'c').should eq "`c`.`test2`,`c`.`testX`"
|
261
|
-
end
|
262
|
-
|
263
|
-
it 'should exclude multiple fields' do
|
264
|
-
@generic_dal.build_fields_with_ns({"exclude"=>'test1,testX'},'d').should eq "`d`.`test2`"
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
describe '#get_includes' do
|
269
|
-
before(:each) do
|
270
|
-
@generic_dal.fields = ["test1", "test2", "testX"]
|
271
|
-
end
|
272
|
-
|
273
|
-
it 'should return an empty array with a nil query' do
|
274
|
-
@generic_dal.get_includes(nil).should eq []
|
275
|
-
end
|
276
|
-
|
277
|
-
it 'should return an empty array with no fields or includes' do
|
278
|
-
query = { }
|
279
|
-
@generic_dal.get_includes(query).should eq []
|
280
|
-
end
|
281
|
-
|
282
|
-
it 'should return an empty array with fields and no includes' do
|
283
|
-
query = { "field2" => "xxas"}
|
284
|
-
@generic_dal.get_includes(query).should eq []
|
285
|
-
end
|
286
|
-
|
287
|
-
it 'should return a single include' do
|
288
|
-
query = { "include"=>"test1" }
|
289
|
-
@generic_dal.get_includes(query).should eq ['test1']
|
290
|
-
end
|
291
|
-
|
292
|
-
it 'should return multiple includes' do
|
293
|
-
query = { "include"=>"test1,test2"}
|
294
|
-
@generic_dal.get_includes(query).should eq ['test1','test2']
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
describe '#get_excludes' do
|
299
|
-
before(:each) do
|
300
|
-
@generic_dal.fields = {
|
301
|
-
"test1" => { :type=>:string },
|
302
|
-
"test2" => { :type=>:string },
|
303
|
-
"testX" => { :type=>:string },
|
304
|
-
}
|
305
|
-
end
|
306
|
-
|
307
|
-
it 'should return an empty array with a nil query' do
|
308
|
-
@generic_dal.get_excludes(nil).should eq []
|
309
|
-
end
|
310
|
-
|
311
|
-
it 'should return an empty array with no fields or excludes' do
|
312
|
-
query = { }
|
313
|
-
@generic_dal.get_excludes(query).should eq []
|
314
|
-
end
|
315
|
-
|
316
|
-
it 'should return an empty array with fields and no excludes' do
|
317
|
-
query = { "field2" => "xxas"}
|
318
|
-
@generic_dal.get_excludes(query).should eq []
|
319
|
-
end
|
320
|
-
|
321
|
-
it 'should return a single exclude' do
|
322
|
-
query = { "exclude"=>"test1", "field2" => "xxas"}
|
323
|
-
@generic_dal.get_excludes(query).should eq ['test1']
|
324
|
-
end
|
325
|
-
|
326
|
-
it 'should return multiple excludes' do
|
327
|
-
query = { "exclude"=>"test1,test2"}
|
328
|
-
@generic_dal.get_excludes(query).should eq ['test1','test2']
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
describe '#build_equal_condition' do
|
333
|
-
it 'should return IS NULL for a nil' do
|
334
|
-
@generic_dal.build_equal_condition(nil).should eq 'IS NULL'
|
335
|
-
end
|
336
|
-
|
337
|
-
it 'should return correct response for an integer' do
|
338
|
-
@generic_dal.build_equal_condition(1).should eq '= 1'
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'should return correct response for a float' do
|
342
|
-
@generic_dal.build_equal_condition(1.123).should eq '= 1.123'
|
343
|
-
end
|
344
|
-
|
345
|
-
it 'should return correct response for a string' do
|
346
|
-
@generic_dal.build_equal_condition('ABC').should eq "= 'ABC'"
|
347
|
-
end
|
348
|
-
|
349
|
-
it 'should return correct escaped response for a string' do
|
350
|
-
@generic_dal.build_equal_condition("AB'; DROP TABLE test_table --").should eq "= 'AB\\'; DROP TABLE test_table --'"
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
describe '#valid_query?' do
|
355
|
-
before(:each) do
|
356
|
-
@generic_dal.fields = {
|
357
|
-
"one" => { :type=>:string },
|
358
|
-
"two" => { :type=>:string },
|
359
|
-
"three" => { :type=>:string },
|
360
|
-
}
|
361
|
-
@generic_dal.relations = {
|
362
|
-
"four" => { :type=>:string },
|
363
|
-
"five" => { :type=>:string },
|
364
|
-
"six" => { :type=>:string },
|
365
|
-
}
|
366
|
-
end
|
367
|
-
|
368
|
-
it 'should return true with valid fields' do
|
369
|
-
@generic_dal.valid_query?({"one"=>1}).should be true
|
370
|
-
end
|
371
|
-
|
372
|
-
it 'should return false with invalid fields' do
|
373
|
-
@generic_dal.valid_query?({"five"=>1}).should be false
|
374
|
-
end
|
375
|
-
|
376
|
-
it 'should return true with valid relations' do
|
377
|
-
@generic_dal.valid_query?({"include"=>'four,five'}).should be true
|
378
|
-
end
|
379
|
-
|
380
|
-
it 'should return false with invalid relations' do
|
381
|
-
@generic_dal.valid_query?({"include"=>'ten'}).should be false
|
382
|
-
end
|
383
|
-
|
384
|
-
it 'should return false with nil' do
|
385
|
-
@generic_dal.valid_query?(nil).should be false
|
386
|
-
end
|
387
|
-
|
388
|
-
it 'should return true with no fields' do
|
389
|
-
@generic_dal.valid_query?({}).should be true
|
390
|
-
end
|
391
|
-
|
392
|
-
it 'should return true regardless of include' do
|
393
|
-
@generic_dal.valid_query?({"one"=>1,"include"=>"two"}).should be true
|
394
|
-
end
|
395
|
-
|
396
|
-
it 'should return true regardless of exclude' do
|
397
|
-
@generic_dal.valid_query?({"one"=>1,"exclude"=>"one"}).should be true
|
398
|
-
end
|
399
|
-
|
400
|
-
it 'should return false as cannot exclude a relation' do
|
401
|
-
@generic_dal.valid_query?({"one"=>1,"exclude"=>"five"}).should be false
|
402
|
-
end
|
403
|
-
end
|
404
|
-
|
405
|
-
describe '#escape_str_field' do
|
406
|
-
it 'should escape single quotes' do
|
407
|
-
@generic_dal.escape_str_field("ABC'BC").should eq "ABC\\'BC"
|
408
|
-
end
|
409
|
-
|
410
|
-
it 'should remove backtics' do
|
411
|
-
@generic_dal.escape_str_field("ABC`BC").should eq "ABCBC"
|
412
|
-
end
|
413
|
-
|
414
|
-
it 'should resolve symbols as well as strings' do
|
415
|
-
@generic_dal.escape_str_field(:testing).should eq "testing"
|
416
|
-
end
|
417
|
-
end
|
418
|
-
|
419
|
-
describe '#get_all_by_query' do
|
420
|
-
it 'should call cached_query with the correct query for one field' do
|
421
|
-
memcache_null(@mock_memcache)
|
422
|
-
@generic_dal.fields = {
|
423
|
-
"one" => { :type=>:string },
|
424
|
-
"two" => { :type=>:string },
|
425
|
-
}
|
426
|
-
@generic_dal.table_name = 'test_table'
|
427
|
-
|
428
|
-
@mock_mysql.should_receive(:query).with("SELECT `one`,`two` FROM `test_table` WHERE (`field` = 'test2')")
|
429
|
-
|
430
|
-
@generic_dal.get_all_by_query({ :field => 'test2' })
|
431
|
-
end
|
432
|
-
|
433
|
-
it 'should call cached_query with the correct query for multiple fields' do
|
434
|
-
memcache_null(@mock_memcache)
|
435
|
-
@generic_dal.fields = {
|
436
|
-
"one" => { :type=>:string },
|
437
|
-
"two" => { :type=>:string },
|
438
|
-
}
|
439
|
-
@generic_dal.table_name = 'test_table'
|
440
|
-
|
441
|
-
@mock_mysql.should_receive(:query).with("SELECT `one`,`two` FROM `test_table` WHERE (`field` = 'test2') AND (`twofield` = 2) AND (`nullfield` IS NULL)")
|
442
|
-
|
443
|
-
@generic_dal.get_all_by_query({ :field => 'test2', "twofield" =>2, "nullfield" => nil })
|
444
|
-
end
|
445
|
-
end
|
446
|
-
|
447
|
-
describe '#get_last_id' do
|
448
|
-
it 'should call mysql last_id' do
|
449
|
-
@mock_mysql.should_receive(:last_id)
|
450
|
-
@generic_dal.get_last_id
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
describe '#get_one' do
|
455
|
-
before(:each) do
|
456
|
-
memcache_null(@mock_memcache)
|
457
|
-
|
458
|
-
@generic_dal.fields = {
|
459
|
-
"one" => { :type=>:string },
|
460
|
-
"two" => { :type=>:string },
|
461
|
-
}
|
462
|
-
|
463
|
-
@generic_dal.table_name = 'test_table'
|
464
|
-
|
465
|
-
@mock_result = mysql_result_mock([
|
466
|
-
{ "field_one" => "one" },
|
467
|
-
{ "field_one" => "two" }
|
468
|
-
])
|
469
|
-
end
|
470
|
-
|
471
|
-
it 'should call cached_query with the correct query for one field and return a single object' do
|
472
|
-
@mock_mysql.should_receive(:query)
|
473
|
-
.with("SELECT `one`,`two` FROM `test_table` WHERE (`field` = 'test2')")
|
474
|
-
.and_return(@mock_result)
|
475
|
-
|
476
|
-
@generic_dal.get_one({ :field => 'test2' }).should eq({ "field_one" => "one" })
|
477
|
-
end
|
478
|
-
|
479
|
-
it 'should call cached_query with the correct query for one field and return a single object' do
|
480
|
-
@mock_mysql.should_receive(:query)
|
481
|
-
.with("SELECT `one`,`two` FROM `test_table` WHERE (`field` = 'test2') AND (`field_two` = 'test3')")
|
482
|
-
.and_return(@mock_result)
|
483
|
-
|
484
|
-
@generic_dal.get_one({ :field => 'test2', :field_two => 'test3' }).should eq({ "field_one" => "one" })
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
describe '#map_to_hash_by_primary_key' do
|
489
|
-
before(:each) do
|
490
|
-
@generic_dal.primary_key = 'id'
|
491
|
-
end
|
492
|
-
|
493
|
-
it 'should return an empty hash when given an empty array' do
|
494
|
-
test = []
|
495
|
-
|
496
|
-
@generic_dal.map_to_hash_by_primary_key(test).should eq({})
|
497
|
-
end
|
498
|
-
|
499
|
-
it 'should correctly map an array' do
|
500
|
-
test = [
|
501
|
-
{ "id" => 1, "field_one" => "one" },
|
502
|
-
{ "id" => 2.5, "field_one" => "two point five" },
|
503
|
-
{ "id" => "3", "field_one" => "three" },
|
504
|
-
{ "id" => nil, "field_one" => "four" }
|
505
|
-
]
|
506
|
-
|
507
|
-
@generic_dal.map_to_hash_by_primary_key(test).should eq({
|
508
|
-
1 => { "id" => 1, "field_one" => "one" },
|
509
|
-
2.5 => { "id" => 2.5, "field_one" => "two point five" },
|
510
|
-
"3" => { "id" => "3", "field_one" => "three" },
|
511
|
-
nil => { "id" => nil, "field_one" => "four" }
|
512
|
-
})
|
513
|
-
end
|
514
|
-
end
|
515
|
-
|
516
|
-
describe '#remove_key_from_hash_of_arrays!' do
|
517
|
-
|
518
|
-
it 'should remove a key from each hash in each array in each hash value' do
|
519
|
-
|
520
|
-
test = {
|
521
|
-
'one' => [ ],
|
522
|
-
2 => [ {"x" => 'a', "y" => 'b', 'z' => 'c' } ],
|
523
|
-
nil => [ {"x" => 'd', "y" => 'e', 'z' => 'f' }, {"x" => 'g', "y" => 'h', 'z' => 'i' } ],
|
524
|
-
}
|
525
|
-
|
526
|
-
@generic_dal.remove_key_from_hash_of_arrays!(test,'z')
|
527
|
-
|
528
|
-
test.should eq({
|
529
|
-
'one' => [ ],
|
530
|
-
2 => [ {"x" => 'a', "y" => 'b'} ],
|
531
|
-
nil => [ {"x" => 'd', "y" => 'e' }, {"x" => 'g', "y" => 'h' } ],
|
532
|
-
})
|
533
|
-
|
534
|
-
end
|
535
|
-
end
|
536
|
-
|
537
|
-
describe '#map_to_hash_of_arrays_by_key' do
|
538
|
-
it 'should return an empty hash when given an empty array' do
|
539
|
-
test = []
|
540
|
-
|
541
|
-
@generic_dal.map_to_hash_of_arrays_by_key(test,'field_one').should eq({})
|
542
|
-
end
|
543
|
-
|
544
|
-
it 'should correctly map an array' do
|
545
|
-
test = [
|
546
|
-
{ "id" => 1, "field_one" => 1 },
|
547
|
-
{ "id" => 2.5, "field_one" => "two point five" },
|
548
|
-
{ "id" => "3", "field_one" => "three" },
|
549
|
-
{ "id" => nil, "field_one" => 4.5 },
|
550
|
-
{ "id" => nil, "field_one" => 1 },
|
551
|
-
{ "id" => 90, "field_one" => "two point five" },
|
552
|
-
{ "id" => nil, "field_one" => "four" },
|
553
|
-
{ "id" => "16", "field_one" => "three" },
|
554
|
-
{ "id" => 2.1, "field_one" => 4.5 },
|
555
|
-
{ "id" => 328, "field_one" => "one" },
|
556
|
-
{ "id" => nil, "field_one" => nil },
|
557
|
-
{ "id" => 123, "field_one" => nil },
|
558
|
-
]
|
559
|
-
|
560
|
-
@generic_dal.map_to_hash_of_arrays_by_key(test,'field_one').should eq({
|
561
|
-
nil => [
|
562
|
-
{ "id" => nil, "field_one" => nil },
|
563
|
-
{ "id" => 123, "field_one" => nil },
|
564
|
-
],
|
565
|
-
1 => [
|
566
|
-
{ "id" => 1, "field_one" => 1 },
|
567
|
-
{ "id" => nil, "field_one" => 1 },
|
568
|
-
],
|
569
|
-
"two point five" => [
|
570
|
-
{ "id" => 2.5, "field_one" => "two point five" },
|
571
|
-
{ "id" => 90, "field_one" => "two point five" },
|
572
|
-
],
|
573
|
-
"three" => [
|
574
|
-
{ "id" => "3", "field_one" => "three" },
|
575
|
-
{ "id" => "16", "field_one" => "three" },
|
576
|
-
],
|
577
|
-
"four" => [
|
578
|
-
{ "id" => nil, "field_one" => "four" },
|
579
|
-
],
|
580
|
-
4.5 => [
|
581
|
-
{ "id" => nil, "field_one" => 4.5 },
|
582
|
-
{ "id" => 2.1, "field_one" => 4.5 },
|
583
|
-
],
|
584
|
-
"one" => [
|
585
|
-
{ "id" => 328, "field_one" => "one" },
|
586
|
-
]
|
587
|
-
})
|
588
|
-
end
|
589
|
-
end
|
590
|
-
|
591
|
-
describe '#add_field_from_map!' do
|
592
|
-
it 'should map correctly' do
|
593
|
-
records = [
|
594
|
-
{"id"=>1, "fk_code"=>"EU", "name"=>"Test1" },
|
595
|
-
{"id"=>2, "fk_code"=>"EU", "name"=>"Test2" },
|
596
|
-
{"id"=>3, "fk_code"=>"AU", "name"=>"Test3" },
|
597
|
-
{"id"=>4, "fk_code"=>"GB", "name"=>"Test4" },
|
598
|
-
{"id"=>5, "fk_code"=>"US", "name"=>"Test5" },
|
599
|
-
{"id"=>6, "fk_code"=>nil, "name"=>"Test5" },
|
600
|
-
]
|
601
|
-
|
602
|
-
map = {
|
603
|
-
'EU' => 1,
|
604
|
-
'AU' => { "name"=>"one" },
|
605
|
-
'US' => nil,
|
606
|
-
'GB' => "test!"
|
607
|
-
}
|
608
|
-
|
609
|
-
@generic_dal.add_field_from_map!(records, map, 'fk_field', 'fk_code')
|
610
|
-
|
611
|
-
records.should eq [
|
612
|
-
{"id"=>1, "fk_code"=>"EU", "name"=>"Test1", "fk_field"=>1 },
|
613
|
-
{"id"=>2, "fk_code"=>"EU", "name"=>"Test2", "fk_field"=>1 },
|
614
|
-
{"id"=>3, "fk_code"=>"AU", "name"=>"Test3", "fk_field"=>{ "name"=>"one" } },
|
615
|
-
{"id"=>4, "fk_code"=>"GB", "name"=>"Test4", "fk_field"=>"test!" },
|
616
|
-
{"id"=>5, "fk_code"=>"US", "name"=>"Test5", "fk_field"=>nil },
|
617
|
-
{"id"=>6, "fk_code"=>nil, "name"=>"Test5" },
|
618
|
-
]
|
619
|
-
|
620
|
-
end
|
621
|
-
end
|
622
|
-
|
623
|
-
describe '#get_relation_query_sql' do
|
624
|
-
it 'should return the correct sql for a has_one relation with no query' do
|
625
|
-
|
626
|
-
@generic_dal.table_name = "currencies"
|
627
|
-
|
628
|
-
rel = {
|
629
|
-
:type => :has_one,
|
630
|
-
:table => 'countries',
|
631
|
-
:table_key => 'default_currency_code',
|
632
|
-
:this_key => 'code',
|
633
|
-
:table_fields => 'code_alpha_2,name',
|
634
|
-
}
|
635
|
-
|
636
|
-
@generic_dal.get_relation_query_sql(rel,{}).should eq(
|
637
|
-
"SELECT `a`.`code_alpha_2`,`a`.`name`,`b`.`code` AS `_table_key` FROM `countries` AS `a`, `currencies` AS `b` WHERE (`a`.`default_currency_code` = `b`.`code`)"
|
638
|
-
)
|
639
|
-
|
640
|
-
end
|
641
|
-
|
642
|
-
it 'should return the correct sql for a has_one relation with a query' do
|
643
|
-
|
644
|
-
@generic_dal.table_name = "currencies"
|
645
|
-
|
646
|
-
rel = {
|
647
|
-
:type => :has_one,
|
648
|
-
:table => 'countries',
|
649
|
-
:table_key => 'default_currency_code',
|
650
|
-
:this_key => 'code',
|
651
|
-
:table_fields => 'code_alpha_2,name',
|
652
|
-
}
|
653
|
-
|
654
|
-
@generic_dal.get_relation_query_sql(rel,{'testfield'=>1}).should eq(
|
655
|
-
"SELECT `a`.`code_alpha_2`,`a`.`name`,`b`.`code` AS `_table_key` FROM `countries` AS `a`, `currencies` AS `b` WHERE (`a`.`default_currency_code` = `b`.`code`) AND (`b`.`testfield` = 1)"
|
656
|
-
)
|
657
|
-
|
658
|
-
end
|
659
|
-
|
660
|
-
it 'should return the correct sql for a has_many relation' do
|
661
|
-
|
662
|
-
@generic_dal.table_name = "houses"
|
663
|
-
|
664
|
-
rel = {
|
665
|
-
:type => :has_many,
|
666
|
-
:table => 'cats',
|
667
|
-
:table_key => 'house_id',
|
668
|
-
:this_key => 'id',
|
669
|
-
:table_fields => 'cat_id,name',
|
670
|
-
}
|
671
|
-
|
672
|
-
@generic_dal.get_relation_query_sql(rel,{}).should eq(
|
673
|
-
"SELECT `a`.`cat_id`,`a`.`name`,`b`.`id` AS `_table_key` FROM `cats` AS `a`, `houses` AS `b` WHERE (`a`.`house_id` = `b`.`id`)"
|
674
|
-
)
|
675
|
-
|
676
|
-
end
|
677
|
-
|
678
|
-
it 'should return the correct sql for a has_many relation with a query' do
|
679
|
-
|
680
|
-
@generic_dal.table_name = "houses"
|
681
|
-
|
682
|
-
rel = {
|
683
|
-
:type => :has_many,
|
684
|
-
:table => 'cats',
|
685
|
-
:table_key => 'house_id',
|
686
|
-
:this_key => 'id',
|
687
|
-
:table_fields => 'cat_id,name',
|
688
|
-
}
|
689
|
-
|
690
|
-
@generic_dal.get_relation_query_sql(rel,{"colour"=>"ginger"}).should eq(
|
691
|
-
"SELECT `a`.`cat_id`,`a`.`name`,`b`.`id` AS `_table_key` FROM `cats` AS `a`, `houses` AS `b` WHERE (`a`.`house_id` = `b`.`id`) AND (`b`.`colour` = 'ginger')"
|
692
|
-
)
|
693
|
-
|
694
|
-
end
|
695
|
-
|
696
|
-
it 'should return the correct sql for a has_many_through relation' do
|
697
|
-
|
698
|
-
@generic_dal.table_name = "countries"
|
699
|
-
|
700
|
-
rel = {
|
701
|
-
:type => :has_many_through,
|
702
|
-
:table => 'regions',
|
703
|
-
:link_table => 'region_countries',
|
704
|
-
:link_key => 'country_code_alpha_2',
|
705
|
-
:link_field => 'region_code',
|
706
|
-
:table_key => 'code',
|
707
|
-
:this_key => 'code_alpha_2',
|
708
|
-
:table_fields => 'code,name',
|
709
|
-
}
|
710
|
-
|
711
|
-
@generic_dal.get_relation_query_sql(rel,{}).should eq(
|
712
|
-
"SELECT `a`.`code`,`a`.`name`,`c`.`code_alpha_2` AS `_table_key` FROM `regions` AS `a`, `region_countries` AS `b`, `countries` AS `c` WHERE (`a`.`code` = `b`.`region_code` AND `b`.`country_code_alpha_2` = `c`.`code_alpha_2`)"
|
713
|
-
)
|
714
|
-
|
715
|
-
end
|
716
|
-
|
717
|
-
it 'should return the correct sql for a has_many_through relation with a query' do
|
718
|
-
|
719
|
-
@generic_dal.table_name = "countries"
|
720
|
-
|
721
|
-
rel = {
|
722
|
-
:type => :has_many_through,
|
723
|
-
:table => 'regions',
|
724
|
-
:link_table => 'region_countries',
|
725
|
-
:link_key => 'country_code_alpha_2',
|
726
|
-
:link_field => 'region_code',
|
727
|
-
:table_key => 'code',
|
728
|
-
:this_key => 'code_alpha_2',
|
729
|
-
:table_fields => 'code,name',
|
730
|
-
}
|
731
|
-
|
732
|
-
@generic_dal.get_relation_query_sql(rel,{"default_currency_code"=>"EUR"}).should eq(
|
733
|
-
"SELECT `a`.`code`,`a`.`name`,`c`.`code_alpha_2` AS `_table_key` FROM `regions` AS `a`, `region_countries` AS `b`, `countries` AS `c` WHERE (`a`.`code` = `b`.`region_code` AND `b`.`country_code_alpha_2` = `c`.`code_alpha_2`) AND (`c`.`default_currency_code` = 'EUR')"
|
734
|
-
)
|
735
|
-
|
736
|
-
end
|
737
|
-
end
|
738
|
-
|
739
|
-
describe "#get_relation_tables" do
|
740
|
-
it 'should return the correct tables for a has_one relation' do
|
741
|
-
@generic_dal.table_name = "currencies"
|
742
|
-
|
743
|
-
rel = {
|
744
|
-
:type => :has_one,
|
745
|
-
:table => 'countries',
|
746
|
-
:table_key => 'default_currency_code',
|
747
|
-
:this_key => 'code',
|
748
|
-
:table_fields => 'code_alpha_2,name',
|
749
|
-
}
|
750
|
-
|
751
|
-
@generic_dal.get_relation_tables(rel).should eq(["countries", "currencies"])
|
752
|
-
end
|
753
|
-
|
754
|
-
it 'should return the correct tables for a has_many relation' do
|
755
|
-
@generic_dal.table_name = "houses"
|
756
|
-
|
757
|
-
rel = {
|
758
|
-
:type => :has_many,
|
759
|
-
:table => 'cats',
|
760
|
-
:table_key => 'house_id',
|
761
|
-
:this_key => 'id',
|
762
|
-
:table_fields => 'cat_id,name',
|
763
|
-
}
|
764
|
-
|
765
|
-
@generic_dal.get_relation_tables(rel).should eq(["cats", "houses"])
|
766
|
-
end
|
767
|
-
|
768
|
-
it 'should return the correct tables for a has_many_through relation' do
|
769
|
-
@generic_dal.table_name = "countries"
|
770
|
-
|
771
|
-
rel = {
|
772
|
-
:type => :has_many_through,
|
773
|
-
:table => 'regions',
|
774
|
-
:link_table => 'region_countries',
|
775
|
-
:link_key => 'country_code_alpha_2',
|
776
|
-
:link_field => 'region_code',
|
777
|
-
:table_key => 'code',
|
778
|
-
:this_key => 'code_alpha_2',
|
779
|
-
:table_fields => 'code,name',
|
780
|
-
}
|
781
|
-
|
782
|
-
@generic_dal.get_relation_tables(rel).should eq(["countries","region_countries","regions"])
|
783
|
-
end
|
784
|
-
end
|
785
|
-
|
786
|
-
describe '#expire_table_cache' do
|
787
|
-
it 'should set a table version when it doesnt exist' do
|
788
|
-
|
789
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(nil)
|
790
|
-
@mock_memcache.should_receive(:set).ordered.with("prefix-testtable-version",1,nil,{:raw=>true}).and_return(nil)
|
791
|
-
|
792
|
-
@generic_dal.expire_table_cache(['testtable'])
|
793
|
-
end
|
794
|
-
|
795
|
-
it 'should increment a table version when it exists' do
|
796
|
-
|
797
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(1)
|
798
|
-
@mock_memcache.should_receive(:incr).ordered.with("prefix-testtable-version",1,nil).and_return(nil)
|
799
|
-
|
800
|
-
@generic_dal.expire_table_cache(['testtable'])
|
801
|
-
end
|
802
|
-
|
803
|
-
it 'should expire multiple tables' do
|
804
|
-
|
805
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-testtable-version").and_return(1)
|
806
|
-
@mock_memcache.should_receive(:incr).ordered.with("prefix-testtable-version",1,nil).and_return(nil)
|
807
|
-
@mock_memcache.should_receive(:get).ordered.with("prefix-tabletwo-version").and_return(1)
|
808
|
-
@mock_memcache.should_receive(:incr).ordered.with("prefix-tabletwo-version",1,nil).and_return(nil)
|
809
|
-
|
810
|
-
@generic_dal.expire_table_cache(['testtable','tabletwo'])
|
811
|
-
end
|
812
|
-
end
|
813
|
-
|
814
|
-
describe '#exists_by_primary_key?' do
|
815
|
-
before do
|
816
|
-
memcache_null(@mock_memcache)
|
817
|
-
|
818
|
-
@generic_dal.table_name = 'pktesttable'
|
819
|
-
@generic_dal.primary_key = 'id'
|
820
|
-
|
821
|
-
@mock_result = mysql_result_mock([ { "c" => 1 } ])
|
822
|
-
end
|
823
|
-
|
824
|
-
it 'should call cached_query with correct sql with a numeric primary key' do
|
825
|
-
@mock_mysql.should_receive(:query).with("SELECT COUNT(*) AS `c` FROM `pktesttable` WHERE (`id` = 2002)").and_return(@mock_result)
|
826
|
-
|
827
|
-
@generic_dal.exists_by_primary_key?(2002).should eq(true)
|
828
|
-
end
|
829
|
-
|
830
|
-
it 'should call cached_query with correct sql with a string primary key' do
|
831
|
-
@mock_mysql.should_receive(:query).with("SELECT COUNT(*) AS `c` FROM `pktesttable` WHERE (`id` = 'test')").and_return(@mock_result)
|
832
|
-
|
833
|
-
@generic_dal.exists_by_primary_key?('test').should eq(true)
|
834
|
-
end
|
835
|
-
|
836
|
-
it 'should return true when count is not 0' do
|
837
|
-
@mock_result = mysql_result_mock([ { "c" => 1 } ])
|
838
|
-
|
839
|
-
@mock_mysql.should_receive(:query).with("SELECT COUNT(*) AS `c` FROM `pktesttable` WHERE (`id` = 'test')").and_return(@mock_result)
|
840
|
-
|
841
|
-
@generic_dal.exists_by_primary_key?('test').should eq(true)
|
842
|
-
end
|
843
|
-
|
844
|
-
it 'should return false when count is 0' do
|
845
|
-
@mock_result = mysql_result_mock([ { "c" => 0 } ])
|
846
|
-
|
847
|
-
@mock_mysql.should_receive(:query).with("SELECT COUNT(*) AS `c` FROM `pktesttable` WHERE (`id` = 'test')").and_return(@mock_result)
|
848
|
-
|
849
|
-
@generic_dal.exists_by_primary_key?('test').should eq(false)
|
850
|
-
end
|
851
|
-
end
|
852
|
-
|
853
|
-
describe '#valid_insert?' do
|
854
|
-
it 'should return false if object nil' do
|
855
|
-
@generic_dal.valid_insert?(nil).should eq(false)
|
856
|
-
end
|
857
|
-
|
858
|
-
it 'should return false if object empty' do
|
859
|
-
@generic_dal.valid_insert?({}).should eq(false)
|
860
|
-
end
|
861
|
-
|
862
|
-
it 'should return true if all fields exist' do
|
863
|
-
@generic_dal.fields = {
|
864
|
-
"one" => { :type=>:string },
|
865
|
-
"two" => { :type=>:string },
|
866
|
-
}
|
867
|
-
|
868
|
-
@generic_dal.valid_insert?({ "one"=>"1", "two"=>"2" }).should eq(true)
|
869
|
-
end
|
870
|
-
|
871
|
-
it 'should return false if fields do not exist' do
|
872
|
-
@generic_dal.fields = {
|
873
|
-
"one" => { :type=>:string },
|
874
|
-
"two" => { :type=>:string },
|
875
|
-
}
|
876
|
-
|
877
|
-
@generic_dal.valid_insert?({ "five"=>"1", "two"=>"2" }).should eq(false)
|
878
|
-
end
|
879
|
-
|
880
|
-
it 'should return true if data is within the max length' do
|
881
|
-
@generic_dal.fields = {
|
882
|
-
"one" => { :type=>:string },
|
883
|
-
"two" => { :type=>:string, :length=>4 },
|
884
|
-
}
|
885
|
-
|
886
|
-
@generic_dal.valid_insert?({ "one"=>"1", "two"=>"2" }).should eq(true)
|
887
|
-
end
|
888
|
-
|
889
|
-
it 'should return false if data is greater than the max length' do
|
890
|
-
@generic_dal.fields = {
|
891
|
-
"one" => { :type=>:string },
|
892
|
-
"two" => { :type=>:string, :length=>4 },
|
893
|
-
}
|
894
|
-
|
895
|
-
@generic_dal.valid_insert?({ "one"=>"1", "two"=>"22332" }).should eq(false)
|
896
|
-
end
|
897
|
-
|
898
|
-
it 'should return false if required key is missing' do
|
899
|
-
@generic_dal.fields = {
|
900
|
-
"one" => { :type=>:string },
|
901
|
-
"two" => { :type=>:string, :required=>true },
|
902
|
-
}
|
903
|
-
|
904
|
-
@generic_dal.valid_insert?({ "one"=>"1" }).should eq(false)
|
905
|
-
end
|
906
|
-
|
907
|
-
it 'should return true if required keys are ok' do
|
908
|
-
@generic_dal.fields = {
|
909
|
-
"one" => { :type=>:string, :required=>true },
|
910
|
-
"two" => { :type=>:string, :required=>true },
|
911
|
-
}
|
912
|
-
|
913
|
-
@generic_dal.valid_insert?({ "one"=>"1","two"=>"2" }).should eq(true)
|
914
|
-
end
|
915
|
-
end
|
916
|
-
|
917
|
-
describe '#valid_update?' do
|
918
|
-
it 'should return false if object nil' do
|
919
|
-
@generic_dal.valid_update?(nil).should eq(false)
|
920
|
-
end
|
921
|
-
|
922
|
-
it 'should return false if object empty' do
|
923
|
-
@generic_dal.valid_update?({}).should eq(false)
|
924
|
-
end
|
925
|
-
|
926
|
-
it 'should return true if all fields exist' do
|
927
|
-
@generic_dal.fields = {
|
928
|
-
"one" => { :type=>:string },
|
929
|
-
"two" => { :type=>:string },
|
930
|
-
}
|
931
|
-
|
932
|
-
@generic_dal.valid_update?({ "one"=>"1", "two"=>"2" }).should eq(true)
|
933
|
-
end
|
934
|
-
|
935
|
-
it 'should return false if fields do not exist' do
|
936
|
-
@generic_dal.fields = {
|
937
|
-
"one" => { :type=>:string },
|
938
|
-
"two" => { :type=>:string },
|
939
|
-
}
|
940
|
-
|
941
|
-
@generic_dal.valid_update?({ "five"=>"1", "two"=>"2" }).should eq(false)
|
942
|
-
end
|
943
|
-
|
944
|
-
it 'should return false if data is greater than the max length' do
|
945
|
-
@generic_dal.fields = {
|
946
|
-
"one" => { :type=>:string },
|
947
|
-
"two" => { :type=>:string, :length=>4 },
|
948
|
-
}
|
949
|
-
|
950
|
-
@generic_dal.valid_update?({ "one"=>"1", "two"=>"22332" }).should eq(false)
|
951
|
-
end
|
952
|
-
end
|
953
|
-
|
954
|
-
describe "#escape_value" do
|
955
|
-
it 'should return NULL for nil' do
|
956
|
-
@generic_dal.escape_value(nil).should eq('NULL')
|
957
|
-
end
|
958
|
-
|
959
|
-
it 'should return integer for int/float' do
|
960
|
-
@generic_dal.escape_value(1).should eq('1')
|
961
|
-
@generic_dal.escape_value(1.45).should eq('1.45')
|
962
|
-
end
|
963
|
-
|
964
|
-
it 'should return a quoted string for string' do
|
965
|
-
@generic_dal.escape_value('test').should eq("'test'")
|
966
|
-
end
|
967
|
-
|
968
|
-
it 'should escape sql values properly' do
|
969
|
-
@generic_dal.escape_value("test '; DROP TABLE test; --").should eq("'test \\'; DROP TABLE test; --'")
|
970
|
-
end
|
971
|
-
end
|
972
|
-
|
973
|
-
describe "#build_insert" do
|
974
|
-
it 'should return correct SQL fragment for basic fields' do
|
975
|
-
data = {
|
976
|
-
"one" => 1,
|
977
|
-
"two" => "2",
|
978
|
-
"three" => nil,
|
979
|
-
}
|
980
|
-
|
981
|
-
@generic_dal.build_insert(data).should eq("(`one`, `two`, `three`) VALUES (1, '2', NULL)")
|
982
|
-
end
|
983
|
-
|
984
|
-
it 'should escape field names and data' do
|
985
|
-
data = {
|
986
|
-
"one`; DROP TABLE test; -- " => 1,
|
987
|
-
"two" => "two",
|
988
|
-
"three" => "'; DROP TABLE test; --'",
|
989
|
-
}
|
990
|
-
|
991
|
-
@generic_dal.build_insert(data).should eq("(`one; DROP TABLE test; -- `, `two`, `three`) VALUES (1, 'two', '\\'; DROP TABLE test; --\\'')")
|
992
|
-
end
|
993
|
-
end
|
994
|
-
|
995
|
-
describe "#build_update" do
|
996
|
-
it 'should return correct SQL fragment for basic fields' do
|
997
|
-
data = {
|
998
|
-
"one" => 1,
|
999
|
-
"two" => "two",
|
1000
|
-
"three" => nil,
|
1001
|
-
}
|
1002
|
-
|
1003
|
-
@generic_dal.build_update(data).should eq("`one` = 1, `two` = 'two', `three` = NULL")
|
1004
|
-
end
|
1005
|
-
|
1006
|
-
it 'should escape field names and data' do
|
1007
|
-
data = {
|
1008
|
-
"one`; DROP TABLE test; -- " => 1,
|
1009
|
-
"two" => "2",
|
1010
|
-
"three" => "'; DROP TABLE test; --'",
|
1011
|
-
}
|
1012
|
-
|
1013
|
-
@generic_dal.build_update(data).should eq("`one; DROP TABLE test; -- ` = 1, `two` = '2', `three` = '\\'; DROP TABLE test; --\\''")
|
1014
|
-
end
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
describe "#get_all_related_tables" do
|
1018
|
-
it 'should return the table name for nil relations' do
|
1019
|
-
@generic_dal.table_name = 'test1'
|
1020
|
-
|
1021
|
-
@generic_dal.relations = nil
|
1022
|
-
|
1023
|
-
@generic_dal.get_all_related_tables.should eq(["test1"])
|
1024
|
-
end
|
1025
|
-
|
1026
|
-
it 'should return the table name for empty relations' do
|
1027
|
-
@generic_dal.table_name = 'test1'
|
1028
|
-
|
1029
|
-
@generic_dal.relations = {}
|
1030
|
-
|
1031
|
-
@generic_dal.get_all_related_tables.should eq(["test1"])
|
1032
|
-
end
|
1033
|
-
|
1034
|
-
it 'should return the table name for a single relations' do
|
1035
|
-
@generic_dal.table_name = 'test1'
|
1036
|
-
|
1037
|
-
@generic_dal.relations = {
|
1038
|
-
'countries' => {
|
1039
|
-
:type => :has_one,
|
1040
|
-
:table => 'countries',
|
1041
|
-
:table_key => 'default_currency_code',
|
1042
|
-
:this_key => 'code',
|
1043
|
-
:table_fields => 'code_alpha_2,name',
|
1044
|
-
},
|
1045
|
-
}
|
1046
|
-
|
1047
|
-
@generic_dal.get_all_related_tables.should eq(["countries","test1"])
|
1048
|
-
end
|
1049
|
-
|
1050
|
-
|
1051
|
-
it 'should return the correct table names for multiple relations with dedupe' do
|
1052
|
-
@generic_dal.table_name = 'test1'
|
1053
|
-
|
1054
|
-
@generic_dal.relations = {
|
1055
|
-
'countries' => {
|
1056
|
-
:type => :has_one,
|
1057
|
-
:table => 'countries',
|
1058
|
-
:table_key => 'default_currency_code',
|
1059
|
-
:this_key => 'code',
|
1060
|
-
:table_fields => 'code_alpha_2,name',
|
1061
|
-
},
|
1062
|
-
'countries2' => {
|
1063
|
-
:type => :has_many,
|
1064
|
-
:table => 'countries',
|
1065
|
-
:table_key => 'default_currency_code',
|
1066
|
-
:this_key => 'code',
|
1067
|
-
:table_fields => 'code_alpha_2,name',
|
1068
|
-
},
|
1069
|
-
'regions' => {
|
1070
|
-
:type => :has_many_through,
|
1071
|
-
:table => 'regions',
|
1072
|
-
:link_table => 'region_countries',
|
1073
|
-
:link_key => 'country_code_alpha_2',
|
1074
|
-
:link_field => 'region_code',
|
1075
|
-
:table_key => 'code',
|
1076
|
-
:this_key => 'code_alpha_2',
|
1077
|
-
:table_fields => 'code,name',
|
1078
|
-
}
|
1079
|
-
}
|
1080
|
-
|
1081
|
-
@generic_dal.get_all_related_tables.should eq(["countries", "region_countries", "regions", "test1"])
|
1082
|
-
end
|
1083
|
-
end
|
1084
|
-
|
1085
|
-
describe '#insert' do
|
1086
|
-
it 'should call the correct sql and expire the correct cache' do
|
1087
|
-
testdata = { "field_one" => "one" }
|
1088
|
-
|
1089
|
-
@generic_dal.table_name = "test_table"
|
1090
|
-
@generic_dal.fields = {
|
1091
|
-
"field_one" => { :type => :integer }
|
1092
|
-
}
|
1093
|
-
@generic_dal.auto_primary_key = false
|
1094
|
-
|
1095
|
-
query = "INSERT INTO `test_table` (`field_one`) VALUES ('one')"
|
1096
|
-
|
1097
|
-
@mock_mysql.should_receive(:query).ordered.with(query)
|
1098
|
-
@mock_mysql.should_not_receive(:last_id)
|
1099
|
-
|
1100
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1101
|
-
@mock_memcache.should_receive(:incr).ordered.with('prefix-test_table-version',1,nil)
|
1102
|
-
|
1103
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1104
|
-
@mock_memcache.should_receive(:get).ordered.and_return([{ "field_one" => "one","id"=>1 }])
|
1105
|
-
|
1106
|
-
@generic_dal.insert(testdata)
|
1107
|
-
end
|
1108
|
-
|
1109
|
-
it 'should call last_id when auto_primary_key is true' do
|
1110
|
-
testdata = { "field_one" => "one" }
|
1111
|
-
|
1112
|
-
@generic_dal.table_name = "test_table"
|
1113
|
-
@generic_dal.fields = {
|
1114
|
-
"field_one" => { :type => :integer }
|
1115
|
-
}
|
1116
|
-
@generic_dal.auto_primary_key = true
|
1117
|
-
|
1118
|
-
query = "INSERT INTO `test_table` (`field_one`) VALUES ('one')"
|
1119
|
-
|
1120
|
-
@mock_mysql.should_receive(:query).ordered.with(query)
|
1121
|
-
@mock_mysql.should_receive(:last_id)
|
1122
|
-
|
1123
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1124
|
-
@mock_memcache.should_receive(:incr).ordered.with('prefix-test_table-version',1,nil)
|
1125
|
-
|
1126
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1127
|
-
@mock_memcache.should_receive(:get).ordered.and_return([{ "field_one" => "one","id"=>1 }])
|
1128
|
-
@mock_memcache.should_not_receive(:last_id)
|
1129
|
-
|
1130
|
-
@generic_dal.insert(testdata)
|
1131
|
-
end
|
1132
|
-
end
|
1133
|
-
|
1134
|
-
describe '#update_by_primary_key' do
|
1135
|
-
it 'should call the correct sql and expire the correct cache' do
|
1136
|
-
testdata = { "field_one" => "two" }
|
1137
|
-
|
1138
|
-
@generic_dal.table_name = "test_table"
|
1139
|
-
@generic_dal.primary_key = "code"
|
1140
|
-
@generic_dal.fields = {
|
1141
|
-
"field_one" => { :type => :integer }
|
1142
|
-
}
|
1143
|
-
|
1144
|
-
query = "UPDATE `test_table` SET `field_one` = 'two' WHERE (`code` = 2)"
|
1145
|
-
|
1146
|
-
@mock_mysql.should_receive(:query).ordered.with(query)
|
1147
|
-
|
1148
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1149
|
-
@mock_memcache.should_receive(:incr).ordered.with('prefix-test_table-version',1,nil)
|
1150
|
-
|
1151
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1152
|
-
@mock_memcache.should_receive(:get).ordered.and_return([{ "field_one" => "two","id"=>2}])
|
1153
|
-
|
1154
|
-
@generic_dal.update_by_primary_key(2, testdata)
|
1155
|
-
end
|
1156
|
-
end
|
1157
|
-
|
1158
|
-
describe '#delete_by_primary_key' do
|
1159
|
-
it 'should call the correct sql and expire the correct cache' do
|
1160
|
-
|
1161
|
-
@generic_dal.table_name = "test_table"
|
1162
|
-
@generic_dal.primary_key = "code"
|
1163
|
-
|
1164
|
-
query = "DELETE FROM `test_table` WHERE (`code` = 'three')"
|
1165
|
-
|
1166
|
-
@mock_mysql.should_receive(:query).ordered.with(query)
|
1167
|
-
@mock_memcache.should_receive(:get).ordered.with('prefix-test_table-version').and_return(1)
|
1168
|
-
@mock_memcache.should_receive(:incr).ordered.with('prefix-test_table-version',1,nil)
|
1169
|
-
|
1170
|
-
@generic_dal.delete_by_primary_key('three')
|
1171
|
-
end
|
1172
|
-
end
|
1173
|
-
|
1174
|
-
end
|