command_post 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+