rod 0.7.1 → 0.7.2
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/.travis.yml +1 -1
- data/README.rdoc +38 -10
- data/Rakefile +20 -9
- data/changelog.txt +25 -0
- data/contributors.txt +1 -0
- data/data/backward/0.7.0/_join_element.dat +0 -0
- data/data/backward/0.7.0/_polymorphic_join_element.dat +0 -0
- data/data/backward/0.7.0/char.dat +0 -0
- data/data/backward/0.7.0/database.yml +58 -0
- data/data/backward/0.7.0/rod_test__automobile.dat +0 -0
- data/data/backward/0.7.0/rod_test__caveman.dat +0 -0
- data/data/backward/0.7.0/rod_test__dog.dat +0 -0
- data/data/backward/0.7.0/rod_test__test_model.dat +0 -0
- data/data/portability/_join_element.dat +0 -0
- data/data/portability/_polymorphic_join_element.dat +0 -0
- data/data/portability/char.dat +0 -0
- data/data/portability/database.yml +49 -0
- data/data/portability/rod_test__automobile.dat +0 -0
- data/data/portability/rod_test__caveman.dat +0 -0
- data/data/portability/rod_test__dog.dat +0 -0
- data/data/portability/rod_test__test_model.dat +0 -0
- data/features/backward.feature +33 -0
- data/features/basic.feature +3 -0
- data/features/collection_proxy.feature +95 -0
- data/features/flat_indexing.feature +44 -2
- data/features/hash_indexing.feature +63 -9
- data/features/portability.feature +72 -0
- data/features/segmented_indexing.feature +45 -2
- data/features/steps/collection_proxy.rb +1 -1
- data/features/steps/model.rb +48 -5
- data/features/steps/rod.rb +15 -16
- data/lib/rod.rb +11 -1
- data/lib/rod/abstract_database.rb +52 -42
- data/lib/rod/berkeley/collection_proxy.rb +96 -0
- data/lib/rod/berkeley/database.rb +337 -0
- data/lib/rod/berkeley/environment.rb +209 -0
- data/lib/rod/berkeley/sequence.rb +222 -0
- data/lib/rod/berkeley/transaction.rb +233 -0
- data/lib/rod/collection_proxy.rb +76 -1
- data/lib/rod/constants.rb +3 -2
- data/lib/rod/database.rb +127 -14
- data/lib/rod/index/base.rb +12 -3
- data/lib/rod/index/hash_index.rb +295 -70
- data/lib/rod/index/segmented_index.rb +3 -0
- data/lib/rod/model.rb +154 -531
- data/lib/rod/property/base.rb +190 -0
- data/lib/rod/property/field.rb +258 -0
- data/lib/rod/property/plural_association.rb +145 -0
- data/lib/rod/property/singular_association.rb +139 -0
- data/rod.gemspec +6 -4
- data/spec/berkeley/database.rb +83 -0
- data/spec/berkeley/environment.rb +58 -0
- data/spec/berkeley/sequence.rb +101 -0
- data/spec/berkeley/transaction.rb +92 -0
- data/spec/collection_proxy.rb +38 -0
- data/spec/database.rb +36 -0
- data/spec/model.rb +26 -0
- data/spec/property/base.rb +73 -0
- data/spec/property/field.rb +244 -0
- data/spec/property/plural_association.rb +67 -0
- data/spec/property/singular_association.rb +65 -0
- data/tests/class_compatibility_create.rb +2 -2
- data/tests/eff1_test.rb +1 -1
- data/tests/eff2_test.rb +1 -1
- data/tests/full_runs.rb +1 -1
- data/tests/generate_classes_create.rb +14 -14
- data/tests/migration_create.rb +47 -47
- data/tests/migration_verify.rb +1 -1
- data/tests/missing_class_create.rb +6 -6
- data/tests/properties_order_create.rb +4 -4
- data/tests/read_on_create.rb +33 -34
- data/tests/save_struct.rb +40 -39
- data/tests/unit/database.rb +1 -1
- data/tests/unit/model_tests.rb +73 -65
- metadata +71 -15
- data/tests/unit/model.rb +0 -36
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rod'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
# TODO translate collection proxy feature into spec.
|
7
|
+
describe Rod::CollectionProxy do
|
8
|
+
describe "a persisted collection proxy" do
|
9
|
+
before do
|
10
|
+
@size = 10
|
11
|
+
@offset = 0
|
12
|
+
@db = Object.new
|
13
|
+
@size.times do |index|
|
14
|
+
@db.expects(:join_index).with(@offset,index).returns(index+1).at_least(0)
|
15
|
+
end
|
16
|
+
@proxy = Rod::CollectionProxy.new(@size,@db,@offset,Rod::Model)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "with another collection proxy" do
|
20
|
+
before do
|
21
|
+
size = 10
|
22
|
+
size.times do |index|
|
23
|
+
# these collections have 5 rod_ids in common (6 = 1 + 5, 0 for nil objects)
|
24
|
+
@db.expects(:join_index).with(@size,index).returns(index+6).at_least(0)
|
25
|
+
end
|
26
|
+
@other_proxy = Rod::CollectionProxy.new(size,@db,@size,Rod::Model)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be possible to compute their intersection" do
|
30
|
+
(@proxy & @other_proxy).size.must_equal 5
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be possible to compute their sum" do
|
34
|
+
(@proxy | @other_proxy).size.must_equal 15
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/database.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rod'
|
4
|
+
|
5
|
+
describe Rod::Database do
|
6
|
+
describe "a database" do
|
7
|
+
it "should allow to create itself without a block given" do
|
8
|
+
database = Rod::Database.instance
|
9
|
+
database.opened?.must_equal false
|
10
|
+
database.create_database("tmp/without_block")
|
11
|
+
database.opened?.must_equal true
|
12
|
+
database.close_database
|
13
|
+
database.opened?.must_equal false
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should allow to create itself with a block given" do
|
17
|
+
database = Rod::Database.instance
|
18
|
+
database.opened?.must_equal false
|
19
|
+
database.create_database("tmp/without_block") do
|
20
|
+
database.opened?.must_equal true
|
21
|
+
end
|
22
|
+
database.opened?.must_equal false
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should close itself on create even if an exception is raised" do
|
26
|
+
database = Rod::Database.instance
|
27
|
+
(proc do
|
28
|
+
database.create_database("tmp/block_exception") do
|
29
|
+
database.opened?.must_equal true
|
30
|
+
raise "Runtime exception"
|
31
|
+
end
|
32
|
+
end).must_raise RuntimeError
|
33
|
+
database.opened?.must_equal false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/model.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rod'
|
4
|
+
|
5
|
+
class User < Rod::Model
|
6
|
+
database_class Rod::Database
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Rod::Model do
|
10
|
+
describe "a model" do
|
11
|
+
before do
|
12
|
+
@database = Rod::Database.instance
|
13
|
+
@database.create_database("tmp/model")
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
@database.close_database
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return nil if index in #[] is out of scope" do
|
21
|
+
User[0].must_equal nil
|
22
|
+
User[1].must_equal nil
|
23
|
+
User[-1].must_equal nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rod'
|
4
|
+
|
5
|
+
describe Rod::Property::Base do
|
6
|
+
describe "a property" do
|
7
|
+
before do
|
8
|
+
@klass = MiniTest::Mock.new
|
9
|
+
@klass.expect :nil?,false
|
10
|
+
@field = Rod::Property::Field.new(@klass,:user_name,:string)
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
@klass.verify
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must have proper name" do
|
18
|
+
@field.name.must_equal :user_name
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must have proper type" do
|
22
|
+
@field.type.must_equal :string
|
23
|
+
end
|
24
|
+
|
25
|
+
it "must produce its metadata" do
|
26
|
+
@field.metadata.wont_be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must covert to C struct" do
|
30
|
+
@field.to_c_struct.wont_be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must produce its layout" do
|
34
|
+
@field.layout.wont_be_nil
|
35
|
+
end
|
36
|
+
|
37
|
+
it "must not have an index" do
|
38
|
+
@field.has_index?.wont_equal true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "an indexed property" do
|
43
|
+
before do
|
44
|
+
@klass = MiniTest::Mock.new
|
45
|
+
@klass.expect :nil?,false
|
46
|
+
@field = Rod::Property::Field.new(@klass,:user_name,:string,:index => :flat)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must have an index" do
|
50
|
+
@field.has_index?.must_equal true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "must return an index" do
|
54
|
+
database = MiniTest::Mock.new
|
55
|
+
database.expect :path,"path"
|
56
|
+
@klass.expect :database,database
|
57
|
+
@klass.expect :model_path,"model_path"
|
58
|
+
@field.index.wont_be_nil
|
59
|
+
database.verify
|
60
|
+
end
|
61
|
+
|
62
|
+
it "must define finders" do
|
63
|
+
database = MiniTest::Mock.new
|
64
|
+
database.expect :nil?,false
|
65
|
+
database.expect :path,"path"
|
66
|
+
@klass.expect :database,database
|
67
|
+
@klass.expect :model_path,"model_path"
|
68
|
+
@field.define_finders
|
69
|
+
proc {@klass.find_by_user_name("Name")}.must_be_silent
|
70
|
+
database.verify
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rod'
|
4
|
+
|
5
|
+
describe Rod::Property::Field do
|
6
|
+
before do
|
7
|
+
@klass = MiniTest::Mock.new
|
8
|
+
@klass.expect :nil?,false
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
@klass.verify
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "a generic field" do
|
16
|
+
before do
|
17
|
+
@builder = MiniTest::Mock.new
|
18
|
+
@field = Rod::Property::Field.new(@klass,:user_name,:string)
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
@builder.verify
|
23
|
+
end
|
24
|
+
|
25
|
+
it "must be a field" do
|
26
|
+
@field.field?.must_equal true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "must not be an association" do
|
30
|
+
@field.association?.wont_equal true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "must define C accessors" do
|
34
|
+
@klass.expect :struct_name, "struct_name"
|
35
|
+
@builder.expect :c,nil,[String]
|
36
|
+
@field.define_c_accessors(@builder)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "must seal C accessors" do
|
40
|
+
@klass.expect :send,nil,[:private,String]
|
41
|
+
@field.seal_c_accessors
|
42
|
+
end
|
43
|
+
|
44
|
+
it "must define getter" do
|
45
|
+
@klass.expect :send,nil,[:define_method,"user_name"]
|
46
|
+
@klass.expect :database,nil
|
47
|
+
@field.define_getter
|
48
|
+
end
|
49
|
+
|
50
|
+
it "must define setter" do
|
51
|
+
@klass.expect :send,nil,[:define_method,"user_name="]
|
52
|
+
@field.define_setter
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "a string field" do
|
57
|
+
before do
|
58
|
+
@field = Rod::Property::Field.new(@klass,:user_name,:string)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "must have string type" do
|
62
|
+
@field.type.must_equal :string
|
63
|
+
end
|
64
|
+
|
65
|
+
it "must have empty string as default value" do
|
66
|
+
@field.default_value.must_equal ''
|
67
|
+
end
|
68
|
+
|
69
|
+
it "must be a variable size field" do
|
70
|
+
@field.variable_size?.must_equal true
|
71
|
+
end
|
72
|
+
|
73
|
+
it "must set utf-8 encoding for dumped value" do
|
74
|
+
@field.dump("string").encoding.must_equal Encoding.find("utf-8")
|
75
|
+
end
|
76
|
+
|
77
|
+
it "must set utf-8 encoding for loaded value" do
|
78
|
+
@field.load("string").encoding.must_equal Encoding.find("utf-8")
|
79
|
+
end
|
80
|
+
|
81
|
+
it "must not be an identifier" do
|
82
|
+
@field.identifier?.wont_equal true
|
83
|
+
end
|
84
|
+
|
85
|
+
it "must produce proper metadata" do
|
86
|
+
@field.metadata.must_equal({:type => :string})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "an object field" do
|
91
|
+
before do
|
92
|
+
@field = Rod::Property::Field.new(@klass,:tag,:object)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "must have object type" do
|
96
|
+
@field.type.must_equal :object
|
97
|
+
end
|
98
|
+
|
99
|
+
it "must have nil as default value" do
|
100
|
+
@field.default_value.must_equal nil
|
101
|
+
end
|
102
|
+
|
103
|
+
it "must be a variable size field" do
|
104
|
+
@field.variable_size?.must_equal true
|
105
|
+
end
|
106
|
+
|
107
|
+
it "must marshal dumped value" do
|
108
|
+
@field.dump(:value).must_equal Marshal::dump(:value)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "must unmarshal loaded value" do
|
112
|
+
@field.load(Marshal::dump(:value)).must_equal :value
|
113
|
+
end
|
114
|
+
|
115
|
+
it "must produce proper metadata" do
|
116
|
+
@field.metadata.must_equal({:type => :object})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "a json field" do
|
121
|
+
before do
|
122
|
+
@field = Rod::Property::Field.new(@klass,:tag,:json)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "must have json type" do
|
126
|
+
@field.type.must_equal :json
|
127
|
+
end
|
128
|
+
|
129
|
+
it "must have nil as default value" do
|
130
|
+
@field.default_value.must_equal nil
|
131
|
+
end
|
132
|
+
|
133
|
+
it "must be a variable size field" do
|
134
|
+
@field.variable_size?.must_equal true
|
135
|
+
end
|
136
|
+
|
137
|
+
it "must convert to json dumped value" do
|
138
|
+
@field.dump("value").must_equal JSON::dump(["value"])
|
139
|
+
end
|
140
|
+
|
141
|
+
it "must convert from json loaded value" do
|
142
|
+
@field.load(JSON::dump(["value"])).must_equal "value"
|
143
|
+
end
|
144
|
+
|
145
|
+
it "must produce proper metadata" do
|
146
|
+
@field.metadata.must_equal({:type => :json})
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "an integer field" do
|
151
|
+
before do
|
152
|
+
@field = Rod::Property::Field.new(@klass,:tag,:integer)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "must have integer type" do
|
156
|
+
@field.type.must_equal :integer
|
157
|
+
end
|
158
|
+
|
159
|
+
it "must have 0 as default value" do
|
160
|
+
@field.default_value.must_equal 0
|
161
|
+
end
|
162
|
+
|
163
|
+
it "must not be a variable size field" do
|
164
|
+
@field.variable_size?.wont_equal true
|
165
|
+
end
|
166
|
+
|
167
|
+
it "must pass dumped value" do
|
168
|
+
@field.dump(-10).must_equal -10
|
169
|
+
end
|
170
|
+
|
171
|
+
it "must pass loaded value" do
|
172
|
+
@field.load(-10).must_equal -10
|
173
|
+
end
|
174
|
+
|
175
|
+
it "must produce proper metadata" do
|
176
|
+
@field.metadata.must_equal({:type => :integer})
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "a float field" do
|
181
|
+
before do
|
182
|
+
@field = Rod::Property::Field.new(@klass,:tag,:float)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "must have float type" do
|
186
|
+
@field.type.must_equal :float
|
187
|
+
end
|
188
|
+
|
189
|
+
it "must have 0.0 as default value" do
|
190
|
+
@field.default_value.must_equal 0.0
|
191
|
+
end
|
192
|
+
|
193
|
+
it "must not be a variable size field" do
|
194
|
+
@field.variable_size?.wont_equal true
|
195
|
+
end
|
196
|
+
|
197
|
+
it "must pass dumped value" do
|
198
|
+
@field.dump(-10.0).must_equal -10.0
|
199
|
+
end
|
200
|
+
|
201
|
+
it "must pass loaded value" do
|
202
|
+
@field.load(-10.0).must_equal -10.0
|
203
|
+
end
|
204
|
+
|
205
|
+
it "must produce proper metadata" do
|
206
|
+
@field.metadata.must_equal({:type => :float})
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "an ulong field" do
|
211
|
+
before do
|
212
|
+
@field = Rod::Property::Field.new(@klass,:tag,:ulong)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "must have ulong type" do
|
216
|
+
@field.type.must_equal :ulong
|
217
|
+
end
|
218
|
+
|
219
|
+
it "must have 0 as default value" do
|
220
|
+
@field.default_value.must_equal 0
|
221
|
+
end
|
222
|
+
|
223
|
+
it "must not be a variable size field" do
|
224
|
+
@field.variable_size?.wont_equal true
|
225
|
+
end
|
226
|
+
|
227
|
+
it "must pass dumped value if it is greater or equals 0" do
|
228
|
+
@field.dump(10.0).must_equal 10.0
|
229
|
+
@field.dump(0).must_equal 0
|
230
|
+
end
|
231
|
+
|
232
|
+
it "must raise exception when dumping value lower than 0" do
|
233
|
+
proc {@field.dump(-10)}.must_raise Rod::InvalidArgument
|
234
|
+
end
|
235
|
+
|
236
|
+
it "must pass loaded value" do
|
237
|
+
@field.load(10).must_equal 10
|
238
|
+
end
|
239
|
+
|
240
|
+
it "must produce proper metadata" do
|
241
|
+
@field.metadata.must_equal({:type => :ulong})
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'rod'
|
4
|
+
|
5
|
+
describe Rod::Property::PluralAssociation do
|
6
|
+
before do
|
7
|
+
@klass = MiniTest::Mock.new
|
8
|
+
@builder = MiniTest::Mock.new
|
9
|
+
@klass.expect :nil?,false
|
10
|
+
end
|
11
|
+
|
12
|
+
after do
|
13
|
+
@klass.verify
|
14
|
+
@builder.verify
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "a plural association" do
|
18
|
+
before do
|
19
|
+
@association = Rod::Property::PluralAssociation.new(@klass,:users,
|
20
|
+
:polymorphic => true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "must not be a field" do
|
24
|
+
@association.field?.wont_equal true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must be an association" do
|
28
|
+
@association.association?.must_equal true
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must not be a singular association" do
|
32
|
+
@association.singular?.wont_equal true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "must be a plural association" do
|
36
|
+
@association.plural?.must_equal true
|
37
|
+
end
|
38
|
+
|
39
|
+
it "must produce proper metadata" do
|
40
|
+
@association.metadata.must_equal({:polymorphic => true})
|
41
|
+
end
|
42
|
+
|
43
|
+
it "must define C accessors" do
|
44
|
+
@klass.expect :struct_name, "struct_name"
|
45
|
+
@builder.expect :c,nil,[String]
|
46
|
+
@association.define_c_accessors(@builder)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must seal C accessors" do
|
50
|
+
@klass.expect :send,nil,[:private,String]
|
51
|
+
@association.seal_c_accessors
|
52
|
+
end
|
53
|
+
|
54
|
+
it "must define getter" do
|
55
|
+
@klass.expect :send,nil,[:define_method,"users"]
|
56
|
+
@klass.expect :scope_name,"Rod"
|
57
|
+
@klass.expect :database, nil
|
58
|
+
@association.define_getter
|
59
|
+
end
|
60
|
+
|
61
|
+
it "must define setter" do
|
62
|
+
@klass.expect :send,nil,[:define_method,"users="]
|
63
|
+
@association.define_setter
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|