ObjectModel 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.
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