ObjectModel 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +849 -0
- data/lib/ObjectModel.res/config.yaml +5 -0
- data/lib/ObjectModel/AnEntity/BackReferences.rb +113 -0
- data/lib/ObjectModel/AnEntity/Bag.rb +129 -0
- data/lib/ObjectModel/AnEntity/BagCopy.rb +29 -0
- data/lib/ObjectModel/AnEntity/ChildrenBag.rb +10 -0
- data/lib/ObjectModel/AnEntity/EntityCopy.rb +38 -0
- data/lib/ObjectModel/AnEntity/EntityType.rb +408 -0
- data/lib/ObjectModel/AnEntity/ReferencesBag.rb +10 -0
- data/lib/ObjectModel/AnEntity/entity_cm.rb +108 -0
- data/lib/ObjectModel/Entity.rb +278 -0
- data/lib/ObjectModel/Errors/LoadError.rb +3 -0
- data/lib/ObjectModel/Errors/NoTransactionError.rb +3 -0
- data/lib/ObjectModel/Errors/NotFoundError.rb +2 -0
- data/lib/ObjectModel/Errors/OutdatedError.rb +8 -0
- data/lib/ObjectModel/Errors/ValidationError.rb +3 -0
- data/lib/ObjectModel/Indexes/HashIndex.rb +64 -0
- data/lib/ObjectModel/Indexes/IndexStorage.rb +64 -0
- data/lib/ObjectModel/Indexes/Manager.rb +72 -0
- data/lib/ObjectModel/Metadata.rb +34 -0
- data/lib/ObjectModel/Metadata.res/after_event_types.rb +25 -0
- data/lib/ObjectModel/Metadata.res/attribute_types_shortcuts.rb +10 -0
- data/lib/ObjectModel/Metadata.res/before_event_types.rb +25 -0
- data/lib/ObjectModel/Metadata.res/child_types_shortcuts.rb +4 -0
- data/lib/ObjectModel/Metadata.res/metadata_checks.rb +9 -0
- data/lib/ObjectModel/Metadata.res/reference_types_shortcuts.rb +4 -0
- data/lib/ObjectModel/Metadata/DSL.rb +11 -0
- data/lib/ObjectModel/Metadata/attribute.rb +56 -0
- data/lib/ObjectModel/Metadata/child.rb +50 -0
- data/lib/ObjectModel/Metadata/events.rb +109 -0
- data/lib/ObjectModel/Metadata/name.rb +20 -0
- data/lib/ObjectModel/Metadata/reference.rb +50 -0
- data/lib/ObjectModel/Metadata/require.rb +10 -0
- data/lib/ObjectModel/Metadata/validate.rb +66 -0
- data/lib/ObjectModel/Repository.rb +326 -0
- data/lib/ObjectModel/Repository/EventProcessor.rb +58 -0
- data/lib/ObjectModel/Repository/ObjectStorage.rb +102 -0
- data/lib/ObjectModel/Repository/StreamID.rb +20 -0
- data/lib/ObjectModel/Repository/StreamStorage.rb +121 -0
- data/lib/ObjectModel/Repository/SystemListener.rb +143 -0
- data/lib/ObjectModel/Repository/Transaction.rb +63 -0
- data/lib/ObjectModel/Repository/TransactionProcessor.rb +36 -0
- data/lib/ObjectModel/Tools/DefaultTransactionStrategy.rb +9 -0
- data/lib/ObjectModel/Tools/InMemoryCache.rb +9 -0
- data/lib/ObjectModel/Tools/NoCache.rb +18 -0
- data/lib/ObjectModel/Tools/OGLRUCache.rb +37 -0
- data/lib/ObjectModel/Types/BagType.rb +94 -0
- data/lib/ObjectModel/Types/BooleanType.rb +42 -0
- data/lib/ObjectModel/Types/ClassType.rb +43 -0
- data/lib/ObjectModel/Types/DataType.rb +44 -0
- data/lib/ObjectModel/Types/DateType.rb +43 -0
- data/lib/ObjectModel/Types/NumberType.rb +62 -0
- data/lib/ObjectModel/Types/ObjectType.rb +164 -0
- data/lib/ObjectModel/Types/ProcType.rb +43 -0
- data/lib/ObjectModel/Types/SingleType.rb +59 -0
- data/lib/ObjectModel/Types/StringType.rb +39 -0
- data/lib/ObjectModel/_require.rb +43 -0
- data/lib/ObjectModel/require.rb +1 -0
- data/rakefile +62 -0
- data/spec/ObjectModel/BasicSpec/BaseClass.rb +7 -0
- data/spec/ObjectModel/BasicSpec/BaseTypes.rb +11 -0
- data/spec/ObjectModel/BasicSpec/Descendant.rb +5 -0
- data/spec/ObjectModel/BasicSpec/EachTest.rb +14 -0
- data/spec/ObjectModel/BasicSpec/UpChild.rb +10 -0
- data/spec/ObjectModel/BasicSpec/UpParent.rb +11 -0
- data/spec/ObjectModel/ErrorsSpec/AfterCommitError.rb +9 -0
- data/spec/ObjectModel/ExtendedSpec/CustomInitialization.rb +11 -0
- data/spec/ObjectModel/ExtendedSpec/UpNotNil.rb +8 -0
- data/spec/ObjectModel/ExtendedSpec/UpParent.rb +11 -0
- data/spec/ObjectModel/ValidationSpec/BaseTypes.rb +11 -0
- data/spec/aspect_spec.rb +55 -0
- data/spec/back_references_spec.rb +161 -0
- data/spec/basic_spec.rb +162 -0
- data/spec/cascade_delete_spec.rb +168 -0
- data/spec/complex_events_spec.rb +134 -0
- data/spec/concurrency_spec.rb +186 -0
- data/spec/containment_spec.rb +146 -0
- data/spec/data_migration_spec.rb +51 -0
- data/spec/errors_spec.rb +65 -0
- data/spec/events_spec.rb +173 -0
- data/spec/extended_spec.rb +171 -0
- data/spec/indexing_spec.rb +56 -0
- data/spec/set_in_memory.rb +2 -0
- data/spec/set_no_cache.rb +2 -0
- data/spec/smoke_test_spec.rb +85 -0
- data/spec/stream_spec.rb +143 -0
- data/spec/stream_storage.rb +148 -0
- data/spec/timer.rb +5 -0
- data/spec/validation_spec.rb +87 -0
- 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,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
|