dry-facts 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b341b5c19a83f7f568b2cb9ad1b4f2caf14ec394d061c08509f0bc2940efd4c5
4
- data.tar.gz: 36e9b955c5511f7ba03a0f6be0b682d79a1f3da410d77e2dfdced632f780a030
3
+ metadata.gz: 35e96fd751117a68e6492f8472722648f80a1cd49fa0830cdba2fb4b579b1fce
4
+ data.tar.gz: 2e2f7b7374ea7e141df10b332f04e836f2475423995ff0518d6b196bb3b18cb3
5
5
  SHA512:
6
- metadata.gz: fbeaffa2e91b48af5c9304e2fda103cfb104b8830971599a1168c4ea5392bd478449e2092f920725f1db7e824b85c372de16215fdcdc1225d636149f4a663b8e
7
- data.tar.gz: 7e6e32fac315907ad1a60f547fd9e9c012d59498892d1390a5af2afc6b31ec686c36dbde3324261ff2489dae86d7d8e7df5d41db805be1c7c69c544ad480eefe
6
+ metadata.gz: 4d1ee1eef74e2fdb5379777c8cb91b9c3bc6612543736e9687beb7c812b9210eb7c2722ec47a75c965ff2744efc592b643ff2ea46534ef1bbfdfdb9af7128145
7
+ data.tar.gz: 7eefafc1aa1bf0ce211b752cd6a26028506aaba9739ce51985cd40828ebf3e755dc1ab4f32194c0d33899127f621249944e76b5831e089eb09f78b85de826172
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
- source "https://rubygems.org"
1
+ ruby "2.5.0"
2
+ source "https://rubygems.org"
2
3
 
3
4
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
5
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dry-facts (0.2.0)
4
+ dry-facts (0.3.0)
5
5
  dry-equalizer (>= 0.0.11)
6
6
  dry-events (>= 0.1.0)
7
7
  dry-struct
@@ -66,5 +66,8 @@ DEPENDENCIES
66
66
  minitest (>= 5.0)
67
67
  rake (>= 10.0)
68
68
 
69
+ RUBY VERSION
70
+ ruby 2.5.0p0
71
+
69
72
  BUNDLED WITH
70
73
  1.16.1
data/README.md CHANGED
@@ -3,6 +3,13 @@
3
3
  EventSourcing ruby toolkit, somewhat based on dry-rb primitives.
4
4
  Opinionated. Raw.
5
5
 
6
+ ## Rationale
7
+
8
+ People dont *know* or *understand* software projects, people navigate themselves through software projects.
9
+ To effectively navigate through structure and mutable state of big systems - programmers need sub-systems to be isolated.
10
+ Usable incapsulation - barriers have to be visible and hard to break.
11
+ Readability matters - declarative readable code wins.
12
+
6
13
  ## Goals
7
14
 
8
15
  * General EventSourcing toolkit for Ruby
data/ROADMAP.md CHANGED
@@ -1,33 +1,23 @@
1
1
  # Roadmap
2
2
 
3
- Big vision behind this project is to build powerful toolkit that would allow
4
- rapid application development using EventSourcing as a core architectural
5
- pattern.
3
+ Goal is to build toolkit that would allow rapid application development using EventSourcing as a core architectural pattern.
6
4
 
7
- Being able to build core behaviors and exposing those through GraphQL to the
8
- customers is the basic idea.
5
+ Being able to build core behaviors and exposing those through GraphQL to the customers is the basic idea.
9
6
 
10
7
  Goal is multidimensional:
11
- GraphQL generation from bounded context code (?),
12
- persistance,
13
- serialization,
14
- validations,
15
- nested transactions,
16
- async execution,
17
- command composition
18
-
8
+ Autogenerated GraphQL schema
9
+ EventSourcing toolkit
10
+ Idiomatic, human-friendly DSL
19
11
 
20
12
  ## Top to bottom vision
21
-
22
- Autogenerated GraphQL used to invoke Commands and Queries, which read from Projections,
23
- Aggregates, generate and persist events. Events persisted in EventStore.
13
+ Autogenerated GraphQL used to invoke Commands and Queries, which read from Projections, Aggregates, generate and persist events. Events persisted in EventStore.
24
14
 
25
15
  ## Approach
26
16
 
27
17
  Minimal prototypes of primitives
28
18
  Minimal prototype of integrated system
29
19
  Minimal prototype of application based on system
30
- Refactoring
20
+ Refactoring-Improvement-Refactoring
31
21
 
32
22
  ## Challenges
33
23
 
@@ -35,6 +25,13 @@ Brain split,
35
25
  Deliver once,
36
26
  Transactional consistency,
37
27
  Nesting transactions,
28
+ Persistence,
29
+ Serialization,
30
+ Validations,
31
+ Command composition,
32
+ Nested transactions,
33
+ Async execution
34
+
38
35
  Event/Command/Schema evolution (behavior, naming, structure),
39
36
  Identity (Sequent -- Repository for aggregates.
40
37
  Implements the Unit-Of-Work and Identity-Map patterns to ensure each aggregate is only loaded once per transaction and that you always get the same aggregate instance back.)
@@ -46,6 +43,14 @@ No explicit types ?
46
43
 
47
44
 
48
45
  ## Checklist
46
+ * DX
47
+ - [x] Git Flow
48
+ - [ ] CI
49
+ - [ ] Ruby below 2.5.0 (yield_self usage)
50
+ - [ ] Linter
51
+ - [ ] Dependency watcher
52
+ - [ ] Badges
53
+
49
54
  * Command
50
55
  - [x] Skeleton without any meaningful structure
51
56
  - [x] With inner class input contract
@@ -54,6 +59,7 @@ No explicit types ?
54
59
  - [x] With explicit method output contract
55
60
  - [x] Without input contract
56
61
  - [x] Without output contract
62
+ - [ ] Dry-transaction?
57
63
  - [ ] Unified result (Relay?)
58
64
  - [ ] Multistep
59
65
  - [ ] Composition
@@ -68,23 +74,27 @@ No explicit types ?
68
74
  - [x] In memory store
69
75
  - [ ] Serialization and typecasting?
70
76
  - [x] Aggregates
77
+ - [ ] Snapshots
71
78
  - [ ] Causality
72
79
  - [ ] Correlations
73
80
  - [ ] Transactions
74
- - [ ] Snapshots
75
81
  - [ ] Projections
76
82
  - [ ] Versioning
77
83
  - [ ] Locking
84
+ - [ ] Blockchain?
78
85
  - [ ] Lifecycle and maintenance tasks
79
86
  - [ ] Sequel store
80
87
  - [ ] ActiveRecord store
81
88
  - [ ] Redis store
82
89
  - [ ] Kafka store
90
+ - [ ] IPFS store?
91
+ - [ ] IPDB store?
83
92
  - [ ] Docs from comments
84
93
  * Event
85
94
  - [ ] Hash?
86
95
  - [x] Object?
87
- - [ ] Aggregate DSL
96
+ - [x] Immutability?
97
+ - [x] Aggregate DSL
88
98
  - [ ] Correlation DSL
89
99
  - [ ] Causation DSL
90
100
  - [ ] Module?
@@ -97,6 +107,8 @@ No explicit types ?
97
107
  - [x] Class instance
98
108
  - [x] With events
99
109
  - [x] Data transfer DSL
110
+ - [x] To hash
111
+ - [ ] Aggregate from namespaces (*::Events* ?)
100
112
  - [ ] Stream DSL
101
113
  - [ ] Projection DSL
102
114
  - [ ] Conversion to Hash
@@ -104,6 +116,8 @@ No explicit types ?
104
116
  - [ ] With contract?
105
117
  - [ ] Code & test generator
106
118
  - [ ] Docs from comments
119
+ * Projections
120
+ - [ ] Skeleton without any functionality
107
121
  * GraphQL
108
122
  - [x] Data type
109
123
  - [x] Query
@@ -115,7 +129,6 @@ No explicit types ?
115
129
  - [ ] Query generation
116
130
  - [ ] Mutation generation
117
131
  - [ ] Schema from hash?
118
- * CI
119
132
  * JRuby tests
120
133
  * OpalRuby tests
121
134
 
@@ -12,40 +12,39 @@ module Dry
12
12
  attr_accessor :uuid
13
13
 
14
14
  class << self
15
- def build_one_from_events events
16
- self
17
- .new(events)
15
+ def aggregate_data_from_event_types *event_klasses
16
+ event_klasses.each do |klass|
17
+ define_event_type_handler klass, :_transfer_data_from_event
18
+ end
18
19
  end
19
20
 
20
21
  def build_all_from_events events
21
22
  events
22
- .group_by {|e| e.aggregate_id }
23
- .map {|_, g_events| build_one_from_events(g_events) }
23
+ .group_by {|e| e.aggregate_id }
24
+ .map {|_, g_events| build_one_from_events(g_events) }
24
25
  end
25
26
 
26
- def event_types
27
- @event_handlers.keys
27
+ def build_one_from_events events
28
+ self
29
+ .new(events)
28
30
  end
29
31
 
30
- def event_handlers
31
- @event_handlers
32
+ def define_event_type_handler klass, method_name
33
+ @event_handlers ||= {}
34
+ @event_handlers[klass.name] = method_name
32
35
  end
33
36
 
34
- def find_event_handler(key)
35
- (@event_handlers)[key]
37
+ def event_handlers
38
+ @event_handlers
36
39
  end
37
40
 
38
- def define_event_handler(name, method_name= :no_op)
39
- @event_handlers ||= {}
40
- @event_handlers[name] = method_name
41
+ def event_types
42
+ @event_handlers.keys
41
43
  end
42
44
 
43
- def aggregate_data_from_event_types(*event_klasses)
44
- event_klasses.each do |klass|
45
- define_event_handler klass.name, :_transfer_data_from_event
46
- end
45
+ def find_event_handler(key)
46
+ (@event_handlers)[key]
47
47
  end
48
-
49
48
  end
50
49
 
51
50
  def initialize(events)
@@ -59,9 +58,12 @@ module Dry
59
58
  end
60
59
 
61
60
  def to_h
62
- {id: self.id, email: self.email}
61
+ self
62
+ .instance_variables
63
+ .map {|ivar_name| ivar_name.to_s.gsub(/@/, '')}
64
+ .yield_self {|ivars| ivars - ['events', 'uuid']}
65
+ .reduce(Hash.new) {|memo, obj| memo[obj.to_sym] = self.send(obj); memo }
63
66
  end
64
-
65
67
  alias_method :to_hash, :to_h
66
68
 
67
69
  private
@@ -70,20 +72,22 @@ module Dry
70
72
  uuid = SecureRandom.uuid,
71
73
  { id: uuid,
72
74
  uuid: uuid,
73
- type: { name: self.class.name,
74
- version: '0' } }
75
+ type: { name: self.class.name } }
75
76
  end
76
77
 
77
78
  def _handle_event event
78
79
  if self.uuid != event.metadata[:aggregate_id]
79
- fail "Event don't belong to aggregate instance. Aggregate #{self.inspect}, Event: #{event.inspect}"
80
+ fail "Event don't belong to aggregate instance. \n
81
+ Aggregate #{self.inspect} \n
82
+ Event: #{event.inspect}"
80
83
  end
84
+
81
85
  handler_name =
82
86
  self
83
87
  .class
84
88
  .find_event_handler(event.metadata[:type][:name])
85
89
 
86
- self.send(handler_name, event)
90
+ self.send(handler_name, event) if handler_name
87
91
  end
88
92
 
89
93
  def _transfer_data_from_event event
@@ -36,14 +36,14 @@ module Dry
36
36
  def define_input_contract &block
37
37
  @input_contract =
38
38
  Class
39
- .new(Dry::Struct)
39
+ .new(Dry::Struct::Value)
40
40
  .yield_self { |k| k.instance_eval(&block) if block }
41
41
  end
42
42
 
43
43
  def define_output_contract &block
44
44
  @output_contract =
45
45
  Class
46
- .new(Dry::Struct)
46
+ .new(Dry::Struct::Value)
47
47
  .yield_self { |k| k.instance_eval(&block) if block }
48
48
  end
49
49
 
@@ -54,7 +54,8 @@ module Dry
54
54
  self::InputContract
55
55
  else
56
56
  self.input_contract
57
- end.yield_self {|c| _enforce_contract_if_present(c, input) }
57
+ end
58
+ .yield_self {|c| _enforce_contract_if_present(c, input) }
58
59
  end
59
60
 
60
61
  def _enforce_output_contract_on output
@@ -62,16 +63,17 @@ module Dry
62
63
  self::OutputContract
63
64
  else
64
65
  self.output_contract
65
- end.yield_self {|c| _enforce_contract_if_present(c, output) }
66
+ end
67
+ .yield_self {|c| _enforce_contract_if_present(c, output) }
66
68
  end
67
69
 
68
70
  def _execute_with input
69
71
  self.new.call input
70
72
  end
71
73
 
72
- def _enforce_contract_if_present(contract, data)
74
+ def _enforce_contract_if_present contract, data
73
75
  if contract
74
- contract.new(**data)
76
+ contract.new **data
75
77
  else
76
78
  data
77
79
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Facts
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-facts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andriy Tyurnikov