command_post 0.0.1

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 (33) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +28 -0
  5. data/README.md +310 -0
  6. data/Rakefile +1 -0
  7. data/command_post.gemspec +21 -0
  8. data/lib/command_post/command/command.rb +375 -0
  9. data/lib/command_post/command_post.rb +5 -0
  10. data/lib/command_post/db/connection.rb +12 -0
  11. data/lib/command_post/db/postgresql.sql +45 -0
  12. data/lib/command_post/event_sourcing/aggregate.rb +82 -0
  13. data/lib/command_post/event_sourcing/aggregate_event.rb +107 -0
  14. data/lib/command_post/identity/identity.rb +75 -0
  15. data/lib/command_post/identity/sequence_generator.rb +44 -0
  16. data/lib/command_post/persistence/aggregate_pointer.rb +18 -0
  17. data/lib/command_post/persistence/auto_load.rb +70 -0
  18. data/lib/command_post/persistence/data_validation.rb +113 -0
  19. data/lib/command_post/persistence/persistence.rb +157 -0
  20. data/lib/command_post/persistence/schema_validation.rb +137 -0
  21. data/lib/command_post/util/hash_util.rb +23 -0
  22. data/lib/command_post/util/string_util.rb +18 -0
  23. data/lib/command_post/version.rb +3 -0
  24. data/spec/command_post/command/command_spec.rb +0 -0
  25. data/spec/command_post/identity/identity_lookup_value_aggregate_id_spec.rb +89 -0
  26. data/spec/command_post/identity/identity_lookup_value_checksum_spec.rb +108 -0
  27. data/spec/command_post/identity/identity_lookup_value_field_spec.rb +83 -0
  28. data/spec/command_post/persistence/data_validation_spec.rb +74 -0
  29. data/spec/command_post/persistence/nested_remote_spec.rb +0 -0
  30. data/spec/command_post/persistence/schema_validation_spec.rb +269 -0
  31. data/spec/command_post/require.rb +9 -0
  32. data/spec/spec_helper.rb +0 -0
  33. metadata +112 -0
@@ -0,0 +1,44 @@
1
+ require 'securerandom'
2
+ require 'sequel'
3
+
4
+
5
+ require_relative '../db/connection.rb'
6
+
7
+
8
+ module CommandPost
9
+
10
+ class SequenceGenerator
11
+
12
+
13
+ def self.aggregate_id
14
+ @@DB ||= Connection.db_cqrs
15
+ val = 0
16
+ @@DB.fetch("SELECT nextval('aggregate');") do |row|
17
+ val = row[row.keys.first]
18
+ end
19
+ val
20
+ end
21
+
22
+ def self.transaction_id
23
+ @@DB ||= Connection.db_cqrs
24
+ val = 0
25
+ @@DB.fetch("SELECT nextval('transaction');") do |row|
26
+ val = row[row.keys.first]
27
+ end
28
+ val
29
+ end
30
+
31
+ def self.misc
32
+ @@DB ||= Connection.db_cqrs
33
+ val = 0
34
+ @@DB.fetch("SELECT nextval('misc');") do |row|
35
+ val = row[row.keys.first]
36
+ end
37
+ val
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+
@@ -0,0 +1,18 @@
1
+
2
+ module CommandPost
3
+
4
+
5
+ class AggregatePointer < Hash
6
+ attr_accessor :aggregate_type, :aggregate_id
7
+
8
+ def initialize hash
9
+ @aggregate_type = hash[:aggregate_type]
10
+ @aggregate_id = hash[:aggregate_id]
11
+ self[:aggregate_type] = hash[:aggregate_type]
12
+ self[:aggregate_id] = hash[:aggregate_id]
13
+ self[:class_name] = 'AggregatePointer'
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,70 @@
1
+ require_relative '../util/hash_util'
2
+
3
+ module CommandPost
4
+
5
+ module AutoLoad
6
+
7
+ def auto_load_fields
8
+
9
+ schema_fields.select {|key, value| value[:auto_load] == true }.keys
10
+ end
11
+
12
+
13
+ def local_peristent_fields
14
+
15
+ schema_fields.select {|key, value| value[:location] == :local && value[:type].superclass == Persistence }.keys
16
+ end
17
+
18
+
19
+ def populate_auto_load_fields
20
+ auto_load_fields.select {|x| @data.keys.include? x}.each do |field|
21
+ if @data[field].class == Array
22
+ if schema_fields[field][:location] == :remote
23
+ array_of_objects = Array.new
24
+ array_of_pointers = @data[field]
25
+ array_of_pointers.each do |pointer|
26
+ if pointer.respond_to? :aggregate_pointer
27
+ pointer = pointer.aggregate_pointer
28
+ end
29
+ obj = Aggregate.get_by_aggregate_id(Object.const_get(pointer[:aggregate_type]), pointer[:aggregate_id])
30
+ array_of_objects << obj
31
+ end
32
+ array_of_pointers.clear
33
+ @data[field].clear
34
+ @data[field] += array_of_objects
35
+ end
36
+ else
37
+ @data[field] = Aggregate.get_by_aggregate_id( schema_fields[field][:type], @data[field][:aggregate_id])
38
+ end
39
+ end
40
+ end
41
+
42
+
43
+ def to_pretty_pp
44
+ len = 0
45
+ result = ''
46
+ @data.keys.map{|key| len = key.length if (key.length > len) }
47
+
48
+ @data.keys.reject{|key| /aggregate/.match key}.each do |key|
49
+ label = "%#{len}s :" % key
50
+ if auto_load_fields.include? key
51
+ result += "\n#{label} (remote object)"
52
+ result += (@data[key]).to_s
53
+ else
54
+ result += "#{label} #{@data[key]}"
55
+ end
56
+ end
57
+ result
58
+ end
59
+
60
+
61
+ def populate_local_persistent_objects
62
+ local_peristent_fields.each do |field|
63
+ klass = schema_fields[field][:type]
64
+ @data[field] = klass.load_from_hash klass, HashUtil.symbolize_keys(@data[field])
65
+ @data[field].populate_local_persitent_objects
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,113 @@
1
+
2
+
3
+
4
+ module CommandPost
5
+
6
+ module DataValidation
7
+
8
+ def empty?
9
+
10
+ @data.nil? || @data == {}
11
+ end
12
+
13
+ def valid?
14
+
15
+ verify_data.length == 0
16
+ end
17
+
18
+ def data_errors
19
+
20
+ verify_data
21
+ end
22
+
23
+ def verify_data
24
+
25
+ errors = Array.new
26
+
27
+ schema_fields.each do |field_name, field_info|
28
+ if missing_required_field(field_name, field_info)
29
+
30
+ errors << "#{self.class}:#{field_name} - is a required field."
31
+ end
32
+ if data_type_does_not_match_declaration(field_name, field_info)
33
+
34
+ errors << "#{self.class}: #{field_name}: expected type: #{field_info[:type].name}, but received type #{@data[field_name].class.name}."
35
+ end
36
+ if allowed_values_declared_but_array_of_values_not_supplied(field_name, field_info)
37
+
38
+ errors << "#{self.class}: #{field_name}: expected type: #{field_info[:type].name}, but received type #{@data[field_name].class.name}."
39
+ end
40
+ if value_not_among_the_list_of_allowed_values(field_name, field_info)
41
+
42
+ errors << "#{self.class}: #{field_name}: The value supplied was not in the list of acceptable values."
43
+ end
44
+ if type_is_array_but_keyword___of___not_supplied(field_name, field_info)
45
+
46
+ errors << "#{self.class}: #{field_name}: is an Array, but the ':of' keyword was not set to declare the class type for objects in the array."
47
+ end
48
+ if accepted_values_supplied_but_they_are_not_all_the_same_type(field_name, field_info)
49
+
50
+ errors << "#{self.class}: #{field_name} is an Array and all objects should be of type #{expected_type} but one object was of type #{object_in_array.class}."
51
+ end
52
+ if field_is_array_of_remote_objects_but_array_has_values_other_than_persistence_or_identity(field_name, field_info)
53
+
54
+ errors << "#{self.class}: #{field_name} is an Array and all objects should be of type #{expected_type} but one object was of type #{object_in_array.class} or of AggregatePointer."
55
+ end
56
+ end
57
+ errors
58
+ end
59
+
60
+ def missing_required_field field_name, field_info
61
+ puts "field_name is #{field_name} and has class of #{field_name.class}"
62
+ @data.keys.include?(field_name)==false && field_info[:required] == true
63
+ end
64
+
65
+ def data_type_does_not_match_declaration field_name, field_info
66
+
67
+ @data[field_name] != nil && (@data[field_name].class != field_info[:type])
68
+ end
69
+
70
+ def allowed_values_declared_but_array_of_values_not_supplied field_name, field_info
71
+
72
+ (@data[field_name] != nil) && (@data[field_name].class != Array) && (field_info[:allowed_values]) && (field_info[:allowed_values].class != Array)
73
+ end
74
+
75
+ def value_not_among_the_list_of_allowed_values field_name, field_info
76
+
77
+ (@data[field_name] != nil) && (@data[field_name].class != Array) && (field_info[:allowed_values]) && (field_info[:allowed_values].include?(@data[field_name]) == false )
78
+ end
79
+
80
+ def type_is_array_but_keyword___of___not_supplied field_name, field_info
81
+
82
+ (@data[field_name.to_s] != nil) && (@data[field_name].class == Array) && (field_info[:type] == Array) && (field_info[:local] == true) && ((!field_info.keys.include?(:of)) || field_info[:of].nil?)
83
+ end
84
+
85
+ def accepted_values_supplied_but_they_are_not_all_the_same_type(field_name, field_info)
86
+ if (@data[field_name.to_s] != nil) && (@data[field_name].class == Array) && (field_info[:type] == Array) && (field_info[:local] == true)
87
+ if field_info[:location] == :local
88
+ expected_type = field_info[:of]
89
+ @data[field_name.to_s].each do |object_in_array|
90
+ if object_in_array.class != expected_type
91
+ return true
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ def field_is_array_of_remote_objects_but_array_has_values_other_than_persistence_or_identity(field_name, field_info)
99
+ if (@data[field_name.to_s] != nil) && (@data[field_name].class == Array) && (field_info[:type] == Array) && (field_info[:location] == :remote)
100
+ # OK, :of was declared, forge ahead and check any objects in the array for the correct type (these are all local, no worries about aggregate pointer)
101
+ expected_type = field_info[:of]
102
+ @data[field_name.to_s].each do |object_in_array|
103
+ if (object_in_array.class != expected_type) && (object_in_array.class != AggregatePointer)
104
+ return ["#{self.class}: #{field_name} is an Array and all objects should be of type #{expected_type} but one object was of type #{object_in_array.class} or of AggregatePointer."]
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,157 @@
1
+
2
+ require_relative '../event_sourcing/aggregate.rb'
3
+ require_relative '../event_sourcing/aggregate_event.rb'
4
+ require_relative '../persistence/persistence.rb'
5
+ require_relative './schema_validation.rb'
6
+ require_relative './data_validation.rb'
7
+ require_relative './auto_load.rb'
8
+ require_relative '../command/command.rb'
9
+
10
+ module CommandPost
11
+
12
+ class Persistence
13
+ include SchemaValidation
14
+ include DataValidation
15
+ include AutoLoad
16
+
17
+ def initialize
18
+
19
+ @@fields ||= Hash.new
20
+ @aggregate_info_set = false
21
+ @data = Hash.new
22
+ self.class.init_schema self.class.schema
23
+ Command.auto_generate self.class
24
+ end
25
+
26
+
27
+ def schema_fields
28
+
29
+ @@fields[self.class]
30
+ end
31
+
32
+
33
+ def set_data data_hash
34
+ @data = data_hash
35
+ if @aggregate_info_set == false
36
+ @aggregate_info_set = true
37
+ end
38
+ end
39
+
40
+
41
+ def get_data name
42
+ if schema_fields[name][:location] == :local
43
+ if schema_fields[name][:type] == DateTime
44
+ return DateHelper.parse_date_time(@data[name])
45
+ elsif schema_fields[name][:type] == Time
46
+ DateHelper.parse_time(@data[name])
47
+ else
48
+ return @data[name]
49
+ end
50
+ else
51
+ if @data[name].class == Hash && @data[name].keys == [:aggregate_type,:aggregate_id]
52
+ Aggregate.get_by_aggregate_id(schema_fields[name][:type], @data[name][:aggregate_id])
53
+ else
54
+ @data[name]
55
+ end
56
+ end
57
+ end
58
+
59
+
60
+ def method_missing(nm, *args)
61
+
62
+ name = nm.to_s
63
+ if name.end_with?('=') == false
64
+
65
+
66
+ if @data.keys.include? nm
67
+ get_data nm
68
+ else
69
+ if schema_fields.keys.include? nm
70
+ return nil
71
+ else
72
+ begin
73
+ super
74
+ rescue
75
+ puts "#{nm} is not a defined field in #{self}"
76
+ end
77
+ end
78
+ end
79
+ else
80
+ nm = name.gsub(/\=/,'').to_sym
81
+ @data[nm] = args.first
82
+ end
83
+ end
84
+
85
+
86
+ def aggregate_type
87
+ self.class
88
+ #@data[:aggregate_info][:aggregate_type]
89
+ end
90
+
91
+
92
+ def to_h
93
+
94
+ @data
95
+ end
96
+
97
+
98
+ def self.all
99
+
100
+ Aggregate.where(self)
101
+ end
102
+
103
+
104
+ def self.init_schema fields
105
+ schema_error_messages = SchemaValidation.validate_schema(fields)
106
+ if schema_error_messages.length > 0
107
+ raise ArgumentError, "The schema for #{self} had the following error(s): #{pp schema_error_messages}"
108
+ end
109
+ @@fields[self] ||= fields
110
+ end
111
+
112
+
113
+ def self.load_from_hash the_class, string_hash
114
+
115
+ data_hash = HashUtil.symbolize_keys(string_hash)
116
+
117
+
118
+ if (data_hash.keys.include?(:aggregate_info) == false) && (the_class.included_modules.include?(CommandPost::Identity) == true)
119
+ data_hash[:aggregate_info] = Hash.new
120
+ data_hash[:aggregate_info][:aggregate_type] = the_class.to_s
121
+ data_hash[:aggregate_info][:version] = 1
122
+ data_hash[:aggregate_info][:aggregate_id] = SequenceGenerator.aggregate_id
123
+ end
124
+
125
+
126
+ object = the_class.new
127
+ object.set_data data_hash
128
+ object.populate_auto_load_fields #unless self.bypass_auto_load == true
129
+ object.populate_local_persistent_objects
130
+ if (the_class.included_modules.include?(CommandPost::Identity) == true)
131
+ object.set_aggregate_lookup_value
132
+ end
133
+ object
134
+ end
135
+
136
+
137
+ def self.bypass_auto_load
138
+ @@bypass ||= Hash.new
139
+ @@bypass[self] ||= false
140
+ @@bypass[self]
141
+ end
142
+
143
+
144
+ def self.bypass_auto_load=(value)
145
+ @@bypass ||= Hash.new
146
+ @@bypass[self]=value
147
+ end
148
+
149
+
150
+ def self.upcase? field_name
151
+ raise ArgumentError ,"field not found " if (schema.keys.include?(field_name) == false)
152
+ field_info = schema[field_name]
153
+ field_info.keys.include?(:upcase) ? field_info[:upcase] : false
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,137 @@
1
+ require 'pp'
2
+
3
+ module SchemaValidation
4
+
5
+ def self.validate_schema fields
6
+
7
+ errors = Array.new
8
+ fields.keys.each do |field_name|
9
+ errors += self.validate_field_name field_name
10
+ errors += self.validate_keywords field_name, fields[field_name]
11
+ errors += self.validate_required field_name, fields[field_name] if fields[field_name].keys.include? :required
12
+ errors += self.validate_type field_name, fields[field_name] if fields[field_name].keys.include? :type
13
+ errors += self.validate_location field_name, fields[field_name] if fields[field_name].keys.include? :location
14
+ errors += self.validate_auto_load field_name, fields[field_name] if fields[field_name].keys.include? :auto_load
15
+ errors += self.validate_allowed_values field_name, fields[field_name] if fields[field_name].keys.include? :allowed_values
16
+ end
17
+ errors
18
+ end
19
+
20
+ def self.validate_keywords field_name, field_info
21
+ errors = Array.new
22
+
23
+ if field_name == :lookup
24
+ errors = self.validate_lookup field_name, field_info
25
+ else
26
+ keywords = [:required, :type, :of, :location, :auto_load, :allowed_values, :upcase ]
27
+ field_info.keys.each do |key|
28
+ if keywords.include?(key)==false
29
+ errors << "Field Name: #{field_name} : #{key} is an invalid keyword."
30
+ end
31
+ end
32
+ end
33
+ errors
34
+ end
35
+
36
+ def self.validate_lookup field_name, field_info
37
+ errors = Array.new
38
+ keywords = [:use ]
39
+ field_info.keys.each do |key|
40
+ if keywords.include?(key)==false
41
+ errors << "Lookup Field has invalid keyword '#{key}'."
42
+ end
43
+ end
44
+ errors
45
+ end
46
+
47
+
48
+ def self.validate_allowed_values field_name, field_info
49
+ if field_info[:allowed_values].class != Array
50
+ return ["Field Name '#{field_name}' : :allowed_values was specified but the allowed_values must be contained in an Array." ]
51
+ end
52
+ types = Hash.new
53
+
54
+ field_info.each{|x| types[x.type] = 0 }
55
+ if types.keys.count != 1
56
+ return ["Field Name '#{field_name}' : :allowed_values the values were not all of the same type - or no values were specified. " ]
57
+ end
58
+ []
59
+ end
60
+
61
+
62
+ def self.validate_auto_load field_name, field_info
63
+ if [true,false].include?(field_info[:auto_load])==false
64
+ return ["Field Name '#{field_name}' : :auto_load was specified with an invalid value. Must be 'true' or 'false'." ]
65
+ end
66
+ if (field_info[:type] == Array)
67
+ if !field_info[:of].kind_of?(CommandPost::Persistence) == false
68
+ return ["Field Name '#{field_name}' : When :auto_load is true and :type is Array, then :of must be a kind_of CommandPost::Persistence." ]
69
+ end
70
+ else
71
+ if field_info[:type].superclass.to_s != 'CommandPost::Persistence'
72
+ return ["Field Name '#{field_name}' : When :auto_load is true then :type must be kind_of CommandPost::Persistence." ]
73
+ end
74
+ end
75
+ []
76
+ end
77
+
78
+
79
+ def self.validate_location field_name, field_info
80
+ if [:local,:remote].include?(field_info[:location]) == false
81
+ return ["Field Name '#{field_name}' : :location was specified with an invalid value. Must be ':remote' or ':local'." ]
82
+ end
83
+ if field_info[:location] == :remote
84
+ if (field_info[:type] == Array)
85
+ if !field_info[:of]
86
+ return ["Field Name '#{field_name}' : :type is Array, but :of is not present. Use ':of => <type>' to decare the type contained by Array." ]
87
+ end
88
+ if field_info[:of].included_modules.include?(CommandPost::Identity) == false
89
+ return ["Field Name '#{field_name}' : When :location is :remote and :type is Array, then :of must be a type that includes module CommandPost::Identity." ]
90
+ end
91
+ else
92
+ if field_info[:type].included_modules.include?(CommandPost::Identity) == false
93
+ return ["Field Name '#{field_name}' : When :location is :remote then :type must be a type that includes module CommandPost::Identity." ]
94
+ end
95
+ end
96
+ else
97
+ # location is :local
98
+ if (field_info[:type] == Array)
99
+
100
+ if field_info[:of].included_modules.include?(CommandPost::Identity)
101
+ return ["Field Name '#{field_name}' : When :location is :local and :type is Array, then :of cannot be an instance of CommandPost::Identity." ]
102
+ end
103
+ else
104
+ if field_info[:type].included_modules.include?(CommandPost::Identity)
105
+ return ["Field Name '#{field_name}' : When :location is :local then :type cannot be an instance of CommandPost::Identity." ]
106
+ end
107
+ end
108
+ end
109
+ []
110
+ end
111
+
112
+
113
+ def self.validate_type field_name, field_info
114
+ if (field_info[:type] == Array) && (field_info.keys.include?(:of) == false)
115
+ return ["Field Name '#{field_name}' : :type is Array, but :of is not present. Use ':of => <type>' to decare the type contained by Array." ]
116
+ end
117
+ []
118
+ end
119
+
120
+
121
+ def self.validate_required field_name, field_info
122
+ if [true,false].include?(field_info[:required]) == false
123
+ return ["Field Name '#{field_name}' : :required was specified with an invalid value. Must be 'true' or 'false'." ]
124
+ end
125
+ []
126
+ end
127
+
128
+
129
+ def self.validate_field_name field_name
130
+ if field_name.class != Symbol
131
+ return ["Field Name '#{field_name}' : :field_name must be a Symbol." ]
132
+ end
133
+ []
134
+ end
135
+
136
+
137
+ end
@@ -0,0 +1,23 @@
1
+
2
+
3
+
4
+ class HashUtil
5
+
6
+
7
+ def self.symbolize_keys(hash)
8
+ hash.inject({}){|result, (key, value)|
9
+ new_key = case key
10
+ when String then key.to_sym
11
+ else key
12
+ end
13
+ new_value = case value
14
+ when Hash then symbolize_keys(value)
15
+ else value
16
+ end
17
+ result[new_key] = new_value
18
+ result
19
+ }
20
+ end
21
+
22
+ end
23
+
@@ -0,0 +1,18 @@
1
+
2
+
3
+ module CommandPost
4
+ class StringUtil
5
+
6
+ def self.to_camel_case(field, upcase)
7
+ string = field.to_s
8
+ upcase == true ? string.upcase : string.split('_').collect{|x| x.slice(0,1).capitalize + x.slice(1..-1) }.join()
9
+ end
10
+
11
+ def self.to_label(field, upcase)
12
+ string = field.to_s
13
+ upcase == true ? string.upcase : string.split('_').collect{|x| x.slice(0,1).capitalize + x.slice(1..-1) }.join(' ')
14
+ end
15
+
16
+
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module CommandPost
2
+ VERSION = "0.0.1"
3
+ end
File without changes
@@ -0,0 +1,89 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../command_post/require')
2
+
3
+
4
+ class Test003Person < CommandPost::Persistence
5
+ include CommandPost::Identity
6
+
7
+ def initialize
8
+ super
9
+ end
10
+ def self.schema
11
+ fields = Hash.new
12
+ fields[ :first_name ] = { :required => true, :type => String, :location => :local }
13
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
14
+ fields[ :ssn ] = { :required => true, :type => String, :location => :local }
15
+ fields[ :lookup ] = { :use => :aggregate_id }
16
+ fields
17
+ end
18
+ end
19
+
20
+
21
+
22
+ describe CommandPost::Identity do
23
+ it 'as the name suggestions, provides the means for objects to have an identity that is used in retrieving it from the database' do
24
+
25
+ params = Hash.new # like a web request...
26
+ params['first_name'] = 'John' #hash key is a string to mimic a web post/put
27
+ params['last_name'] = 'Doe' #hash key is a string to mimic a web post/put
28
+ params['ssn'] = "%09d" % CommandPost::SequenceGenerator.misc #hash key is a string to mimic a web post/put
29
+
30
+
31
+ #----------------------------------------------------------------
32
+ # The code below will eventually be replaced by the
33
+ # 'handle' method of the CommandXXXXXX class.
34
+ #----------------------------------------------------------------
35
+
36
+ object = Test003Person.load_from_hash Test003Person, params
37
+ event = CommandPost::AggregateEvent.new
38
+ event.aggregate_id = object.aggregate_id
39
+ event.object = object
40
+ event.aggregate_type = Test003Person
41
+ event.event_description = 'hired'
42
+ event.user_id = 'test'
43
+ event.publish
44
+
45
+
46
+ #----------------------------------------------------------------
47
+ # Retrieve the object by both aggregate_id and aggregate_lookup_value
48
+ # Both ways should retrieve the same object and the fields of both
49
+ # should match the original values used to create the object.
50
+ #----------------------------------------------------------------
51
+
52
+ saved_person = CommandPost::Aggregate.get_by_aggregate_id Test003Person, event.aggregate_id
53
+ saved_person2 = CommandPost::Aggregate.get_aggregate_by_lookup_value Test003Person, saved_person.aggregate_lookup_value
54
+
55
+
56
+ params['first_name'].must_equal saved_person.first_name
57
+ params['last_name'].must_equal saved_person.last_name
58
+ params['ssn'].must_equal saved_person.ssn
59
+
60
+ params['first_name'].must_equal saved_person2.first_name
61
+ params['last_name'].must_equal saved_person2.last_name
62
+ params['ssn'].must_equal saved_person2.ssn
63
+ end
64
+ end
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+