rod 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.travis.yml +1 -1
  2. data/README.rdoc +38 -10
  3. data/Rakefile +20 -9
  4. data/changelog.txt +25 -0
  5. data/contributors.txt +1 -0
  6. data/data/backward/0.7.0/_join_element.dat +0 -0
  7. data/data/backward/0.7.0/_polymorphic_join_element.dat +0 -0
  8. data/data/backward/0.7.0/char.dat +0 -0
  9. data/data/backward/0.7.0/database.yml +58 -0
  10. data/data/backward/0.7.0/rod_test__automobile.dat +0 -0
  11. data/data/backward/0.7.0/rod_test__caveman.dat +0 -0
  12. data/data/backward/0.7.0/rod_test__dog.dat +0 -0
  13. data/data/backward/0.7.0/rod_test__test_model.dat +0 -0
  14. data/data/portability/_join_element.dat +0 -0
  15. data/data/portability/_polymorphic_join_element.dat +0 -0
  16. data/data/portability/char.dat +0 -0
  17. data/data/portability/database.yml +49 -0
  18. data/data/portability/rod_test__automobile.dat +0 -0
  19. data/data/portability/rod_test__caveman.dat +0 -0
  20. data/data/portability/rod_test__dog.dat +0 -0
  21. data/data/portability/rod_test__test_model.dat +0 -0
  22. data/features/backward.feature +33 -0
  23. data/features/basic.feature +3 -0
  24. data/features/collection_proxy.feature +95 -0
  25. data/features/flat_indexing.feature +44 -2
  26. data/features/hash_indexing.feature +63 -9
  27. data/features/portability.feature +72 -0
  28. data/features/segmented_indexing.feature +45 -2
  29. data/features/steps/collection_proxy.rb +1 -1
  30. data/features/steps/model.rb +48 -5
  31. data/features/steps/rod.rb +15 -16
  32. data/lib/rod.rb +11 -1
  33. data/lib/rod/abstract_database.rb +52 -42
  34. data/lib/rod/berkeley/collection_proxy.rb +96 -0
  35. data/lib/rod/berkeley/database.rb +337 -0
  36. data/lib/rod/berkeley/environment.rb +209 -0
  37. data/lib/rod/berkeley/sequence.rb +222 -0
  38. data/lib/rod/berkeley/transaction.rb +233 -0
  39. data/lib/rod/collection_proxy.rb +76 -1
  40. data/lib/rod/constants.rb +3 -2
  41. data/lib/rod/database.rb +127 -14
  42. data/lib/rod/index/base.rb +12 -3
  43. data/lib/rod/index/hash_index.rb +295 -70
  44. data/lib/rod/index/segmented_index.rb +3 -0
  45. data/lib/rod/model.rb +154 -531
  46. data/lib/rod/property/base.rb +190 -0
  47. data/lib/rod/property/field.rb +258 -0
  48. data/lib/rod/property/plural_association.rb +145 -0
  49. data/lib/rod/property/singular_association.rb +139 -0
  50. data/rod.gemspec +6 -4
  51. data/spec/berkeley/database.rb +83 -0
  52. data/spec/berkeley/environment.rb +58 -0
  53. data/spec/berkeley/sequence.rb +101 -0
  54. data/spec/berkeley/transaction.rb +92 -0
  55. data/spec/collection_proxy.rb +38 -0
  56. data/spec/database.rb +36 -0
  57. data/spec/model.rb +26 -0
  58. data/spec/property/base.rb +73 -0
  59. data/spec/property/field.rb +244 -0
  60. data/spec/property/plural_association.rb +67 -0
  61. data/spec/property/singular_association.rb +65 -0
  62. data/tests/class_compatibility_create.rb +2 -2
  63. data/tests/eff1_test.rb +1 -1
  64. data/tests/eff2_test.rb +1 -1
  65. data/tests/full_runs.rb +1 -1
  66. data/tests/generate_classes_create.rb +14 -14
  67. data/tests/migration_create.rb +47 -47
  68. data/tests/migration_verify.rb +1 -1
  69. data/tests/missing_class_create.rb +6 -6
  70. data/tests/properties_order_create.rb +4 -4
  71. data/tests/read_on_create.rb +33 -34
  72. data/tests/save_struct.rb +40 -39
  73. data/tests/unit/database.rb +1 -1
  74. data/tests/unit/model_tests.rb +73 -65
  75. metadata +71 -15
  76. data/tests/unit/model.rb +0 -36
@@ -0,0 +1,139 @@
1
+ require 'rod/property/base'
2
+
3
+ module Rod
4
+ module Property
5
+ # This class defines the +has_one+ (singular association) property.
6
+ # A +has_one+ property has to define its +name+.
7
+ class SingularAssociation < Base
8
+ # Creates new singular association associated with +klass+,
9
+ # with given +name+ and +options+.
10
+ # Valid options are:
11
+ # * +:class_name+ - the name of the class (as String) associated
12
+ # with this class
13
+ # * +:polymorphic+ - if set to +true+ the association is polymorphic (allows to access
14
+ # objects of different classes via this association).
15
+ def initialize(klass,name,options={})
16
+ super(klass,name,options)
17
+ end
18
+
19
+ # Predicate indicating that this property is a field.
20
+ def field?
21
+ false
22
+ end
23
+
24
+ # Predicate indicating that this property is an association.
25
+ def association?
26
+ true
27
+ end
28
+
29
+ # Predicate indicating that this property is a singular association.
30
+ def singular?
31
+ true
32
+ end
33
+
34
+ # Predicate indicating that this property is not a plural association.
35
+ def plural?
36
+ false
37
+ end
38
+
39
+ # Predicate indicating that this property is polymorphic.
40
+ def polymorphic?
41
+ @options[:polymorphic]
42
+ end
43
+
44
+ # Returns the metadata of the association in form of a hash.
45
+ def metadata
46
+ @options.dup
47
+ end
48
+
49
+ # Converts the association to fields in a C struct.
50
+ def to_c_struct
51
+ result = " #{c_type(:ulong)} #{@name};\n"
52
+ if polymorphic?
53
+ result += " #{c_type(:ulong)} #{@name}__class;\n"
54
+ end
55
+ result
56
+ end
57
+
58
+ # Defines the accessor of the association's constituents
59
+ # (C struct field/fields that hold the association data).
60
+ def define_c_accessors(builder)
61
+ field_reader(@name,@klass.struct_name,c_type(:ulong),builder)
62
+ field_writer(@name,@klass.struct_name,c_type(:ulong),builder)
63
+ if polymorphic?
64
+ field_reader("#{@name}__class",@klass.struct_name,c_type(:ulong),builder)
65
+ field_writer("#{@name}__class",@klass.struct_name,c_type(:ulong),builder)
66
+ end
67
+ end
68
+
69
+ # Make the C accessors private.
70
+ def seal_c_accessors
71
+ @klass.send(:private,"_#{@name}")
72
+ @klass.send(:private,"_#{@name}=")
73
+ end
74
+
75
+ # Defines the getter of the Ruby class which corresponds to this association.
76
+ def define_getter
77
+ # optimization
78
+ name = @name.to_s
79
+ property = self
80
+ class_name =
81
+ if @options[:class_name]
82
+ @options[:class_name]
83
+ else
84
+ "#{@klass.scope_name}::#{name.camelcase}"
85
+ end
86
+ klass = options[:polymorphic] ? nil : class_name.constantize
87
+ @klass.send(:define_method,name) do
88
+ value = instance_variable_get("@#{name}")
89
+ if value.nil?
90
+ return nil if self.new?
91
+ rod_id = send("_#{name}",@rod_id)
92
+ # the indices are shifted by 1, to leave 0 for nil
93
+ if rod_id == 0
94
+ value = nil
95
+ else
96
+ if property.polymorphic?
97
+ klass = Model.get_class(send("_#{name}__class",@rod_id))
98
+ end
99
+ value = klass.find_by_rod_id(rod_id)
100
+ end
101
+ # avoid change tracking
102
+ instance_variable_set("@#{name}",value)
103
+ end
104
+ value
105
+ end
106
+ end
107
+
108
+ # Defines the settor of the Ruby class which corresponds to this association.
109
+ def define_setter
110
+ # optimization
111
+ name = @name.to_s
112
+ @klass.send(:define_method,"#{name}=") do |value|
113
+ old_value = send(name)
114
+ send("#{name}_will_change!") unless old_value == value
115
+ instance_variable_set("@#{name}", value)
116
+ value
117
+ end
118
+ end
119
+
120
+ # Returns the memory layout of the C struct fields that
121
+ # correspond to this association.
122
+ def layout
123
+ unless polymorphic?
124
+ "#{@name}[value:#{sizeof(:ulong)}]"
125
+ else
126
+ "#{@name}[value:#{sizeof(:ulong)}+" +
127
+ "class:#{sizeof(:ulong)}]"
128
+ end
129
+ end
130
+
131
+ protected
132
+ # Check if the property has valid options.
133
+ # An exceptions is raised if they are not.
134
+ def check_options(options)
135
+ #TODO implement
136
+ end
137
+ end
138
+ end
139
+ end
@@ -11,8 +11,8 @@ Gem::Specification.new do |s|
11
11
  s.authors = ['Aleksander Pohl']
12
12
  s.email = ["apohllo@o2.pl"]
13
13
  s.homepage = "http://github.com/apohllo/rod"
14
- s.summary = "Ruby object database"
15
- s.description = "Ruby object database is designed for large amount of data, whose structure rarely changes."
14
+ s.summary = "Ruby Object Database"
15
+ s.description = "Ruby Object Database is designed for large amounts of data, whose structure rarely changes."
16
16
 
17
17
  s.rubyforge_project = "rod"
18
18
  s.rdoc_options = ["--main", "README.rdoc"]
@@ -24,10 +24,12 @@ Gem::Specification.new do |s|
24
24
 
25
25
  s.add_dependency("RubyInline", [">= 3.10.0","< 4.0.0"])
26
26
  s.add_dependency("english", [">= 0.5.0","< 0.6.0"])
27
- s.add_dependency("activemodel", [">= 3.0.7","< 3.1.0"])
27
+ s.add_dependency("activemodel", ["~> 3.2.2"])
28
28
  s.add_dependency("bsearch", [">= 1.5.0","< 1.6.0"])
29
- s.add_development_dependency("mocha", [">= 0.9.8","< 1.0.0"])
29
+
30
+ s.add_development_dependency("mocha", "~> 0.9.8")
30
31
  s.add_development_dependency("cucumber", "~> 1.0.0")
31
32
  s.add_development_dependency("rspec", [">= 2.2.0","< 2.3.0"])
32
33
  s.add_development_dependency("rake", [">= 0.9.0","< 1.0.0"])
34
+ s.add_development_dependency("minitest", "~> 2.7.0")
33
35
  end
@@ -0,0 +1,83 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/autorun'
3
+ require 'rod'
4
+
5
+ describe Rod::Berkeley::Database do
6
+ describe "a database" do
7
+ before do
8
+ environment = Rod::Berkeley::Environment.new
9
+ environment.open("tmp/env_db", :create => true, :cache => true)
10
+ @database = Rod::Berkeley::Database.new(environment)
11
+ end
12
+
13
+ after do
14
+ @database.close
15
+ @database.environment.close
16
+ end
17
+
18
+ it "should not be in opened state befor being opened" do
19
+ @database.opened?.must_equal false
20
+ end
21
+
22
+ it "should allow to open itself" do
23
+ proc {@database.open("db1.db", :hash, :create => true, :truncate => true)}.must_be_silent
24
+ end
25
+
26
+ it "should be in opened state after being opened" do
27
+ @database.open("db1.db", :hash, :create => true, :truncate => true)
28
+ @database.opened?.must_equal true
29
+ end
30
+
31
+ it "should not allow to open itself twice" do
32
+ @database.open("db1.db", :hash, :create => true, :truncate => true)
33
+ proc {@database.open("db1.db", :hash, :create => true, :truncate => true)}.must_raise Rod::DatabaseError
34
+ end
35
+
36
+ it "should allow to close itself" do
37
+ proc {@database.close}.must_be_silent
38
+ end
39
+
40
+ it "should not be in opened state after being closed" do
41
+ @database.open("db1.db", :hash, :create => true, :truncate => true)
42
+ @database.close
43
+ @database.opened?.must_equal false
44
+ end
45
+ end
46
+
47
+ describe "a hash database with transactions enabled" do
48
+ before do
49
+ environment = Rod::Berkeley::Environment.new
50
+ environment.open("tmp/env_txn", :create => true, :cache => true, :transactions => true,
51
+ :logging => true, :locking => true)
52
+ @database = Rod::Berkeley::Database.new(environment)
53
+ @database.open("db1.db", :hash, :create => true, :auto_commit => true)
54
+ end
55
+
56
+ after do
57
+ @database.close
58
+ @database.environment.close
59
+ end
60
+
61
+ it "should allow to add data with transactional protection" do
62
+ transaction = Rod::Berkeley::Transaction.new(@database.environment)
63
+ transaction.begin
64
+ @database.put("Ruby","Matz",transaction)
65
+ transaction.commit
66
+
67
+ transaction.reset
68
+ transaction.begin
69
+ @database.get("Ruby").must_equal "Matz"
70
+ transaction.commit
71
+
72
+ transaction.reset
73
+ transaction.begin
74
+ @database.put("Ruby","Matsumoto San",transaction)
75
+ transaction.abort
76
+
77
+ transaction.reset
78
+ transaction.begin
79
+ @database.get("Ruby").must_equal "Matz"
80
+ transaction.commit
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,58 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/autorun'
3
+ require 'rod'
4
+
5
+ describe Rod::Berkeley::Environment do
6
+ describe "an environment" do
7
+ before do
8
+ @environment = Rod::Berkeley::Environment.new
9
+ end
10
+
11
+ after do
12
+ @environment.close
13
+ end
14
+
15
+ it "should not be in opened state before being opened" do
16
+ @environment.opened?.must_equal false
17
+ end
18
+
19
+ it "should allow to open itself" do
20
+ proc {@environment.open("tmp/env", :create => true)}.must_be_silent
21
+ end
22
+
23
+ it "should not allow to open it twice" do
24
+ @environment.open("tmp/env", :create => true)
25
+ proc {@environment.open("tmp/env")}.must_raise Rod::DatabaseError
26
+ end
27
+
28
+ it "should be in opened state after being opened" do
29
+ @environment.open("tmp/env", :create => true)
30
+ @environment.opened?.must_equal true
31
+ end
32
+
33
+ it "should not be in opened state after being closed" do
34
+ @environment.open("tmp/env", :create => true)
35
+ @environment.close
36
+ @environment.opened?.must_equal false
37
+ end
38
+ end
39
+
40
+ describe "an opened environment" do
41
+ before do
42
+ @environment = Rod::Berkeley::Environment.new
43
+ @environment.open("tmp/env", :create => true)
44
+ end
45
+
46
+ after do
47
+ @environment.close
48
+ end
49
+
50
+ it "should be in opened state" do
51
+ @environment.opened?.must_equal true
52
+ end
53
+
54
+ it "should allow to close it" do
55
+ proc {@environment.close}.must_be_silent
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,101 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/autorun'
3
+ require 'rod'
4
+
5
+ describe Rod::Berkeley::Sequence do
6
+ describe "a sequence" do
7
+ before do
8
+ environment = Rod::Berkeley::Environment.new
9
+ environment.open("tmp/env_seq", :create => true, :cache => true)
10
+ database = Rod::Berkeley::Database.new(environment)
11
+ database.open("db1.db", :hash, :create => true, :truncate => true)
12
+ @sequence = Rod::Berkeley::Sequence.new(database)
13
+ end
14
+
15
+ after do
16
+ @sequence.close
17
+ @sequence.database.close
18
+ @sequence.database.environment.close
19
+ end
20
+
21
+ it "should allow to open itself with 'sequence' as the key" do
22
+ proc {@sequence.open("sequence", nil, :create => true)}.must_be_silent
23
+ end
24
+
25
+ it "should allow to close itself" do
26
+ @sequence.open("sequence", nil, :create => true)
27
+ proc {@sequence.close}.must_be_silent
28
+ end
29
+ end
30
+
31
+ describe "an opened sequence" do
32
+ before do
33
+ environment = Rod::Berkeley::Environment.new
34
+ environment.open("tmp/env_seq", :create => true, :cache => true)
35
+ database = Rod::Berkeley::Database.new(environment)
36
+ database.open("db1.db", :hash, :create => true, :truncate => true)
37
+ @sequence = Rod::Berkeley::Sequence.new(database)
38
+ @sequence.open("sequence", nil, :create => true)
39
+ end
40
+
41
+ after do
42
+ @sequence.close
43
+ @sequence.database.close
44
+ @sequence.database.environment.close
45
+ end
46
+
47
+ it "should return 1 as its first value" do
48
+ @sequence.next.must_equal 1
49
+ end
50
+
51
+ it "should return 3 as the second value with delta set to 2" do
52
+ @sequence.next(nil,:delta => 2)
53
+ @sequence.next.must_equal 3
54
+ end
55
+ end
56
+
57
+ describe "an opened sequence with large cache" do
58
+ before do
59
+ environment = Rod::Berkeley::Environment.new
60
+ environment.open("tmp/env_seq_txn", :create => true, :cache => true,
61
+ :transactions => true, :logging => true, :locking => true)
62
+ database = Rod::Berkeley::Database.new(environment)
63
+ database.open("db1.db", :hash, :create => true, :auto_commit => true)
64
+ @sequence = Rod::Berkeley::Sequence.new(database)
65
+ @sequence.open("sequence", nil, :create => true, :cache_size => 1000)
66
+ end
67
+
68
+ after do
69
+ @sequence.close
70
+ @sequence.database.close
71
+ @sequence.database.environment.close
72
+ end
73
+
74
+ it "should retrive 100 000 values fast" do
75
+ 100_000.times{ @sequence.next}
76
+ end
77
+ end
78
+
79
+ describe "an opened sequence with small cache" do
80
+ before do
81
+ environment = Rod::Berkeley::Environment.new
82
+ environment.open("tmp/env_seq_txn", :create => true, :cache => true,
83
+ :transactions => true, :logging => true, :locking => true)
84
+ database = Rod::Berkeley::Database.new(environment)
85
+ database.open("db1.db", :hash, :create => true, :auto_commit => true)
86
+ @sequence = Rod::Berkeley::Sequence.new(database)
87
+ @sequence.open("sequence", nil, :create => true)
88
+ end
89
+
90
+ after do
91
+ @sequence.close
92
+ @sequence.database.close
93
+ @sequence.database.environment.close
94
+ end
95
+
96
+ it "should retrive 100 000 values fast is syncing is disabled" do
97
+ 100_000.times{ @sequence.next(nil, :no_sync => true)}
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,92 @@
1
+ require 'bundler/setup'
2
+ require 'minitest/autorun'
3
+ require 'rod'
4
+
5
+ describe Rod::Berkeley::Transaction do
6
+ describe "a transaction" do
7
+ before do
8
+ environment = Rod::Berkeley::Environment.new
9
+ environment.open("tmp/env_txn", :create => true, :cache => true, :transactions => true,
10
+ :logging => true, :locking => true)
11
+ @transaction = Rod::Berkeley::Transaction.new(environment)
12
+ end
13
+
14
+ after do
15
+ @transaction.finish
16
+ @transaction.environment.close
17
+ end
18
+
19
+ it "should not be in started state after creation" do
20
+ @transaction.started?.must_equal false
21
+ end
22
+
23
+ it "should not be in finished state after creation" do
24
+ @transaction.finished?.must_equal false
25
+ end
26
+
27
+ it "should allow to start itself" do
28
+ proc {@transaction.begin}.must_be_silent
29
+ end
30
+
31
+ it "should allow to start itself in no_sync mode" do
32
+ proc {@transaction.begin(:no_sync => true)}.must_be_silent
33
+ end
34
+
35
+ it "should allow to start itself in sync mode" do
36
+ proc {@transaction.begin(:sync => true)}.must_be_silent
37
+ end
38
+
39
+ it "should allow to start itself in write_no_sync mode" do
40
+ proc {@transaction.begin(:write_no_sync => true)}.must_be_silent
41
+ end
42
+
43
+ it "should be in started state after being started" do
44
+ @transaction.begin
45
+ @transaction.started?.must_equal true
46
+ end
47
+
48
+ it "should not be in finished state after being started" do
49
+ @transaction.begin
50
+ @transaction.finished?.must_equal false
51
+ end
52
+
53
+ it "should be in started state after being committed" do
54
+ @transaction.begin
55
+ @transaction.commit
56
+ @transaction.started?.must_equal true
57
+ end
58
+
59
+ it "should be in finished state after being committed" do
60
+ @transaction.begin
61
+ @transaction.commit
62
+ @transaction.finished?.must_equal true
63
+ end
64
+
65
+ it "should be in started state after being aborted" do
66
+ @transaction.begin
67
+ @transaction.abort
68
+ @transaction.started?.must_equal true
69
+ end
70
+
71
+ it "should be in finished state after being aborted" do
72
+ @transaction.begin
73
+ @transaction.abort
74
+ @transaction.finished?.must_equal true
75
+ end
76
+
77
+ it "should allow to reset itself before being started" do
78
+ proc {@transaction.reset}.must_be_silent
79
+ end
80
+
81
+ it "should allow to reset itself after being finished" do
82
+ @transaction.begin
83
+ @transaction.abort
84
+ proc {@transaction.reset}.must_be_silent
85
+ end
86
+
87
+ it "should not allow to reset itself before being finished" do
88
+ @transaction.begin
89
+ proc {@transaction.reset}.must_raise Rod::DatabaseError
90
+ end
91
+ end
92
+ end