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,108 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../command_post/require')
2
+
3
+
4
+
5
+
6
+
7
+ class Test002Person < CommandPost::Persistence
8
+ include CommandPost::Identity
9
+
10
+ def initialize
11
+ super
12
+ end
13
+ def self.schema
14
+ fields = Hash.new
15
+ fields[ :first_name ] = { :required => true, :type => String, :location => :local }
16
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
17
+ fields[ :ssn ] = { :required => true, :type => String, :location => :local }
18
+ fields[ :lookup ] = { :use => :checksum }
19
+ fields
20
+ end
21
+ end
22
+
23
+
24
+ describe CommandPost::Identity do
25
+ it 'should produce and return a checksum when declaring the lookup to be :checksum in the schema and the checksum should be able to find the aggregate by value (checksum)' do
26
+
27
+ params = Hash.new # like a web request...
28
+
29
+ params['first_name'] = 'John' #hash key is a string to mimic a web post/put
30
+ params['last_name'] = 'Doe' #hash key is a string to mimic a web post/put
31
+ params['ssn'] = "%09d" % CommandPost::SequenceGenerator.misc #hash key is a string to mimic a web post/put
32
+
33
+
34
+ #----------------------------------------------------------------
35
+ # The code below will eventually be replaced by the
36
+ # 'handle' method of the CommandXXXXXX class.
37
+ #----------------------------------------------------------------
38
+
39
+ object = Test002Person.load_from_hash Test002Person, params
40
+ event = CommandPost::AggregateEvent.new
41
+ event.aggregate_id = object.aggregate_id
42
+ event.object = object
43
+ event.aggregate_type = Test002Person
44
+ event.event_description = 'hired'
45
+ event.user_id = 'test'
46
+ event.publish
47
+
48
+
49
+
50
+ #----------------------------------------------------------------
51
+ # Retrieve the object by both aggregate_id and aggregate_lookup_value
52
+ # Both ways should retrieve the same object and the fields of both
53
+ # should match the original values used to create the object.
54
+ #----------------------------------------------------------------
55
+
56
+
57
+ saved_person = CommandPost::Aggregate.get_by_aggregate_id Test002Person, event.aggregate_id
58
+ saved_person2 = CommandPost::Aggregate.get_aggregate_by_lookup_value Test002Person, saved_person.aggregate_lookup_value
59
+
60
+
61
+ params['first_name'].must_equal saved_person.first_name
62
+ params['last_name'].must_equal saved_person.last_name
63
+ params['ssn'].must_equal saved_person.ssn
64
+
65
+ params['first_name'].must_equal saved_person2.first_name
66
+ params['last_name'].must_equal saved_person2.last_name
67
+ params['ssn'].must_equal saved_person2.ssn
68
+ end
69
+ end
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
@@ -0,0 +1,83 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../command_post/require')
2
+
3
+
4
+
5
+
6
+
7
+ class Test001Person < CommandPost::Persistence
8
+ include CommandPost::Identity
9
+
10
+ def initialize
11
+ super
12
+ end
13
+ def self.schema
14
+ fields = Hash.new
15
+ fields[ :first_name ] = { :required => true, :type => String, :location => :local }
16
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
17
+ fields[ :ssn ] = { :required => true, :type => String, :location => :local }
18
+ fields[ :lookup ] = { :use => :ssn }
19
+ fields
20
+ end
21
+ end
22
+
23
+
24
+
25
+ describe CommandPost::Identity do
26
+ it 'it should return use the SSN as the lookup value' do
27
+
28
+ params = Hash.new # like a web request...
29
+
30
+ params['first_name'] = 'John' #hash key is a string to mimic a web post/put
31
+ params['last_name'] = 'Doe' #hash key is a string to mimic a web post/put
32
+ params['ssn'] = "%09d" % CommandPost::SequenceGenerator.misc #hash key is a string to mimic a web post/put
33
+
34
+
35
+ #----------------------------------------------------------------
36
+ # The code below will eventually be replaced by the
37
+ # 'handle' method of the CommandXXXXXX class.
38
+ #----------------------------------------------------------------
39
+
40
+ object = Test001Person.load_from_hash Test001Person, params
41
+ puts "OBJECT IS NIL #{'=' * 80}" if object.nil?
42
+ event = CommandPost::AggregateEvent.new
43
+ event.aggregate_id = object.aggregate_id
44
+ event.object = object
45
+ event.aggregate_type = Test001Person
46
+ event.event_description = 'hired'
47
+ event.user_id = 'test'
48
+ event.publish
49
+
50
+
51
+ #----------------------------------------------------------------
52
+ # Retrieve the object by both aggregate_id and aggregate_lookup_value
53
+ # Both ways should retrieve the same object and the fields of both
54
+ # should match the original values used to create the object.
55
+ #----------------------------------------------------------------
56
+
57
+
58
+ saved_person = CommandPost::Aggregate.get_by_aggregate_id Test001Person, event.aggregate_id
59
+ saved_person2 = CommandPost::Aggregate.get_aggregate_by_lookup_value Test001Person, saved_person.aggregate_lookup_value
60
+
61
+
62
+ params['first_name'].must_equal saved_person.first_name
63
+ params['last_name'].must_equal saved_person.last_name
64
+ params['ssn'].must_equal saved_person.ssn
65
+
66
+ params['first_name'].must_equal saved_person2.first_name
67
+ params['last_name'].must_equal saved_person2.last_name
68
+ params['ssn'].must_equal saved_person2.ssn
69
+ end
70
+ end
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
@@ -0,0 +1,74 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../command_post/require')
2
+
3
+ class SomeClass < CommandPost::Persistence
4
+ include CommandPost::Identity
5
+
6
+ def initialize
7
+ super
8
+ end
9
+
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[ :birth_date ] = { :required => true, :type => Date, :location => :local }
15
+ fields[ :favorite_number ] = { :required => true, :type => Fixnum, :location => :local }
16
+ fields
17
+ end
18
+ end
19
+
20
+
21
+
22
+
23
+ def get_instance
24
+ some_class = SomeClass.new
25
+ SomeClass.new
26
+ end
27
+
28
+
29
+ describe CommandPost::DataValidation do
30
+
31
+ it 'should be valid if all required fields are present and types are correct' do
32
+ obj = get_instance
33
+ obj.first_name = 'Joe'
34
+ obj.last_name = 'Schmoe'
35
+ obj.birth_date = Date.new(1980,1,1)
36
+ obj.favorite_number = 3
37
+ obj.valid?.must_equal true
38
+ end
39
+
40
+ it 'should not be valid if missing required fields ' do
41
+ obj = get_instance
42
+ obj.first_name = 'Joe'
43
+ obj.last_name = 'Schmoe'
44
+ obj.birth_date = Date.new(1980,1,1)
45
+ # ===> missing obj.favorite_number = 3
46
+ obj.valid?.must_equal false
47
+ end
48
+
49
+ it 'should not be valid if a type is incorrect ' do
50
+ obj = get_instance
51
+ obj.first_name = 'Joe'
52
+ obj.last_name = 'Schmoe'
53
+ obj.birth_date = Date.new(1980,1,1)
54
+ obj.favorite_number = "3" # <---- should be Fixnum
55
+ obj.valid?.must_equal false
56
+ end
57
+ end
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
@@ -0,0 +1,269 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../command_post/require')
2
+
3
+
4
+
5
+ describe CommandPost::Persistence do
6
+
7
+ it 'should complain if the schema is bad' do
8
+
9
+ class SomeClass01 < CommandPost::Persistence
10
+ include CommandPost::Identity
11
+
12
+ def initialize
13
+ super
14
+ end
15
+
16
+ def self.schema
17
+ fields = Hash.new
18
+ fields[ :first_name ] = { :required => true, :type => String, :location => :local }
19
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
20
+ fields
21
+ end
22
+ end
23
+ some_class = SomeClass01.new
24
+ some_class.class.must_be_same_as SomeClass01
25
+ end
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+ it 'should raise an error when a instance of Symbol is not used to identify a field.' do
34
+
35
+ class SomeClass02 < CommandPost::Persistence
36
+ include CommandPost::Identity
37
+
38
+ def initialize
39
+ super
40
+ end
41
+
42
+ def self.schema
43
+ fields = Hash.new
44
+ fields[ 'first_name' ] = { :required => true, :type => String, :location => :local }
45
+ fields[ 'last_name' ] = { :required => true, :type => String, :location => :local }
46
+ fields
47
+ end
48
+ end
49
+
50
+ assert_raises(ArgumentError) { some_class = SomeClass02.new }
51
+ end
52
+
53
+
54
+
55
+
56
+
57
+
58
+ it 'should raise an error when a keyword requires a value of true or false but gets neither.' do
59
+
60
+ class SomeClass03 < CommandPost::Persistence
61
+ include CommandPost::Identity
62
+
63
+ def initialize
64
+ super
65
+ end
66
+ def self.schema
67
+ fields = Hash.new
68
+ fields[ :first_name ] = { :required => :flase, :type => String, :location => :local }
69
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
70
+ fields
71
+ end
72
+ end
73
+
74
+ assert_raises(ArgumentError) { some_class = SomeClass03.new }
75
+ end
76
+
77
+
78
+
79
+
80
+
81
+
82
+ it 'should raise an error when a :location gets neither :remote or :local for a value.' do
83
+
84
+ class SomeClass04 < CommandPost::Persistence
85
+ include CommandPost::Identity
86
+
87
+ def initialize
88
+ super
89
+ end
90
+
91
+ def self.schema
92
+ fields = Hash.new
93
+ fields[ :first_name ] = { :required => true, :type => String, :location => :x }
94
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
95
+ fields
96
+ end
97
+ end
98
+
99
+ assert_raises(ArgumentError) { some_class = SomeClass04.new }
100
+ end
101
+
102
+
103
+
104
+
105
+
106
+
107
+ it 'should raise an error when a :auto_load is true but type is not an CommandPost::Identity class.' do
108
+
109
+ class SomeClass05 < CommandPost::Persistence
110
+ include CommandPost::Identity
111
+
112
+ def initialize
113
+ super
114
+ end
115
+
116
+ def self.schema
117
+ fields = Hash.new
118
+ fields[ :first_name ] = { :required => true, :type => String, :location => :local, :auto_load => true }
119
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
120
+ fields
121
+ end
122
+ end
123
+
124
+ assert_raises(ArgumentError) { some_class = SomeClass05.new }
125
+ end
126
+
127
+
128
+
129
+
130
+
131
+
132
+ it 'should raise an error when a :auto_load is true, :type is Array and :of is not supplied.' do
133
+
134
+ class SomeClass06 < CommandPost::Persistence
135
+ include CommandPost::Identity
136
+
137
+ def initialize
138
+ super
139
+ end
140
+
141
+ def self.schema
142
+ fields = Hash.new
143
+ fields[ :first_name ] = { :required => true, :type => Array, :location => :remote, :auto_load => true }
144
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
145
+ fields
146
+ end
147
+ end
148
+
149
+ assert_raises(ArgumentError) { some_class = SomeClass06.new }
150
+ end
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+ it 'should raise an error when a :auto_load is true, :type is Array, :of is supplied but its value is not an CommandPost::Identity class.' do
159
+
160
+ class SomeClass06 < CommandPost::Persistence
161
+ include CommandPost::Identity
162
+
163
+ def initialize
164
+ super
165
+ end
166
+
167
+ def self.schema
168
+ fields = Hash.new
169
+ fields[ :first_name ] = { :required => false, :type => Array, :of => String, :location => :remote, :auto_load => true }
170
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
171
+ fields
172
+ end
173
+ end
174
+
175
+ assert_raises(ArgumentError) { some_class = SomeClass06.new }
176
+
177
+ end
178
+
179
+
180
+
181
+
182
+
183
+
184
+ it 'should raise an error when a :auto_load is true, :type is Array, :of is supplied but it is a CommandPost::IdentityPersistent class, not an CommandPost::Identity class.' do
185
+
186
+
187
+ class Helper07 < CommandPost::Persistence
188
+ end
189
+
190
+ class SomeClass07 < CommandPost::Persistence
191
+ include CommandPost::Identity
192
+
193
+ def initialize
194
+ super
195
+ end
196
+
197
+ def self.schema
198
+ fields = Hash.new
199
+ fields[ :first_name ] = { :required => true, :type => Array, :of => Helper07, :location => :remote, :auto_load => true }
200
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
201
+ fields
202
+ end
203
+ end
204
+
205
+ assert_raises(ArgumentError) { some_class = SomeClass07.new }
206
+
207
+ end
208
+
209
+
210
+
211
+
212
+
213
+
214
+ it 'should raise an error when a :auto_load is true, its value is Persistent, but not an CommandPost::Identity class.' do
215
+
216
+
217
+ class Helper08 < CommandPost::Persistence
218
+ end
219
+
220
+ class SomeClass08 < CommandPost::Persistence
221
+ include CommandPost::Identity
222
+
223
+ def initialize
224
+ super
225
+ end
226
+
227
+ def self.schema
228
+ fields = Hash.new
229
+ fields[ :first_name ] = { :required => true, :type => Helper08, :location => :remote, :auto_load => true }
230
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
231
+ fields
232
+ end
233
+ end
234
+
235
+ assert_raises(ArgumentError) { some_class = SomeClass08.new }
236
+ end
237
+
238
+
239
+
240
+
241
+ it 'should raise an error when an CommandPost::Identity class is the :type and location is :local.' do
242
+
243
+
244
+ class Helper09 < CommandPost::Persistence
245
+ include CommandPost::Identity
246
+ end
247
+
248
+ class SomeClass09 < CommandPost::Persistence
249
+ include CommandPost::Identity
250
+
251
+ def initialize
252
+ super
253
+ end
254
+
255
+ def self.schema
256
+ fields = Hash.new
257
+ fields[ :first_name ] = { :required => true, :type => Helper09, :location => :local }
258
+ fields[ :last_name ] = { :required => true, :type => String, :location => :local }
259
+ fields
260
+ end
261
+ end
262
+
263
+ assert_raises(ArgumentError) { some_class = SomeClass09.new }
264
+ end
265
+
266
+ end
267
+
268
+
269
+
@@ -0,0 +1,9 @@
1
+ require 'date'
2
+ require 'minitest/autorun'
3
+ require 'minitest/spec'
4
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/command_post/persistence/persistence')
5
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/command_post/persistence/data_validation')
6
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/command_post/identity/identity')
7
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/command_post/event_sourcing/aggregate')
8
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/command_post/event_sourcing/aggregate_event')
9
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/command_post/identity/sequence_generator')
File without changes
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: command_post
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Joe Meirow
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: CommandPost
42
+ email:
43
+ - joe.meirow@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - Gemfile.lock
51
+ - README.md
52
+ - Rakefile
53
+ - command_post.gemspec
54
+ - lib/command_post/command/command.rb
55
+ - lib/command_post/command_post.rb
56
+ - lib/command_post/db/connection.rb
57
+ - lib/command_post/db/postgresql.sql
58
+ - lib/command_post/event_sourcing/aggregate.rb
59
+ - lib/command_post/event_sourcing/aggregate_event.rb
60
+ - lib/command_post/identity/identity.rb
61
+ - lib/command_post/identity/sequence_generator.rb
62
+ - lib/command_post/persistence/aggregate_pointer.rb
63
+ - lib/command_post/persistence/auto_load.rb
64
+ - lib/command_post/persistence/data_validation.rb
65
+ - lib/command_post/persistence/persistence.rb
66
+ - lib/command_post/persistence/schema_validation.rb
67
+ - lib/command_post/util/hash_util.rb
68
+ - lib/command_post/util/string_util.rb
69
+ - lib/command_post/version.rb
70
+ - spec/command_post/command/command_spec.rb
71
+ - spec/command_post/identity/identity_lookup_value_aggregate_id_spec.rb
72
+ - spec/command_post/identity/identity_lookup_value_checksum_spec.rb
73
+ - spec/command_post/identity/identity_lookup_value_field_spec.rb
74
+ - spec/command_post/persistence/data_validation_spec.rb
75
+ - spec/command_post/persistence/nested_remote_spec.rb
76
+ - spec/command_post/persistence/schema_validation_spec.rb
77
+ - spec/command_post/require.rb
78
+ - spec/spec_helper.rb
79
+ homepage: http://github.com/jmeirow/command_post
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.7
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: CommandPost - Object storage/retrieval, event sourcing, command pattern
103
+ test_files:
104
+ - spec/command_post/command/command_spec.rb
105
+ - spec/command_post/identity/identity_lookup_value_aggregate_id_spec.rb
106
+ - spec/command_post/identity/identity_lookup_value_checksum_spec.rb
107
+ - spec/command_post/identity/identity_lookup_value_field_spec.rb
108
+ - spec/command_post/persistence/data_validation_spec.rb
109
+ - spec/command_post/persistence/nested_remote_spec.rb
110
+ - spec/command_post/persistence/schema_validation_spec.rb
111
+ - spec/command_post/require.rb
112
+ - spec/spec_helper.rb