dry-facts 0.3.0 → 0.4.0

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.
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