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,63 @@
1
+ class Transaction
2
+ attr_reader :copies, :name, :new_entities, :event_processor, :repository, :system_listener, :deleted_entities
3
+ attr_writer :repository, :name
4
+ attr_accessor :managed
5
+
6
+ def initialize
7
+ @name = "default"
8
+ @copies = Hash.new{|hash, key| raise "Can't find Copy for '#{key}'entity_id!"}
9
+ @new_entities = Hash.new{|hash, key| raise "Can't find New Entity for '#{key}' entity_id!"}
10
+ @deleted_entities = Hash.new{|hash, key| raise "Can't find Deleted Entity for '#{key}' entity_id!"}
11
+ @event_processor = EventProcessor.new(self)
12
+ @system_listener = SystemListener.new(self)
13
+ @commited = false
14
+ @managed = false
15
+ end
16
+
17
+ def copy_get! entity
18
+ unless @copies.include? entity.entity_id
19
+ copy = AnEntity::EntityType.create_copy entity
20
+ @copies[entity.entity_id] = copy
21
+ end
22
+ @copies[entity.entity_id]
23
+ end
24
+
25
+ def resolve entity_id
26
+ if @new_entities.include? entity_id
27
+ @new_entities[entity_id]
28
+ elsif @deleted_entities.include? entity_id
29
+ @deleted_entities[entity_id]
30
+ else
31
+ @repository.by_id(entity_id)
32
+ end
33
+ end
34
+
35
+ def commited!
36
+ @commited = true
37
+ end
38
+
39
+ def commited?
40
+ @commited
41
+ end
42
+
43
+ def commit
44
+ @repository.commit self
45
+ end
46
+
47
+ def changed? entity_id
48
+ entity_id.should! :be_a, String
49
+ @copies.include?(entity_id) || @new_entities.include?(entity_id)
50
+ end
51
+
52
+ def to_s
53
+ types = {:new => 0, :deleted => 0, :updated => 0, :moved => 0}
54
+ methods = types.keys
55
+ @copies.values.each do |c|
56
+ methods.each do |m|
57
+ types[m] += 1 if c.send :"#{m}?"
58
+ end
59
+ end
60
+ return "#<Transaction: #{@name}#{commited? ? ", commited" : ""}, #{types.inspect}>"
61
+ end
62
+ alias_method :inspect, :to_s
63
+ end
@@ -0,0 +1,36 @@
1
+ class TransactionProcessor
2
+ inherit Log
3
+
4
+ def initialize repository, transaction
5
+ @repository, @transaction = repository, transaction
6
+ end
7
+
8
+ def check_outdated
9
+ outdated = []
10
+ @transaction.copies.each do |entity_id, c|
11
+ next if c.new?
12
+ e = @repository.by_id(entity_id)
13
+ outdated << entity_id if c.om_version != e.om_version
14
+ end
15
+ raise_without_self OutdatedError.new(outdated), "Outdated Entities: ['#{outdated.join('\', \'')}']", ObjectModel unless outdated.empty?
16
+ end
17
+
18
+ def write_back
19
+ @transaction.copies.each do |entity_id, copy|
20
+ next if copy.deleted?
21
+ entity = @transaction.resolve entity_id
22
+ AnEntity::EntityType.write_back copy, entity
23
+ end
24
+ end
25
+
26
+ def persist
27
+ @transaction.copies.each do |entity_id, copy|
28
+ entity = @transaction.resolve entity_id
29
+ if copy.deleted?
30
+ AnEntity::EntityType.delete entity, @repository.storage
31
+ else
32
+ AnEntity::EntityType.persist copy, entity, @repository.storage
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ class DefaultTransactionStrategy
2
+ def initialize repository; end
3
+
4
+ def create_new
5
+ Repository::Transaction.new
6
+ end
7
+
8
+ def after_commit transaction; end
9
+ end
@@ -0,0 +1,9 @@
1
+ class InMemoryCache < Hash
2
+ def initialize repository, *parameters
3
+ super()
4
+ end
5
+
6
+ def update transaction
7
+ transaction.copies.each{|entity_id, c| delete entity_id if c.deleted?}
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ class NoCache
2
+ def initialize repository, *parameters
3
+ end
4
+
5
+ def [] key
6
+ nil
7
+ end
8
+
9
+ def []= key, item
10
+ end
11
+
12
+ def update transaction
13
+ end
14
+
15
+ def delete key
16
+
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ # It should have max_items at least equal to 1!
2
+ class OGLRUCache < LRUCache
3
+ class EntityContainer
4
+ include LRUCache::Item
5
+
6
+ attr_reader :entity
7
+ def initialize entity
8
+ @entity = entity
9
+ end
10
+ end
11
+
12
+ def initialize repository, percentage
13
+ @repository, @percentage = repository, percentage
14
+ super(1)
15
+ update_size
16
+ end
17
+
18
+ def [](key)
19
+ container = super(key)
20
+ nil == container ? nil : container.entity
21
+ end
22
+
23
+ def []=(key, item)
24
+ container = EntityContainer.new item
25
+ super(key, container)
26
+ end
27
+
28
+ def update transaction
29
+ transaction.copies.each{|entity_id, c| delete entity_id if c.deleted?}
30
+ update_size
31
+ end
32
+
33
+ protected
34
+ def update_size
35
+ self.max_items = (@repository.size * @percentage).floor + 1
36
+ end
37
+ end
@@ -0,0 +1,94 @@
1
+ class BagType
2
+ class << self
3
+ def initial_value m, e
4
+ calculate_class(m).new e, m.name, e.om_repository
5
+ # e.instance_variable_set m.ivname, bag
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ bag = e.instance_variable_get m.ivname
10
+ bag_copy = AnEntity::BagCopy.new bag._array
11
+ c[m.ivname] = bag_copy
12
+ end
13
+
14
+ def initialize_storage db
15
+ db.create_table :bags do
16
+ column :entity_id, :text
17
+ column :name, :text
18
+ column :reference_id, :text
19
+ # index :entity_id
20
+ end
21
+ end
22
+
23
+ def print_storage db, name
24
+ return unless name == nil or name == :bags
25
+ puts "\nBags:"
26
+ db[:bags].print
27
+ end
28
+
29
+ def load m, e, storage
30
+ rows = storage[:bags].filter :entity_id => e.entity_id, :name => m.name.to_s
31
+ bag = calculate_class(m).new e, m.name, e.om_repository
32
+ rows.each do |row|
33
+ value = AnEntity::EntityType.load_id row[:reference_id]
34
+ bag._array << value
35
+ end
36
+ e.instance_variable_set m.ivname, bag
37
+ end
38
+
39
+ def write_back c, e, m
40
+ bag_copy = c[m.ivname]
41
+ bag = e.instance_variable_get m.ivname
42
+ bag._array.replace bag_copy._array # TODO reimplement more efficiently
43
+ end
44
+
45
+ def persist c, entity_id, m, storage
46
+ # TODO reimplement more efficiently
47
+ sname = m.name.to_s
48
+ storage[:bags].filter(:entity_id => entity_id, :name => sname).delete
49
+ c[m.ivname]._array.each do |ref_id|
50
+ ref_id.should_not! :be_nil
51
+ storage[:bags].insert(
52
+ :entity_id => entity_id,
53
+ :name => sname,
54
+ :reference_id => AnEntity::EntityType.dump_id(ref_id)
55
+ )
56
+ end
57
+ end
58
+
59
+ def delete e, m, storage
60
+ storage[:bags].filter(:entity_id => e.entity_id).delete
61
+ end
62
+
63
+ def delete_all_children e, m
64
+ bag = e.send m.name
65
+ bag.every.delete
66
+ end
67
+
68
+ def delete_all_references_to referrer, e, m
69
+ bag = referrer.send m.name
70
+ bag.delete e
71
+ end
72
+
73
+ def delete_from_parent e, parent, m
74
+ bag = parent.send m.name
75
+ bag.delete e
76
+ end
77
+
78
+ def each e, m, &b
79
+ bag = e.send m.name
80
+ bag.each &b
81
+ end
82
+
83
+ protected
84
+ def calculate_class m
85
+ if m.is_a? Metadata::Child
86
+ AnEntity::ChildrenBag
87
+ elsif m.is_a? Metadata::Reference
88
+ AnEntity::ReferencesBag
89
+ else
90
+ should! :be_never_called
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,42 @@
1
+ class BooleanType
2
+ class << self
3
+ inherit Log
4
+
5
+ def initial_value m, e
6
+ false
7
+ # e.instance_variable_set m.ivname, false
8
+ end
9
+
10
+ def initialize_copy m, e, c
11
+ value_copy = e.instance_variable_get(m.ivname).copy
12
+ c[m.ivname] = value_copy
13
+ end
14
+
15
+ def load m, e, storage
16
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
17
+ raise LoadError unless row and row[:class] == "BOOLEAN"
18
+
19
+ e.instance_variable_set m.ivname, (row[:value] == "false" ? false : true)
20
+ end
21
+
22
+ def persist c, entity_id, m, storage
23
+ value = c[m.ivname] ? "true" : "false"
24
+ storage[:entities_content].insert(
25
+ :entity_id => entity_id,
26
+ :name => m.name.to_s,
27
+ :value => value,
28
+ :class => "BOOLEAN"
29
+ )
30
+ end
31
+
32
+ def write_back c, e, m
33
+ value = c[m.ivname]
34
+ value.should! :be_a, [TrueClass, FalseClass]
35
+ e.instance_variable_set m.ivname, value
36
+ end
37
+
38
+ def validate_type value
39
+ value == true or value == false
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,43 @@
1
+ class ClassType
2
+ class << self
3
+ def initial_value m, e
4
+ nil
5
+ # e.instance_variable_set m.ivname, nil
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ value_copy = e.instance_variable_get(m.ivname)
10
+ c[m.ivname] = value_copy
11
+ end
12
+
13
+ def write_back c, e, m
14
+ value = c[m.ivname]
15
+ value.should! :be_a, [NilClass, Module, Class]
16
+ e.instance_variable_set m.ivname, value
17
+ end
18
+
19
+ def load m, e, storage
20
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
21
+
22
+ raise LoadError unless row and row[:class] == "CLASS"
23
+ value = row[:value]
24
+ value = eval(value, TOPLEVEL_BINDING, __FILE__, __LINE__) if value
25
+ e.instance_variable_set m.ivname, value
26
+ end
27
+
28
+ def persist c, entity_id, m, storage
29
+ value = c[m.ivname]
30
+ value = value.name if value
31
+ storage[:entities_content].insert(
32
+ :entity_id => entity_id,
33
+ :name => m.name.to_s,
34
+ :value => value,
35
+ :class => "CLASS"
36
+ )
37
+ end
38
+
39
+ def validate_type value
40
+ value == nil or value.is_a?(Module) or value.is_a?(Class)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ class DataType
2
+ class << self
3
+ def initial_value m, e
4
+ nil
5
+ # e.instance_variable_set m.ivname, nil
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ value = e.instance_variable_get(m.ivname)
10
+ value_copy = value != nil ? Repository::StreamID.new(value.sid) : nil
11
+ c[m.ivname] = value_copy
12
+ end
13
+
14
+ def write_back c, e, m
15
+ value = c[m.ivname]
16
+ value.should! :be_a, [NilClass, Repository::StreamID]
17
+ e.instance_variable_set m.ivname, value
18
+ end
19
+
20
+ def load m, e, storage
21
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
22
+ raise LoadError unless row and row[:class] == "STREAM_ID"
23
+
24
+ stream_id = row[:value]
25
+ value = stream_id == "nil" ? nil : Repository::StreamID.new(stream_id)
26
+ e.instance_variable_set m.ivname, value
27
+ end
28
+
29
+ def persist c, entity_id, m, storage
30
+ value = c[m.ivname]
31
+ stream_id = value == nil ? "nil" : value.sid
32
+ storage[:entities_content].insert(
33
+ :entity_id => entity_id,
34
+ :name => m.name.to_s,
35
+ :value => stream_id,
36
+ :class => "STREAM_ID"
37
+ )
38
+ end
39
+
40
+ def validate_type value
41
+ value == nil or value.is_a? StreamID
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ class DateType
2
+ class << self
3
+ def initial_value m, e
4
+ nil
5
+ # e.instance_variable_set m.ivname, nil
6
+ end
7
+
8
+ def initialize_copy m, e, c
9
+ value = e.instance_variable_get(m.ivname)
10
+ value_copy = value != nil ? value.clone : nil
11
+ c[m.ivname] = value_copy
12
+ end
13
+
14
+ def write_back c, e, m
15
+ value = c[m.ivname]
16
+ value.should! :be_a, [NilClass, DateTime]
17
+ e.instance_variable_set m.ivname, value
18
+ end
19
+
20
+ def persist c, entity_id, m, storage
21
+ value = c[m.ivname]
22
+ str_value = value == nil ? "nil" : value.to_s
23
+ storage[:entities_content].insert(
24
+ :entity_id => entity_id,
25
+ :name => m.name.to_s,
26
+ :value => str_value,
27
+ :class => "DATE"
28
+ )
29
+ end
30
+
31
+ def load m, e, storage
32
+ row = storage[:entities_content][:entity_id => e.entity_id, :name => m.name.to_s]
33
+ raise LoadError unless row and row[:class] == "DATE"
34
+
35
+ value = row[:value]
36
+ e.instance_variable_set m.ivname, (value == "nil" ? nil : DateTime.parse(value))
37
+ end
38
+
39
+ def validate_type value
40
+ value == nil or value.is_a? DateTime
41
+ end
42
+ end
43
+ end