oklahoma_mixer 0.2.0 → 0.3.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/CHANGELOG.rdoc +7 -0
- data/README.rdoc +4 -0
- data/Rakefile +1 -1
- data/TODO.rdoc +2 -3
- data/lib/oklahoma_mixer.rb +7 -20
- data/lib/oklahoma_mixer/array_list.rb +21 -7
- data/lib/oklahoma_mixer/array_list/c.rb +9 -1
- data/lib/oklahoma_mixer/b_tree_database.rb +25 -9
- data/lib/oklahoma_mixer/b_tree_database/c.rb +5 -0
- data/lib/oklahoma_mixer/cursor.rb +3 -0
- data/lib/oklahoma_mixer/cursor/c.rb +2 -0
- data/lib/oklahoma_mixer/error.rb +2 -0
- data/lib/oklahoma_mixer/extensible_string.rb +4 -2
- data/lib/oklahoma_mixer/extensible_string/c.rb +2 -0
- data/lib/oklahoma_mixer/fixed_length_database.rb +11 -3
- data/lib/oklahoma_mixer/fixed_length_database/c.rb +2 -0
- data/lib/oklahoma_mixer/hash_database.rb +24 -7
- data/lib/oklahoma_mixer/hash_database/c.rb +2 -0
- data/lib/oklahoma_mixer/hash_map.rb +42 -0
- data/lib/oklahoma_mixer/hash_map/c.rb +27 -0
- data/lib/oklahoma_mixer/query.rb +73 -0
- data/lib/oklahoma_mixer/query/c.rb +51 -0
- data/lib/oklahoma_mixer/table_database.rb +402 -0
- data/lib/oklahoma_mixer/table_database/c.rb +104 -0
- data/lib/oklahoma_mixer/utilities.rb +26 -1
- data/test/{b_tree_binary_data_test.rb → b_tree_database/b_tree_binary_data_test.rb} +2 -2
- data/test/{b_tree_tuning_test.rb → b_tree_database/b_tree_tuning_test.rb} +2 -2
- data/test/{cursor_based_iteration_test.rb → b_tree_database/cursor_based_iteration_test.rb} +2 -2
- data/test/{duplicate_storage_test.rb → b_tree_database/duplicate_storage_test.rb} +18 -12
- data/test/{binary_data_test.rb → core_database/binary_data_test.rb} +2 -2
- data/test/{file_system_test.rb → core_database/file_system_test.rb} +0 -0
- data/test/{getting_and_setting_keys_test.rb → core_database/getting_and_setting_keys_test.rb} +31 -60
- data/test/{iteration_test.rb → core_database/iteration_test.rb} +2 -2
- data/test/{transactions_test.rb → core_database/transactions_test.rb} +0 -0
- data/test/core_database/tuning_test.rb +31 -0
- data/test/{fixed_length_tuning_test.rb → fixed_length_database/fixed_length_tuning_test.rb} +0 -0
- data/test/{getting_and_setting_by_id_test.rb → fixed_length_database/getting_and_setting_by_id_test.rb} +8 -0
- data/test/{shared_binary_data.rb → shared/binary_data_tests.rb} +1 -1
- data/test/{tuning_test.rb → shared/hash_tuning_tests.rb} +18 -42
- data/test/{shared_iteration.rb → shared/iteration_tests.rb} +8 -7
- data/test/{key_range_test.rb → shared/key_range_test.rb} +0 -0
- data/test/{order_test.rb → shared/order_test.rb} +0 -0
- data/test/shared/storage_tests.rb +65 -0
- data/test/{top_level_interface_test.rb → shared/top_level_interface_test.rb} +39 -2
- data/test/{shared_tuning.rb → shared/tuning_tests.rb} +1 -1
- data/test/table_database/document_iteration_test.rb +22 -0
- data/test/table_database/document_storage_test.rb +225 -0
- data/test/table_database/index_test.rb +57 -0
- data/test/table_database/query_test.rb +866 -0
- data/test/table_database/table_tuning_test.rb +56 -0
- data/test/test_helper.rb +27 -0
- metadata +35 -36
@@ -0,0 +1,57 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class TestIndex < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@db = tdb
|
6
|
+
end
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
@db.close
|
10
|
+
remove_db_files
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_an_index_can_be_added_to_a_column
|
14
|
+
assert(@db.add_index(:column, :string), "Index not added")
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_an_index_can_be_rebuilt_by_adding_it_again
|
18
|
+
2.times do
|
19
|
+
assert(@db.add_index(:column, :string), "Index not added")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_string_numeric_token_and_qgram_indexes_are_supported
|
24
|
+
%w[lexical string decimal numeric token qgram].each do |type|
|
25
|
+
assert(@db.add_index(type, type), "Index not added")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_an_unknown_index_type_fails_with_an_error
|
30
|
+
assert_raise(OKMixer::Error::IndexError) do
|
31
|
+
@db.add_index(:column, :unknown)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_adding_an_existing_index_with_keep_mode_returns_false
|
36
|
+
assert(@db.add_index(:column, :string), "Index not added")
|
37
|
+
assert(!@db.add_index(:column, :string, :keep), "Index readded")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_an_existing_index_can_be_removed
|
41
|
+
assert(@db.add_index(:column, :string), "Index not added")
|
42
|
+
assert(@db.remove_index(:column), "Index not removed")
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_removing_a_nonexisting_index_returns_false
|
46
|
+
assert(!@db.remove_index(:missing), "Index removed")
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_an_existing_index_can_be_optimized
|
50
|
+
assert(@db.add_index(:column, :string), "Index not added")
|
51
|
+
assert(@db.optimize_index(:column), "Index not optimized")
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_optimizing_a_nonexisting_index_returns_false
|
55
|
+
assert(!@db.optimize_index(:missing), "Index optimized")
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,866 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class TestQuery < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@db = tdb
|
6
|
+
end
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
@db.close
|
10
|
+
remove_db_files
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_all_returns_primary_key_and_document_by_default
|
14
|
+
load_simple_data
|
15
|
+
results = @db.all
|
16
|
+
assert_equal( [ ["pk1", {"a" => "1", "b" => "2", "c" => "3"}],
|
17
|
+
["pk2", { }] ], results.to_a.sort )
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_all_returns_primary_key_and_document_if_selected
|
21
|
+
load_simple_data
|
22
|
+
%w[ key_and_doc keys_and_docs
|
23
|
+
primary_key_and_doc primary_keys_and_docs ].each do |kad|
|
24
|
+
results = @db.all(:select => kad)
|
25
|
+
assert_equal( [ ["pk1", {"a" => "1", "b" => "2", "c" => "3"}],
|
26
|
+
["pk2", { }] ], results.to_a.sort )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_all_returns_primary_keys_only_if_selected
|
31
|
+
load_simple_data
|
32
|
+
%w[key keys primary_key primary_keys].each do |k|
|
33
|
+
results = @db.all(:select => k)
|
34
|
+
assert_equal(%w[pk1 pk2], results.sort)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_all_returns_documents_only_if_selected
|
39
|
+
load_simple_data
|
40
|
+
%w[doc docs document documents].each do |d|
|
41
|
+
results = @db.all(:select => d)
|
42
|
+
assert_equal( [{ }, {"a" => "1", "b" => "2", "c" => "3"}],
|
43
|
+
results.sort_by { |doc| doc.size } )
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_all_selects_a_return_data_type_by_ruby_version_and_ordering
|
48
|
+
load_simple_data
|
49
|
+
if RUBY_VERSION < "1.9"
|
50
|
+
results = @db.all # not ordered
|
51
|
+
assert_equal( { "pk1" => {"a" => "1", "b" => "2", "c" => "3"},
|
52
|
+
"pk2" => { } }, results )
|
53
|
+
results = @db.all(:order => :a) # ordered
|
54
|
+
assert_equal( [ ["pk1", {"a" => "1", "b" => "2", "c" => "3"}],
|
55
|
+
["pk2", { }] ], results )
|
56
|
+
else
|
57
|
+
results = @db.all
|
58
|
+
assert_equal( { "pk1" => {"a" => "1", "b" => "2", "c" => "3"},
|
59
|
+
"pk2" => { } }, results )
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_all_can_be_forced_to_return_a_hash_of_hashes
|
64
|
+
load_simple_data
|
65
|
+
%w[hoh hohs hash_of_hash hash_of_hashes].each do |hoh|
|
66
|
+
results = @db.all(:return => hoh)
|
67
|
+
assert_equal( { "pk1" => {"a" => "1", "b" => "2", "c" => "3"},
|
68
|
+
"pk2" => { } }, results )
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_all_can_be_forced_to_return_a_merged_array_of_hashes
|
73
|
+
load_simple_data
|
74
|
+
%w[aoh aohs array_of_hash array_of_hashes].each do |aoh|
|
75
|
+
results = @db.all(:return => aoh)
|
76
|
+
assert_equal( [ {:primary_key => "pk2"},
|
77
|
+
{ :primary_key => "pk1",
|
78
|
+
"a" => "1",
|
79
|
+
"b" => "2",
|
80
|
+
"c" => "3" }],
|
81
|
+
results.sort_by { |doc| doc.size } )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_all_can_be_forced_to_return_an_array_of_arrays
|
86
|
+
load_simple_data
|
87
|
+
%w[aoa aoas array_of_array array_of_arrays].each do |aoa|
|
88
|
+
results = @db.all(:return => aoa)
|
89
|
+
assert_equal( [ ["pk1", {"a" => "1", "b" => "2", "c" => "3"}],
|
90
|
+
["pk2", { }] ], results )
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_all_will_pass_keys_and_documents_to_a_passed_block_and_return_self
|
95
|
+
load_simple_data
|
96
|
+
results = [ ]
|
97
|
+
assert_equal(@db, @db.all { |k, v| results << [k, v] })
|
98
|
+
assert_equal( [ ["pk1", {"a" => "1", "b" => "2", "c" => "3"}],
|
99
|
+
["pk2", { }] ], results.sort )
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_all_can_pass_keys_only_to_a_passed_block_and_return_self
|
103
|
+
load_simple_data
|
104
|
+
results = [ ]
|
105
|
+
assert_equal(@db, @db.all(:select => :keys) { |k| results << k })
|
106
|
+
assert_equal(%w[pk1 pk2], results.sort)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_all_can_pass_documents_only_to_a_passed_block_and_return_self
|
110
|
+
load_simple_data
|
111
|
+
results = [ ]
|
112
|
+
assert_equal(@db, @db.all(:select => :docs) { |v| results << v })
|
113
|
+
assert_equal( [{ }, {"a" => "1", "b" => "2", "c" => "3"}],
|
114
|
+
results.sort_by { |doc| doc.size } )
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_all_with_a_block_does_not_modify_records_by_default
|
118
|
+
load_simple_data
|
119
|
+
assert_equal(@db, @db.all { })
|
120
|
+
assert_equal({"a" => "1", "b" => "2", "c" => "3"}, @db[:pk1])
|
121
|
+
assert_equal({ }, @db[:pk2])
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_all_with_a_block_can_update_records
|
125
|
+
load_simple_data
|
126
|
+
assert_equal( @db, @db.all { |k, v|
|
127
|
+
if k == "pk1"
|
128
|
+
v["a"] = "1.1" # change
|
129
|
+
v.delete("c") # remove
|
130
|
+
v[:d] = 4 # add
|
131
|
+
:update
|
132
|
+
end
|
133
|
+
} )
|
134
|
+
assert_equal({"a" => "1.1", "b" => "2", "d" => "4"}, @db[:pk1])
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_all_with_a_block_can_delete_records
|
138
|
+
load_simple_data
|
139
|
+
assert_equal(@db, @db.all { |_, v| v.empty? and :delete })
|
140
|
+
assert_equal({"a" => "1", "b" => "2", "c" => "3"}, @db[:pk1])
|
141
|
+
assert_nil(@db[:pk2])
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_all_with_a_block_can_end_the_query
|
145
|
+
load_simple_data
|
146
|
+
results = [ ]
|
147
|
+
assert_equal(@db, @db.all { |k, _| results << k; :break })
|
148
|
+
assert_equal(1, results.size)
|
149
|
+
assert_match(/\Apk[12]\z/, results.first)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_all_with_a_block_can_combine_flags
|
153
|
+
load_simple_data
|
154
|
+
results = [ ]
|
155
|
+
assert_equal(@db, @db.all { |k, _| results << k; %w[delete break] })
|
156
|
+
assert_equal(1, results.size)
|
157
|
+
assert_match(/\Apk[12]\z/, results.first)
|
158
|
+
assert_equal(1, @db.size)
|
159
|
+
assert_match((%w[pk1 pk2] - results).first, @db.keys.first)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_all_fails_with_an_error_for_malformed_conditions
|
163
|
+
assert_raise(OKMixer::Error::QueryError) do
|
164
|
+
@db.all(:conditions => :first) # not column, operator, and expression
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_all_fails_with_an_error_for_unknown_condition_operators
|
169
|
+
assert_raise(OKMixer::Error::QueryError) do
|
170
|
+
@db.all(:conditions => [:first, :unknown, "James"])
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_all_can_accept_string_equal_conditions
|
175
|
+
load_condition_data
|
176
|
+
%w[== eql equal str_eql string_equal].each do |op|
|
177
|
+
["", "s", "?", "s?"].each do |suffix|
|
178
|
+
next if op == "==" and suffix != ""
|
179
|
+
assert_equal( %w[james],
|
180
|
+
@db.all( :select => :keys,
|
181
|
+
:conditions => [:first, op + suffix, "James"] ) )
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_all_can_accept_string_not_equal_conditions
|
187
|
+
load_condition_data
|
188
|
+
%w[! !_ not_].each do |n|
|
189
|
+
%w[= eql equal str_eql string_equal].each do |op|
|
190
|
+
["", "s", "?", "s?"].each do |suffix|
|
191
|
+
next if op == "=" and suffix != ""
|
192
|
+
assert_equal( %w[dana jim],
|
193
|
+
@db.all( :select => :keys,
|
194
|
+
:conditions => [ :first,
|
195
|
+
n + op + suffix,
|
196
|
+
"James" ] ).sort )
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_all_can_accept_string_include_conditions
|
203
|
+
load_condition_data
|
204
|
+
%w[include includes include? includes?].each do |op|
|
205
|
+
assert_equal( %w[dana james],
|
206
|
+
@db.all( :select => :keys,
|
207
|
+
:conditions => [:first, op, "a"] ).sort )
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_all_can_accept_string_not_include_conditions
|
212
|
+
load_condition_data
|
213
|
+
%w[! !_ not_].each do |n|
|
214
|
+
%w[include includes include? includes?].each do |op|
|
215
|
+
assert_equal( %w[jim],
|
216
|
+
@db.all( :select => :keys,
|
217
|
+
:conditions => [:first, n + op, "a"] ) )
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_all_can_accept_string_starts_with_conditions
|
223
|
+
load_condition_data
|
224
|
+
%w[start_with starts_with start_with? starts_with?].each do |op|
|
225
|
+
assert_equal( %w[james jim],
|
226
|
+
@db.all( :select => :keys,
|
227
|
+
:conditions => [:first, op, "J"] ).sort )
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_all_can_accept_string_not_starts_with_conditions
|
232
|
+
load_condition_data
|
233
|
+
%w[! !_ not_].each do |n|
|
234
|
+
%w[start_with starts_with start_with? starts_with?].each do |op|
|
235
|
+
assert_equal( %w[dana],
|
236
|
+
@db.all( :select => :keys,
|
237
|
+
:conditions => [:first, n + op, "J"] ).sort )
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_all_can_accept_string_ends_with_conditions
|
243
|
+
load_condition_data
|
244
|
+
%w[end_with ends_with end_with? ends_with?].each do |op|
|
245
|
+
assert_equal( [ ],
|
246
|
+
@db.all( :select => :keys,
|
247
|
+
:conditions => [:first, op, "z"] ) )
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def test_all_can_accept_string_not_ends_with_conditions
|
252
|
+
load_condition_data
|
253
|
+
%w[! !_ not_].each do |n|
|
254
|
+
%w[end_with ends_with end_with? ends_with?].each do |op|
|
255
|
+
assert_equal( %w[dana james jim],
|
256
|
+
@db.all( :select => :keys,
|
257
|
+
:conditions => [:first, n + op, "z"] ).sort )
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_all_can_accept_string_includes_all_tokens_conditions
|
263
|
+
load_condition_data
|
264
|
+
%w[ include_all includes_all
|
265
|
+
include_all_tokens includes_all_tokens
|
266
|
+
include_all? includes_all?
|
267
|
+
include_all_tokens? includes_all_tokens? ].each do |op|
|
268
|
+
assert_equal( %w[dana],
|
269
|
+
@db.all( :select => :keys,
|
270
|
+
:conditions => [:middle, op, "Leslie Ann"] ) )
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_all_can_accept_string_not_includes_all_tokens_conditions
|
275
|
+
load_condition_data
|
276
|
+
%w[! !_ not_].each do |n|
|
277
|
+
%w[ include_all includes_all
|
278
|
+
include_all_tokens includes_all_tokens
|
279
|
+
include_all? includes_all?
|
280
|
+
include_all_tokens? includes_all_tokens? ].each do |op|
|
281
|
+
assert_equal( %w[james jim],
|
282
|
+
@db.all( :select => :keys,
|
283
|
+
:conditions => [:middle, n + op, "Leslie Ann"] ).
|
284
|
+
sort )
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_all_can_accept_string_includes_any_token_conditions
|
290
|
+
load_condition_data
|
291
|
+
%w[ include_any includes_any
|
292
|
+
include_any_token includes_any_token
|
293
|
+
include_any? includes_any?
|
294
|
+
include_any_token? includes_any_token? ].each do |op|
|
295
|
+
assert_equal( %w[dana],
|
296
|
+
@db.all( :select => :keys,
|
297
|
+
:conditions => [:middle, op, "Ann Joe"] ) )
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def test_all_can_accept_string_not_includes_any_token_conditions
|
302
|
+
load_condition_data
|
303
|
+
%w[! !_ not_].each do |n|
|
304
|
+
%w[ include_any includes_any
|
305
|
+
include_any_token includes_any_token
|
306
|
+
include_any? includes_any?
|
307
|
+
include_any_token? includes_any_token? ].each do |op|
|
308
|
+
assert_equal( %w[james jim],
|
309
|
+
@db.all( :select => :keys,
|
310
|
+
:conditions => [:middle, n + op, "Ann Joe"] ).
|
311
|
+
sort )
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_all_can_accept_string_equals_any_token_conditions
|
317
|
+
load_condition_data
|
318
|
+
%w[ eql_any eql_any
|
319
|
+
eql_any_token eql_any_token
|
320
|
+
eql_any? eql_any?
|
321
|
+
eql_any_token? eql_any_token?
|
322
|
+
equals_any equals_any
|
323
|
+
equals_any_token equals_any_token
|
324
|
+
equals_any? equals_any?
|
325
|
+
equals_any_token? equals_any_token? ].each do |op|
|
326
|
+
assert_equal( %w[dana james],
|
327
|
+
@db.all( :select => :keys,
|
328
|
+
:conditions => [:first, op, "Dana James"] ).sort )
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_all_can_accept_string_not_equals_any_token_conditions
|
333
|
+
load_condition_data
|
334
|
+
%w[! !_ not_].each do |n|
|
335
|
+
%w[ eql_any eql_any
|
336
|
+
eql_any_token eql_any_token
|
337
|
+
eql_any? eql_any?
|
338
|
+
eql_any_token? eql_any_token?
|
339
|
+
equals_any equals_any
|
340
|
+
equals_any_token equals_any_token
|
341
|
+
equals_any? equals_any?
|
342
|
+
equals_any_token? equals_any_token? ].each do |op|
|
343
|
+
assert_equal( %w[jim],
|
344
|
+
@db.all( :select => :keys,
|
345
|
+
:conditions => [:first, n + op, "Dana James"] ) )
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_all_can_accept_string_matches_regexp_conditions
|
351
|
+
load_condition_data
|
352
|
+
%w[=~ match].each do |op|
|
353
|
+
["", "es", "?", "es?"].each do |suffix|
|
354
|
+
next if op == "=~" and suffix != ""
|
355
|
+
assert_equal( %w[james jim],
|
356
|
+
@db.all( :select => :keys,
|
357
|
+
:conditions => [:first, op + suffix, /J.m/] ).
|
358
|
+
sort )
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_all_can_accept_string_not_matches_regexp_conditions
|
364
|
+
load_condition_data
|
365
|
+
%w[! !_ not_].each do |n|
|
366
|
+
%w[~ match].each do |op|
|
367
|
+
["", "es", "?", "es?"].each do |suffix|
|
368
|
+
next if op == "~" and suffix != ""
|
369
|
+
assert_equal( %w[dana],
|
370
|
+
@db.all( :select => :keys,
|
371
|
+
:conditions => [ :first,
|
372
|
+
n + op + suffix,
|
373
|
+
/J.m/ ] ) )
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_all_can_accept_number_equal_conditions
|
380
|
+
load_condition_data
|
381
|
+
%w[== eql equal num_eql number_equal].each do |op|
|
382
|
+
["", "s", "?", "s?"].each do |suffix|
|
383
|
+
next if op == "==" and suffix != ""
|
384
|
+
assert_equal( %w[james],
|
385
|
+
@db.all( :select => :keys,
|
386
|
+
:conditions => [:age, op + suffix, 33] ) )
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_all_can_accept_number_not_equal_conditions
|
392
|
+
load_condition_data
|
393
|
+
%w[! !_ not_].each do |n|
|
394
|
+
%w[= eql equal num_eql number_equal].each do |op|
|
395
|
+
["", "s", "?", "s?"].each do |suffix|
|
396
|
+
next if op == "=" and suffix != ""
|
397
|
+
assert_equal( %w[dana jim],
|
398
|
+
@db.all( :select => :keys,
|
399
|
+
:conditions => [:age, n + op + suffix, 33] ).
|
400
|
+
sort )
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_all_can_accept_number_greater_than_conditions
|
407
|
+
load_condition_data
|
408
|
+
assert_equal( %w[dana jim], @db.all( :select => :keys,
|
409
|
+
:conditions => [:age, :>, 33] ).sort )
|
410
|
+
end
|
411
|
+
|
412
|
+
def test_all_can_accept_number_not_greater_than_conditions
|
413
|
+
load_condition_data
|
414
|
+
assert_equal( %w[james], @db.all( :select => :keys,
|
415
|
+
:conditions => [:age, "!>", 33] ) )
|
416
|
+
end
|
417
|
+
|
418
|
+
def test_all_can_accept_number_greater_than_or_equal_to_conditions
|
419
|
+
load_condition_data
|
420
|
+
assert_equal( %w[dana jim], @db.all( :select => :keys,
|
421
|
+
:conditions => [:age, :>=, 34] ).sort )
|
422
|
+
end
|
423
|
+
|
424
|
+
def test_all_can_accept_number_not_greater_than_or_equal_to_conditions
|
425
|
+
load_condition_data
|
426
|
+
assert_equal( %w[james], @db.all( :select => :keys,
|
427
|
+
:conditions => [:age, "!>=", 34] ) )
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_all_can_accept_number_less_than_conditions
|
431
|
+
load_condition_data
|
432
|
+
assert_equal( %w[dana james],
|
433
|
+
@db.all( :select => :keys,
|
434
|
+
:conditions => [:age, :<, 53] ).sort )
|
435
|
+
end
|
436
|
+
|
437
|
+
def test_all_can_accept_number_not_less_than_conditions
|
438
|
+
load_condition_data
|
439
|
+
assert_equal( %w[jim], @db.all( :select => :keys,
|
440
|
+
:conditions => [:age, "!<", 53] ) )
|
441
|
+
end
|
442
|
+
|
443
|
+
def test_all_can_accept_number_less_than_or_equal_to_conditions
|
444
|
+
load_condition_data
|
445
|
+
assert_equal( %w[dana james],
|
446
|
+
@db.all( :select => :keys,
|
447
|
+
:conditions => [:age, :<=, 34] ).sort )
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_all_can_accept_number_not_less_than_or_equal_to_conditions
|
451
|
+
load_condition_data
|
452
|
+
assert_equal( %w[jim], @db.all( :select => :keys,
|
453
|
+
:conditions => [:age, "!<=", 34] ) )
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_all_can_accept_number_between_conditions
|
457
|
+
load_condition_data
|
458
|
+
%w[between between?].each do |op|
|
459
|
+
assert_equal( %w[dana james],
|
460
|
+
@db.all( :select => :keys,
|
461
|
+
:conditions => [:age, op, "33 50"] ).sort )
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
def test_all_can_accept_number_not_between_conditions
|
466
|
+
load_condition_data
|
467
|
+
%w[! !_ not_].each do |n|
|
468
|
+
%w[between between?].each do |op|
|
469
|
+
assert_equal( %w[jim],
|
470
|
+
@db.all( :select => :keys,
|
471
|
+
:conditions => [:age, n + op, "33 50"] ) )
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_all_can_accept_any_number_conditions
|
477
|
+
load_condition_data
|
478
|
+
%w[any_num any_number any_num? any_number?].each do |op|
|
479
|
+
assert_equal( %w[james jim],
|
480
|
+
@db.all( :select => :keys,
|
481
|
+
:conditions => [:age, op, "33 53"] ).sort )
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
def test_all_can_accept_not_any_number_conditions
|
486
|
+
load_condition_data
|
487
|
+
%w[! !_ not_].each do |n|
|
488
|
+
%w[any_num any_number any_num? any_number?].each do |op|
|
489
|
+
assert_equal( %w[dana],
|
490
|
+
@db.all( :select => :keys,
|
491
|
+
:conditions => [:age, n + op, "33 53"] ) )
|
492
|
+
end
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
def test_all_can_accept_phrase_search_conditions
|
497
|
+
load_search_data
|
498
|
+
%w[phrase_search phrase_search?].each do |op|
|
499
|
+
assert_equal( %w[james jim],
|
500
|
+
@db.all( :select => :keys,
|
501
|
+
:conditions => [:name, op, "Edward Gray"] ).sort )
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
def test_all_can_accept_not_phrase_search_conditions
|
506
|
+
load_search_data
|
507
|
+
%w[! !_ not_].each do |n|
|
508
|
+
%w[phrase_search phrase_search?].each do |op|
|
509
|
+
assert_equal( %w[dana],
|
510
|
+
@db.all( :select => :keys,
|
511
|
+
:conditions => [:name, n + op, "Edward Gray"] ) )
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
# FIXME: could not determine how to test Full-Text token searches
|
517
|
+
|
518
|
+
def test_all_can_accept_expression_search_conditions
|
519
|
+
load_search_data
|
520
|
+
%w[expression_search expression_search?].each do |op|
|
521
|
+
assert_equal( %w[dana james],
|
522
|
+
@db.all( :select => :keys,
|
523
|
+
:conditions => [:name, op, "James || Ann"] ).sort )
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
def test_all_can_accept_not_expression_search_conditions
|
528
|
+
load_search_data
|
529
|
+
%w[! !_ not_].each do |n|
|
530
|
+
%w[expression_search expression_search?].each do |op|
|
531
|
+
assert_equal( %w[jim],
|
532
|
+
@db.all( :select => :keys,
|
533
|
+
:conditions => [ :name,
|
534
|
+
n + op,
|
535
|
+
"James || Ann" ] ) )
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
def test_all_can_set_conditions_for_the_primary_key
|
541
|
+
load_condition_data
|
542
|
+
["", :pk, :primary_key].each do |key|
|
543
|
+
assert_equal( %w[james jim],
|
544
|
+
@db.all( :select => :keys,
|
545
|
+
:conditions => [key, :starts_with?, "j"] ).sort )
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
def test_all_can_accept_multiple_conditions
|
550
|
+
load_condition_data
|
551
|
+
assert_equal( %w[dana james],
|
552
|
+
@db.all( :select => :keys,
|
553
|
+
:conditions => [ [:last, :==, "Gray"],
|
554
|
+
[:age, "!=", 53] ] ).sort )
|
555
|
+
end
|
556
|
+
|
557
|
+
def test_all_fails_with_an_error_for_malformed_order
|
558
|
+
assert_raise(OKMixer::Error::QueryError) do
|
559
|
+
@db.all(:order => %w[too many args])
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def test_all_fails_with_an_error_for_unknown_order_type
|
564
|
+
assert_raise(OKMixer::Error::QueryError) do
|
565
|
+
@db.all(:order => [:first, :unknown])
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
def test_all_accepts_an_order_field_used_to_arrange_results
|
570
|
+
load_order_data
|
571
|
+
assert_equal( %w[first middle last],
|
572
|
+
@db.all(:select => :keys, :order => :str) )
|
573
|
+
end
|
574
|
+
|
575
|
+
def test_all_order_defaults_to_string_ascending
|
576
|
+
load_order_data
|
577
|
+
assert_equal( %w[1 11 2], @db.all(:select => :docs, :order => :num).
|
578
|
+
map { |doc| doc["num"] } )
|
579
|
+
end
|
580
|
+
|
581
|
+
def test_all_order_can_be_forced_to_string_descending
|
582
|
+
load_order_data
|
583
|
+
%w[ASC STR_ASC].each do |order|
|
584
|
+
assert_equal( %w[first middle last],
|
585
|
+
@db.all(:select => :keys, :order => [:str, order]) )
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
def test_all_order_can_be_set_to_string_descending
|
590
|
+
load_order_data
|
591
|
+
%w[DESC STR_DESC].each do |order|
|
592
|
+
assert_equal( %w[last middle first],
|
593
|
+
@db.all(:select => :keys, :order => [:str, order]) )
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
def test_all_order_can_be_set_to_numeric_ascending
|
598
|
+
load_order_data
|
599
|
+
assert_equal( %w[first middle last],
|
600
|
+
@db.all(:select => :keys, :order => [:num, :NUM_ASC]) )
|
601
|
+
end
|
602
|
+
|
603
|
+
def test_all_order_can_be_set_to_numeric_descending
|
604
|
+
load_order_data
|
605
|
+
assert_equal( %w[last middle first],
|
606
|
+
@db.all(:select => :keys, :order => [:num, :NUM_DESC]) )
|
607
|
+
end
|
608
|
+
|
609
|
+
def test_all_can_order_the_primary_key
|
610
|
+
load_order_data
|
611
|
+
["", :pk, :primary_key].each do |key|
|
612
|
+
assert_equal( %w[first last middle],
|
613
|
+
@db.all(:select => :keys, :order => key) )
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_all_accepts_a_limit_for_returned_results
|
618
|
+
load_order_data
|
619
|
+
assert_equal( %w[first middle], @db.all( :select => :keys,
|
620
|
+
:order => :str,
|
621
|
+
:limit => 2 ) )
|
622
|
+
end
|
623
|
+
|
624
|
+
def test_all_accepts_an_offset_with_a_limit
|
625
|
+
load_order_data
|
626
|
+
assert_equal( %w[last], @db.all( :select => :keys,
|
627
|
+
:order => :str,
|
628
|
+
:limit => 2,
|
629
|
+
:offset => 2 ) )
|
630
|
+
end
|
631
|
+
|
632
|
+
def test_first_is_all_with_limit_one_removed_from_the_array
|
633
|
+
load_order_data
|
634
|
+
assert_equal("first", @db.first(:select => :keys, :order => :str))
|
635
|
+
assert_nil(@db.first(:select => :keys, :order => :str, :offset => 10))
|
636
|
+
end
|
637
|
+
|
638
|
+
def test_count_returns_a_count_of_records_matched
|
639
|
+
load_condition_data
|
640
|
+
assert_equal(2, @db.count(:conditions => [:first, :starts_with?, "J"]))
|
641
|
+
end
|
642
|
+
|
643
|
+
def test_paginate_requires_a_page_argument
|
644
|
+
assert_raise(OKMixer::Error::QueryError) do
|
645
|
+
@db.paginate({ }) # no :page argument
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
def test_paginate_requires_a_page_greater_than_zero_with_nil_allowed
|
650
|
+
assert_raise(OKMixer::Error::QueryError) do
|
651
|
+
@db.paginate({:page => 0})
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
def test_paginate_requires_per_page_be_greater_than_zero_if_provided
|
656
|
+
assert_raise(OKMixer::Error::QueryError) do
|
657
|
+
@db.paginate({:page => nil, :per_page => 0})
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
def test_paginate_defaults_to_thirty_for_a_per_page_count
|
662
|
+
load_search_data
|
663
|
+
assert_equal(30, @db.paginate(:page => nil).per_page)
|
664
|
+
end
|
665
|
+
|
666
|
+
def test_paginate_returns_result_sets_in_pages_regardless_of_type
|
667
|
+
load_search_data
|
668
|
+
%w[hoh aoa aoh].each do |results_mode|
|
669
|
+
page = @db.paginate( :order => :primary_key,
|
670
|
+
:return => results_mode.to_sym,
|
671
|
+
:per_page => 2,
|
672
|
+
:page => nil )
|
673
|
+
keys = page.to_a.map { |result|
|
674
|
+
result.respond_to?(:first) ? result.first : result[:primary_key]
|
675
|
+
}
|
676
|
+
assert_equal(%w[dana james], keys)
|
677
|
+
assert_equal(2, page.size)
|
678
|
+
assert_kind_of(OKMixer::TableDatabase::Paginated, page)
|
679
|
+
assert_equal(1, page.current_page)
|
680
|
+
assert_equal(2, page.per_page)
|
681
|
+
assert_equal(3, page.total_entries)
|
682
|
+
assert_equal(2, page.total_pages)
|
683
|
+
assert(!page.out_of_bounds?, "The first page was out of bounds")
|
684
|
+
assert_equal(0, page.offset)
|
685
|
+
assert_nil(page.previous_page)
|
686
|
+
assert_equal(2, page.next_page)
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
def test_paginate_adjusts_limit_and_offset_by_page_and_per_page
|
691
|
+
load_search_data
|
692
|
+
page = @db.paginate( :select => :keys,
|
693
|
+
:order => :primary_key,
|
694
|
+
:per_page => 2,
|
695
|
+
:page => 2 )
|
696
|
+
assert_equal(%w[jim], page)
|
697
|
+
assert_equal(1, page.size)
|
698
|
+
assert_equal(2, page.current_page)
|
699
|
+
assert_equal(2, page.per_page)
|
700
|
+
assert_equal(3, page.total_entries)
|
701
|
+
assert_equal(2, page.total_pages)
|
702
|
+
assert(!page.out_of_bounds?, "The last page was out of bounds")
|
703
|
+
assert_equal(2, page.offset)
|
704
|
+
assert_equal(1, page.previous_page)
|
705
|
+
assert_nil(page.next_page)
|
706
|
+
end
|
707
|
+
|
708
|
+
def test_paginate_detects_out_of_bounds_pages
|
709
|
+
load_search_data
|
710
|
+
page = @db.paginate( :select => :keys,
|
711
|
+
:order => :primary_key,
|
712
|
+
:per_page => 2,
|
713
|
+
:page => 3 )
|
714
|
+
assert_equal([ ], page)
|
715
|
+
assert_equal(0, page.size)
|
716
|
+
assert_equal(3, page.current_page)
|
717
|
+
assert_equal(2, page.per_page)
|
718
|
+
assert_equal(3, page.total_entries)
|
719
|
+
assert_equal(2, page.total_pages)
|
720
|
+
assert(page.out_of_bounds?, "An out of bounds page was not detected")
|
721
|
+
assert_equal(4, page.offset)
|
722
|
+
assert_equal(2, page.previous_page)
|
723
|
+
assert_nil(page.next_page)
|
724
|
+
end
|
725
|
+
|
726
|
+
def test_union_returns_the_set_union_of_multiple_queries
|
727
|
+
load_condition_data
|
728
|
+
assert_equal( [ [ "dana", { "first" => "Dana",
|
729
|
+
"middle" => "Ann Leslie",
|
730
|
+
"last" => "Gray",
|
731
|
+
"age" => "34" } ],
|
732
|
+
[ "james", { "first" => "James",
|
733
|
+
"last" => "Gray",
|
734
|
+
"age" => "33" } ] ],
|
735
|
+
@db.union( { :conditions => [:first, :ends_with?, "es"],
|
736
|
+
:order => :first },
|
737
|
+
{:conditions => [:age, :==, 34]} ).to_a )
|
738
|
+
end
|
739
|
+
|
740
|
+
def test_union_respects_select_and_return_on_the_first_query
|
741
|
+
load_condition_data
|
742
|
+
assert_equal( %w[dana james],
|
743
|
+
@db.union( { :select => :keys,
|
744
|
+
:conditions => [:first, :ends_with?, "es"],
|
745
|
+
:order => :first },
|
746
|
+
{:conditions => [:age, :==, 34]} ) )
|
747
|
+
assert_equal( [ [ "dana", { "first" => "Dana",
|
748
|
+
"middle" => "Ann Leslie",
|
749
|
+
"last" => "Gray",
|
750
|
+
"age" => "34" } ],
|
751
|
+
[ "james", { "first" => "James",
|
752
|
+
"last" => "Gray",
|
753
|
+
"age" => "33" } ] ],
|
754
|
+
@db.union( { :select => :keys_and_docs,
|
755
|
+
:return => :aoa,
|
756
|
+
:conditions => [:first, :ends_with?, "es"],
|
757
|
+
:order => :first },
|
758
|
+
{:conditions => [:age, :==, 34]} ) )
|
759
|
+
end
|
760
|
+
|
761
|
+
def test_intersection_returns_the_set_intersection_of_multiple_queries
|
762
|
+
load_condition_data
|
763
|
+
assert_equal( [ [ "dana", { "first" => "Dana",
|
764
|
+
"middle" => "Ann Leslie",
|
765
|
+
"last" => "Gray",
|
766
|
+
"age" => "34" } ],
|
767
|
+
[ "james", { "first" => "James",
|
768
|
+
"last" => "Gray",
|
769
|
+
"age" => "33" } ] ],
|
770
|
+
@db.isect( { :conditions => [:first, :include?, "a"],
|
771
|
+
:order => :first },
|
772
|
+
{:conditions => [:last, :==, "Gray"]} ).to_a )
|
773
|
+
end
|
774
|
+
|
775
|
+
def test_intersection_respects_select_and_return_on_the_first_query
|
776
|
+
load_condition_data
|
777
|
+
assert_equal( [ { "first" => "Dana",
|
778
|
+
"middle" => "Ann Leslie",
|
779
|
+
"last" => "Gray",
|
780
|
+
"age" => "34" },
|
781
|
+
{ "first" => "James",
|
782
|
+
"last" => "Gray",
|
783
|
+
"age" => "33" } ],
|
784
|
+
@db.isect( { :select => :docs,
|
785
|
+
:conditions => [:first, :include?, "a"],
|
786
|
+
:order => :first },
|
787
|
+
{:conditions => [:last, :==, "Gray"]} ) )
|
788
|
+
assert_equal( { "dana" => { "first" => "Dana",
|
789
|
+
"middle" => "Ann Leslie",
|
790
|
+
"last" => "Gray",
|
791
|
+
"age" => "34" },
|
792
|
+
"james" => { "first" => "James",
|
793
|
+
"last" => "Gray",
|
794
|
+
"age" => "33" } },
|
795
|
+
@db.isect( { :select => :keys_and_docs,
|
796
|
+
:return => :hoh,
|
797
|
+
:conditions => [:first, :include?, "a"],
|
798
|
+
:order => :first },
|
799
|
+
{:conditions => [:last, :==, "Gray"]} ) )
|
800
|
+
end
|
801
|
+
|
802
|
+
def test_difference_returns_the_set_difference_of_multiple_queries
|
803
|
+
load_condition_data
|
804
|
+
assert_equal( [ [ "dana", { "first" => "Dana",
|
805
|
+
"middle" => "Ann Leslie",
|
806
|
+
"last" => "Gray",
|
807
|
+
"age" => "34" } ],
|
808
|
+
[ "james", { "first" => "James",
|
809
|
+
"last" => "Gray",
|
810
|
+
"age" => "33" } ] ],
|
811
|
+
@db.diff( { :conditions => [:last, :==, "Gray"],
|
812
|
+
:order => :first },
|
813
|
+
{:conditions => [:first, :==, "Jim"]} ).to_a )
|
814
|
+
end
|
815
|
+
|
816
|
+
def test_difference_respects_select_and_return_on_the_first_query
|
817
|
+
load_condition_data
|
818
|
+
assert_equal( %w[dana james],
|
819
|
+
@db.diff( { :select => :keys,
|
820
|
+
:conditions => [:last, :==, "Gray"],
|
821
|
+
:order => :first },
|
822
|
+
{:conditions => [:first, :==, "Jim"]} ) )
|
823
|
+
assert_equal( [ { :primary_key => "dana",
|
824
|
+
"first" => "Dana",
|
825
|
+
"middle" => "Ann Leslie",
|
826
|
+
"last" => "Gray",
|
827
|
+
"age" => "34" },
|
828
|
+
{ :primary_key => "james",
|
829
|
+
"first" => "James",
|
830
|
+
"last" => "Gray",
|
831
|
+
"age" => "33" } ],
|
832
|
+
@db.diff( { :select => :keys_and_docs,
|
833
|
+
:return => :aoh,
|
834
|
+
:conditions => [:last, :==, "Gray"],
|
835
|
+
:order => :first },
|
836
|
+
{:conditions => [:first, :==, "Jim"]} ) )
|
837
|
+
end
|
838
|
+
|
839
|
+
private
|
840
|
+
|
841
|
+
def load_simple_data
|
842
|
+
@db[:pk1] = {:a => 1, :b => 2, :c => 3}
|
843
|
+
@db[:pk2] = { }
|
844
|
+
end
|
845
|
+
|
846
|
+
def load_condition_data
|
847
|
+
@db[:dana] = { :first => "Dana",
|
848
|
+
:middle => "Ann Leslie",
|
849
|
+
:last => "Gray",
|
850
|
+
:age => 34 }
|
851
|
+
@db[:james] = {:first => "James", :last => "Gray", :age => 33}
|
852
|
+
@db[:jim] = {:first => "Jim", :last => "Gray", :age => 53}
|
853
|
+
end
|
854
|
+
|
855
|
+
def load_search_data
|
856
|
+
@db[:dana] = {:name => "Dana Ann Leslie Gray"}
|
857
|
+
@db[:james] = {:name => "James Edward Gray II"}
|
858
|
+
@db[:jim] = {:name => "Jim Edward Gray"}
|
859
|
+
end
|
860
|
+
|
861
|
+
def load_order_data
|
862
|
+
@db[:middle] = {:str => :b, :num => 2}
|
863
|
+
@db[:last] = {:str => :c, :num => 11}
|
864
|
+
@db[:first] = {:str => :a, :num => 1}
|
865
|
+
end
|
866
|
+
end
|