ObjectModel 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/README +849 -0
  2. data/lib/ObjectModel.res/config.yaml +5 -0
  3. data/lib/ObjectModel/AnEntity/BackReferences.rb +113 -0
  4. data/lib/ObjectModel/AnEntity/Bag.rb +129 -0
  5. data/lib/ObjectModel/AnEntity/BagCopy.rb +29 -0
  6. data/lib/ObjectModel/AnEntity/ChildrenBag.rb +10 -0
  7. data/lib/ObjectModel/AnEntity/EntityCopy.rb +38 -0
  8. data/lib/ObjectModel/AnEntity/EntityType.rb +408 -0
  9. data/lib/ObjectModel/AnEntity/ReferencesBag.rb +10 -0
  10. data/lib/ObjectModel/AnEntity/entity_cm.rb +108 -0
  11. data/lib/ObjectModel/Entity.rb +278 -0
  12. data/lib/ObjectModel/Errors/LoadError.rb +3 -0
  13. data/lib/ObjectModel/Errors/NoTransactionError.rb +3 -0
  14. data/lib/ObjectModel/Errors/NotFoundError.rb +2 -0
  15. data/lib/ObjectModel/Errors/OutdatedError.rb +8 -0
  16. data/lib/ObjectModel/Errors/ValidationError.rb +3 -0
  17. data/lib/ObjectModel/Indexes/HashIndex.rb +64 -0
  18. data/lib/ObjectModel/Indexes/IndexStorage.rb +64 -0
  19. data/lib/ObjectModel/Indexes/Manager.rb +72 -0
  20. data/lib/ObjectModel/Metadata.rb +34 -0
  21. data/lib/ObjectModel/Metadata.res/after_event_types.rb +25 -0
  22. data/lib/ObjectModel/Metadata.res/attribute_types_shortcuts.rb +10 -0
  23. data/lib/ObjectModel/Metadata.res/before_event_types.rb +25 -0
  24. data/lib/ObjectModel/Metadata.res/child_types_shortcuts.rb +4 -0
  25. data/lib/ObjectModel/Metadata.res/metadata_checks.rb +9 -0
  26. data/lib/ObjectModel/Metadata.res/reference_types_shortcuts.rb +4 -0
  27. data/lib/ObjectModel/Metadata/DSL.rb +11 -0
  28. data/lib/ObjectModel/Metadata/attribute.rb +56 -0
  29. data/lib/ObjectModel/Metadata/child.rb +50 -0
  30. data/lib/ObjectModel/Metadata/events.rb +109 -0
  31. data/lib/ObjectModel/Metadata/name.rb +20 -0
  32. data/lib/ObjectModel/Metadata/reference.rb +50 -0
  33. data/lib/ObjectModel/Metadata/require.rb +10 -0
  34. data/lib/ObjectModel/Metadata/validate.rb +66 -0
  35. data/lib/ObjectModel/Repository.rb +326 -0
  36. data/lib/ObjectModel/Repository/EventProcessor.rb +58 -0
  37. data/lib/ObjectModel/Repository/ObjectStorage.rb +102 -0
  38. data/lib/ObjectModel/Repository/StreamID.rb +20 -0
  39. data/lib/ObjectModel/Repository/StreamStorage.rb +121 -0
  40. data/lib/ObjectModel/Repository/SystemListener.rb +143 -0
  41. data/lib/ObjectModel/Repository/Transaction.rb +63 -0
  42. data/lib/ObjectModel/Repository/TransactionProcessor.rb +36 -0
  43. data/lib/ObjectModel/Tools/DefaultTransactionStrategy.rb +9 -0
  44. data/lib/ObjectModel/Tools/InMemoryCache.rb +9 -0
  45. data/lib/ObjectModel/Tools/NoCache.rb +18 -0
  46. data/lib/ObjectModel/Tools/OGLRUCache.rb +37 -0
  47. data/lib/ObjectModel/Types/BagType.rb +94 -0
  48. data/lib/ObjectModel/Types/BooleanType.rb +42 -0
  49. data/lib/ObjectModel/Types/ClassType.rb +43 -0
  50. data/lib/ObjectModel/Types/DataType.rb +44 -0
  51. data/lib/ObjectModel/Types/DateType.rb +43 -0
  52. data/lib/ObjectModel/Types/NumberType.rb +62 -0
  53. data/lib/ObjectModel/Types/ObjectType.rb +164 -0
  54. data/lib/ObjectModel/Types/ProcType.rb +43 -0
  55. data/lib/ObjectModel/Types/SingleType.rb +59 -0
  56. data/lib/ObjectModel/Types/StringType.rb +39 -0
  57. data/lib/ObjectModel/_require.rb +43 -0
  58. data/lib/ObjectModel/require.rb +1 -0
  59. data/rakefile +62 -0
  60. data/spec/ObjectModel/BasicSpec/BaseClass.rb +7 -0
  61. data/spec/ObjectModel/BasicSpec/BaseTypes.rb +11 -0
  62. data/spec/ObjectModel/BasicSpec/Descendant.rb +5 -0
  63. data/spec/ObjectModel/BasicSpec/EachTest.rb +14 -0
  64. data/spec/ObjectModel/BasicSpec/UpChild.rb +10 -0
  65. data/spec/ObjectModel/BasicSpec/UpParent.rb +11 -0
  66. data/spec/ObjectModel/ErrorsSpec/AfterCommitError.rb +9 -0
  67. data/spec/ObjectModel/ExtendedSpec/CustomInitialization.rb +11 -0
  68. data/spec/ObjectModel/ExtendedSpec/UpNotNil.rb +8 -0
  69. data/spec/ObjectModel/ExtendedSpec/UpParent.rb +11 -0
  70. data/spec/ObjectModel/ValidationSpec/BaseTypes.rb +11 -0
  71. data/spec/aspect_spec.rb +55 -0
  72. data/spec/back_references_spec.rb +161 -0
  73. data/spec/basic_spec.rb +162 -0
  74. data/spec/cascade_delete_spec.rb +168 -0
  75. data/spec/complex_events_spec.rb +134 -0
  76. data/spec/concurrency_spec.rb +186 -0
  77. data/spec/containment_spec.rb +146 -0
  78. data/spec/data_migration_spec.rb +51 -0
  79. data/spec/errors_spec.rb +65 -0
  80. data/spec/events_spec.rb +173 -0
  81. data/spec/extended_spec.rb +171 -0
  82. data/spec/indexing_spec.rb +56 -0
  83. data/spec/set_in_memory.rb +2 -0
  84. data/spec/set_no_cache.rb +2 -0
  85. data/spec/smoke_test_spec.rb +85 -0
  86. data/spec/stream_spec.rb +143 -0
  87. data/spec/stream_storage.rb +148 -0
  88. data/spec/timer.rb +5 -0
  89. data/spec/validation_spec.rb +87 -0
  90. metadata +186 -0
@@ -0,0 +1,168 @@
1
+ require 'ObjectModel/require'
2
+ require 'spec'
3
+
4
+ module ObjectModel
5
+ module CascadeDelete
6
+ describe "Events" do
7
+ class CompositeEntity
8
+ inherit Entity
9
+ metadata do
10
+ child :child
11
+ child :children, :bag
12
+ end
13
+ end
14
+
15
+ class EnityDeleteAllChildren
16
+ inherit Entity
17
+ metadata do
18
+ child :child
19
+ child :child2
20
+ end
21
+ end
22
+
23
+ it "Shouldn't allow to assign non-Entities to Children" do
24
+ lambda{
25
+ @r.transaction{
26
+ @r['e'].child = "string"
27
+ }.commit
28
+ }.should raise_error(/Child should be Entity or Nil/)
29
+
30
+ lambda{
31
+ @r.transaction{
32
+ @r['e'].children << "string"
33
+ }.commit
34
+ }.should raise_error(/Child should be Entity or Nil/)
35
+ end
36
+
37
+ it "Shouldn't allow to assign self as Child" do
38
+ lambda{
39
+ @r.transaction{
40
+ entity = @r['e']
41
+ entity.child = entity
42
+ }.commit
43
+ }.should raise_error(/Forbiden to add self as Child/)
44
+ end
45
+
46
+ it "Shouldn't allow to assign the same Child twice (for the same Entity)" do
47
+ lambda{
48
+ @r.transaction{
49
+ entity = @r['e']
50
+ child = CompositeEntity.new 'child'
51
+ entity.child = child
52
+ entity.children << child
53
+ }.commit
54
+ }.should raise_error(/Forbiden to add the same Child twice/)
55
+ end
56
+
57
+ it "Delete should delete Entity from it's Parent Childrens" do
58
+ @r.transaction{
59
+ p = CompositeEntity.new 'parent'
60
+
61
+ c1 = CompositeEntity.new 'child1'
62
+ c2 = CompositeEntity.new 'child2'
63
+
64
+ p.child = c1
65
+ p.children << c2
66
+ }.commit
67
+
68
+ @r.transaction{
69
+ @r['parent/child1'].delete
70
+ @r['parent/child2'].delete
71
+ }.commit
72
+
73
+ @r['parent'].child.should be_nil
74
+ @r['parent'].children.should be_empty
75
+ end
76
+
77
+ it "Should also delete all Children for_deleted Entity" do
78
+ @r.transaction{
79
+ p = CompositeEntity.new 'parent'
80
+
81
+ c1 = CompositeEntity.new 'child1'
82
+ c2 = CompositeEntity.new 'child2'
83
+
84
+ p.child = c1
85
+ p.children << c2
86
+ }.commit
87
+
88
+ @r.should_not include('child1')
89
+ @r.should_not include('child2')
90
+
91
+ @r.transaction{
92
+ @r['parent'].delete
93
+ }.commit
94
+
95
+ @r.should_not include('parent')
96
+ @r.should_not include('child1')
97
+ @r.should_not include('child2')
98
+ @r.should_not include('parent/child1')
99
+ @r.should_not include('parent/child1')
100
+ end
101
+
102
+ it "Should also delete all Children Entity (from error)" do
103
+ @r.transaction{
104
+ p = EnityDeleteAllChildren.new 'parent'
105
+
106
+ c1 = EnityDeleteAllChildren.new 'child1'
107
+ c2 = EnityDeleteAllChildren.new 'child2'
108
+
109
+ p.child = c1
110
+ p.child2 = c2
111
+ }.commit
112
+
113
+ @r.transaction{
114
+ @r['parent'].delete
115
+ }.commit
116
+
117
+ @r.should_not include('child1')
118
+ @r.should_not include('child2')
119
+ @r.should_not include('parent/child1')
120
+ @r.should_not include('parent/child1')
121
+ end
122
+
123
+ it "Deleting Child from Children should also delete Child.parent but not delete Child themself" do
124
+ @r.transaction{
125
+ p = CompositeEntity.new 'parent'
126
+
127
+ c1 = CompositeEntity.new 'child1'
128
+ c2 = CompositeEntity.new 'child2'
129
+
130
+ p.child = c1
131
+ p.children << c2
132
+ }.commit
133
+
134
+ tr = @r.transaction{
135
+ p = @r['parent']
136
+ p.child = nil
137
+ p.children.clear
138
+ }
139
+ @r['parent'].child.should_not be_nil
140
+ @r['parent/child1'].parent.should_not be_nil
141
+ @r['parent/child2'].parent.should_not be_nil
142
+
143
+ tr.commit
144
+ @r['parent'].child.should be_nil
145
+ @r['parent'].children.should be_empty
146
+ @r['child1'].parent.should be_nil
147
+ @r['child2'].parent.should be_nil
148
+ @r.should include('child1')
149
+ @r.should include('child2')
150
+ @r.should_not include('parent/child1')
151
+ @r.should_not include('parent/child2')
152
+ end
153
+
154
+ before :each do
155
+ ObjectModel::CONFIG[:directory] = "#{File.dirname __FILE__}/data"
156
+
157
+ Repository.delete :test
158
+ @r = Repository.new :test
159
+ @r.transaction{CompositeEntity.new 'e'}.commit
160
+ end
161
+
162
+ after :each do
163
+ @r.close
164
+ Repository.delete :test
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,134 @@
1
+ require 'ObjectModel/require'
2
+ require 'spec'
3
+
4
+ module ObjectModel
5
+ module ComplexEventsSpec
6
+ describe "Events" do
7
+ class MockListener
8
+ attr_reader :events, :arguments
9
+ def initialize
10
+ @events, @arguments = [], []
11
+ end
12
+
13
+ def method_missing m, *p, &b
14
+ @events << m
15
+ @arguments << p
16
+ end
17
+
18
+ def respond_to? symbol
19
+ true
20
+ end
21
+
22
+ def clear
23
+ @events.clear
24
+ end
25
+ end
26
+
27
+ class BeforeRollbackEntity
28
+ inherit Entity
29
+ metadata do
30
+ before :new do
31
+ raise "abort"
32
+ end
33
+ end
34
+ end
35
+
36
+ class AfterRollbackEntity
37
+ inherit Entity
38
+ metadata do
39
+ after :new do
40
+ raise "abort"
41
+ end
42
+ end
43
+ end
44
+
45
+ it "Should Rollback Transaction if Exception is thrown during Before & After Event" do
46
+ lambda{
47
+ @r.transaction{BeforeRollbackEntity.new 'e'}.commit
48
+ }.should raise_error(/abort/)
49
+ @r.should_not include('e')
50
+
51
+ lambda{
52
+ @r.transaction{AfterRollbackEntity.new 'e'}.commit
53
+ }.should raise_error(/abort/)
54
+ @r.should_not include('e')
55
+ end
56
+
57
+ class AfterCommitEntity
58
+ inherit Entity
59
+ metadata do
60
+ after :commit do
61
+ raise "abort"
62
+ end
63
+ end
64
+ end
65
+
66
+ it "Shouldn't Rollback Transaction if Exception is thrown during after_commit" do
67
+ lambda{
68
+ @r.transaction{AfterCommitEntity.new 'e'}.commit
69
+ }.should raise_error(/abort/)
70
+ @r.should include('e')
71
+ end
72
+
73
+ class User
74
+ inherit Entity
75
+ metadata do
76
+ child :folder
77
+ after :new do |e|
78
+ e.folder = UserFolder.new "#{e.name} folder"
79
+ end
80
+ end
81
+ end
82
+
83
+ class UserFolder
84
+ inherit Entity
85
+ metadata{}
86
+ end
87
+
88
+ it "Changing another Entity during Event" do
89
+ @r.transaction{User.new 'u'}.commit
90
+ @r['u'].folder.name.should == "u folder"
91
+ end
92
+
93
+ class BaseEntity
94
+ inherit Entity
95
+ metadata do
96
+ after :new do
97
+ BaseEntity.events << "base"
98
+ end
99
+ end
100
+
101
+ def self.events
102
+ @events ||= []
103
+ end
104
+ end
105
+
106
+ class DescendantEntity < BaseEntity
107
+ metadata do
108
+ after :new do
109
+ BaseEntity.events << "descendant"
110
+ end
111
+ end
112
+ end
113
+
114
+ it "Events call sequence, first SuperClass Events should be called" do
115
+ @r.transaction{DescendantEntity.new 'de'}.commit
116
+ BaseEntity.events.should == ["base", "descendant"]
117
+ end
118
+
119
+ before :each do
120
+ ObjectModel::CONFIG[:directory] = "#{File.dirname __FILE__}/data"
121
+
122
+ Repository.delete :test
123
+ @r = Repository.new :test
124
+ @l = MockListener.new
125
+ @r.entity_listeners << @l
126
+ end
127
+
128
+ after :each do
129
+ @r.close
130
+ Repository.delete :test
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,186 @@
1
+ require 'ObjectModel/require'
2
+ require 'spec'
3
+ require "#{File.dirname(__FILE__)}/timer"
4
+
5
+ module ObjectModel
6
+ module ConcurrencySpec
7
+ describe "Concurrency" do
8
+ class SimpleEntity
9
+ inherit Entity
10
+ metadata do
11
+ attribute :label, :string
12
+ attribute :value, :number
13
+ end
14
+ end
15
+
16
+ before :each do
17
+ ObjectModel::CONFIG[:directory] = "#{File.dirname __FILE__}/data"
18
+
19
+ Repository.delete :test
20
+ @r = Repository.new :test
21
+ end
22
+
23
+ after :each do
24
+ @r.close
25
+ Repository.delete :test
26
+ end
27
+
28
+ it "Should raise Error if update is outdated" do
29
+ @r.transaction{
30
+ SimpleEntity.new 'one'
31
+ }.commit
32
+
33
+ t1 = Thread.new do
34
+ lambda{
35
+ tr = @r.transaction{
36
+ @r['one'].label = "name one"
37
+ }
38
+ sleep 0.5
39
+ tr.commit
40
+ }.should raise_error(OutdatedError)
41
+ end
42
+
43
+ t2 = Thread.new do
44
+ @r.transaction{
45
+ @r['one'].label = "name two"
46
+ }.commit
47
+ end
48
+ t1.join; t2.join
49
+ @r['one'].label.should == "name two"
50
+ end
51
+
52
+ it "General concurrency test" do
53
+ @r.transaction{
54
+ from = SimpleEntity.new 'from'
55
+ from.value = 5
56
+ to = SimpleEntity.new 'to'
57
+ to.value = 0
58
+ }.commit
59
+
60
+ threads = []
61
+ 20.times do
62
+ threads << Thread.new do
63
+ catch :done do
64
+ while true do
65
+ @r.isolate do
66
+ throw :done if @r['from'].value <= 0
67
+
68
+ sleep(rand(10) / 1000.0)
69
+
70
+ begin
71
+ @r.transaction{
72
+ @r['from'].value -= 1
73
+ @r['to'].value += 1
74
+ }.commit
75
+ rescue OutdatedError
76
+ next
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ threads.each{|t| t.join}
84
+
85
+ @r['from'].value.should == 0
86
+ @r['to'].value.should == 5
87
+ end
88
+
89
+ # # There are 2 read_streamers and 2 put_streamrs, read_streamers should works in parallel, put_streamrs exclusivelly
90
+ # #
91
+ # # 4x5-----8 put_streamr 2
92
+ # # 2x3---5 put_streamr 1
93
+ # # 0-1 read_streamer 2
94
+ # # 0-----3 7x8-9 read_streamer 1
95
+ # # 0 1 2 3 4 5 6 7 8 9 timeline
96
+ # #
97
+ # it "'read' operations should works in parallel and 'write' exclusivelly" do
98
+ # copy = @r.copy
99
+ # copy[:first] = SimpleEntity.new :first
100
+ # copy[:second] = SimpleEntity.new :second
101
+ # @r.commit
102
+ #
103
+ # timer = Timer.new
104
+ # r1 = mock("read 1")
105
+ # r1.should_receive(:created).with(0)
106
+ # r1.should_receive(:start).with(0)
107
+ # r1.should_receive(:finish).with(3)
108
+ # Thread.new do
109
+ # r1.created timer.time
110
+ # @r.isolate do
111
+ # r1.start timer.time
112
+ # @r[:first]
113
+ # sleep 3
114
+ # @r[:second]
115
+ # r1.finish timer.time
116
+ # end
117
+ # end
118
+ #
119
+ # r2 = mock("read 2")
120
+ # r2.should_receive(:created).with(0)
121
+ # r2.should_receive(:start).with(0)
122
+ # r2.should_receive(:finish).with(1)
123
+ # Thread.new do
124
+ # r2.created timer.time
125
+ # @r.isolate do
126
+ # r2.start timer.time
127
+ # @r[:first]
128
+ # sleep 1
129
+ # @r[:second]
130
+ # r2.finish timer.time
131
+ # end
132
+ # end
133
+ #
134
+ # sleep 2
135
+ #
136
+ # w1 = mock("write 1")
137
+ # w1.should_receive(:created).with(2)
138
+ # w1.should_receive(:start).with(3)
139
+ # w1.should_receive(:finish).with(5)
140
+ # Thread.new do
141
+ # w1.created timer.time
142
+ # @r.isolate do
143
+ # copy = @r[:first].copy
144
+ # copy.value = 'new value'
145
+ # @r.om_engine.engine_commit_debug(2){w1.start timer.time} # Should sleep for 2 sec
146
+ # w1.finish timer.time
147
+ # end
148
+ # end
149
+ #
150
+ # sleep 2
151
+ #
152
+ # w2 = mock("write 2")
153
+ # w2.should_receive(:created).with(4)
154
+ # w2.should_receive(:start).with(5)
155
+ # w2.should_receive(:finish).with(8)
156
+ # Thread.new do
157
+ # w2.created timer.time
158
+ # @r.isolate do
159
+ # copy = @r[:first].copy
160
+ # copy.value = "new value 2"
161
+ # @r.om_engine.engine_commit_debug(3){w2.start timer.time;} # Should sleep for 2 sec
162
+ # w2.finish timer.time
163
+ # end
164
+ # end
165
+ #
166
+ # sleep 3
167
+ #
168
+ # r11 = mock("put_streamr 2")
169
+ # r11.should_receive(:created).with(7)
170
+ # r11.should_receive(:start).with(8)
171
+ # r11.should_receive(:finish).with(9)
172
+ # t = Thread.new do
173
+ # r11.created timer.time
174
+ # @r.isolate do
175
+ # r11.start timer.time
176
+ # @r[:first]
177
+ # sleep 1
178
+ # @r[:second]
179
+ # r11.finish timer.time
180
+ # end
181
+ # end
182
+ # t.join
183
+ # end
184
+ end
185
+ end
186
+ end