realm-core 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/realm-core.rb +11 -0
  3. data/lib/realm.rb +20 -0
  4. data/lib/realm/action_handler.rb +84 -0
  5. data/lib/realm/action_handler/result.rb +32 -0
  6. data/lib/realm/builder.rb +84 -0
  7. data/lib/realm/command_handler.rb +18 -0
  8. data/lib/realm/config.rb +56 -0
  9. data/lib/realm/container.rb +65 -0
  10. data/lib/realm/context.rb +35 -0
  11. data/lib/realm/dependency.rb +22 -0
  12. data/lib/realm/dispatcher.rb +66 -0
  13. data/lib/realm/domain_resolver.rb +53 -0
  14. data/lib/realm/error.rb +62 -0
  15. data/lib/realm/event.rb +55 -0
  16. data/lib/realm/event_factory.rb +49 -0
  17. data/lib/realm/event_handler.rb +94 -0
  18. data/lib/realm/event_router.rb +91 -0
  19. data/lib/realm/event_router/gateway.rb +50 -0
  20. data/lib/realm/event_router/internal_loop_gateway.rb +48 -0
  21. data/lib/realm/health_status.rb +44 -0
  22. data/lib/realm/mixins/aggregate_member.rb +25 -0
  23. data/lib/realm/mixins/context_injection.rb +47 -0
  24. data/lib/realm/mixins/controller.rb +50 -0
  25. data/lib/realm/mixins/decorator.rb +33 -0
  26. data/lib/realm/mixins/dependency_injection.rb +50 -0
  27. data/lib/realm/mixins/reactive.rb +30 -0
  28. data/lib/realm/mixins/repository_helper.rb +41 -0
  29. data/lib/realm/multi_worker.rb +30 -0
  30. data/lib/realm/persistence.rb +51 -0
  31. data/lib/realm/persistence/repository_query_handler_adapter.rb +21 -0
  32. data/lib/realm/plugin.rb +17 -0
  33. data/lib/realm/query_handler.rb +6 -0
  34. data/lib/realm/runtime.rb +51 -0
  35. data/lib/realm/runtime/session.rb +31 -0
  36. data/lib/realm/types.rb +9 -0
  37. metadata +36 -3
  38. data/README.md +0 -40
  39. data/Rakefile +0 -19
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ class Persistence
5
+ class InvalidPersistanceType < Realm::Error; end
6
+ class Conflict < Realm::Error; end
7
+
8
+ class RelationIsReadOnly < Realm::Error
9
+ def initialize(relation, msg: "Cannot write using read-only relation #{relation.class}")
10
+ super(msg)
11
+ end
12
+ end
13
+
14
+ class RepositoryIsReadOnly < Realm::Error
15
+ def initialize(repo, msg: "Cannot write using read-only repository #{repo.class}")
16
+ super(msg)
17
+ end
18
+ end
19
+
20
+ def self.setup(...)
21
+ new(...).setup
22
+ end
23
+
24
+ def initialize(container, repositories)
25
+ @container = container
26
+ @repositories = repositories
27
+ end
28
+
29
+ def setup
30
+ register_repos
31
+ end
32
+
33
+ private
34
+
35
+ def gateway
36
+ @gateway ||= @container.resolve('persistence.gateway')
37
+ end
38
+
39
+ def register_repos
40
+ @repositories.each do |repo_class|
41
+ @container.register_factory(repo_class, gateway, as: "#{repo_class.name.demodulize.underscore}_repo")
42
+ end
43
+ end
44
+
45
+ def constantize(*parts)
46
+ return parts[0] unless parts[0].is_a?(String)
47
+
48
+ parts.join('::').safe_constantize
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ class Persistence
5
+ class QueryCannotModifyState < Realm::Error; end
6
+
7
+ class RepositoryQueryHandlerAdapter
8
+ def initialize(repo)
9
+ @repo = repo.respond_to?(:readonly) ? repo.readonly : repo
10
+ end
11
+
12
+ def call(action:, params: {}, **)
13
+ raise CannotHandleAction.new(self, action) unless @repo.respond_to?(action)
14
+
15
+ @repo.send(action, **params)
16
+ rescue RepositoryIsReadOnly
17
+ raise QueryCannotModifyState
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ class Plugin
5
+ class << self
6
+ def plugin_name(value = :not_provided)
7
+ @plugin_name = value.to_sym unless value == :not_provided
8
+ @plugin_name = name.split('::')[-2].underscore.to_sym unless defined?(@plugin_name)
9
+ @plugin_name
10
+ end
11
+
12
+ def setup(_config, _container)
13
+ raise NotImplementedError
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ class QueryHandler < Realm::ActionHandler
5
+ end
6
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ class Runtime
5
+ delegate :query, :run, :run_as_job, :wait_for_jobs, to: :dispatcher
6
+ delegate :trigger, :add_listener, to: :event_router
7
+ delegate :[], to: :context
8
+ attr_reader :container
9
+
10
+ def initialize(container = Container.new)
11
+ @container = Container[container]
12
+ end
13
+
14
+ def context
15
+ @context ||= Context.new(@container)
16
+ end
17
+
18
+ def session(context = {})
19
+ context.blank? ? self : Session.new(self, context)
20
+ end
21
+
22
+ def worker(*args)
23
+ MultiWorker.new(event_router.try(:workers, *args) || [])
24
+ end
25
+
26
+ def health
27
+ component_statuses = container.each_with_object({}) do |(name, component), map|
28
+ map[name] = component.health if component.respond_to?(:health) && !component.is_a?(Runtime)
29
+ end
30
+ HealthStatus.combine(component_statuses)
31
+ end
32
+
33
+ # Get all active messaging queues. For maintenance purpose only.
34
+ # TODO: Introduce component container and allow to call those method directly on components instead of
35
+ # polluting runtime
36
+ # Example: engine.realm.components.find(type: Realm::EventRouter::SNSGateway).try(:active_queues)
37
+ def active_queues
38
+ event_router.try(:active_queues) || []
39
+ end
40
+
41
+ private
42
+
43
+ def dispatcher
44
+ @dispatcher ||= container.create(Dispatcher, self)
45
+ end
46
+
47
+ def event_router
48
+ @container[EventRouter]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ class Runtime
5
+ class Session
6
+ delegate :query, :run, :run_as_job, :wait_for_jobs, to: :dispatcher
7
+ delegate :add_listener, :trigger, :worker, to: :@runtime
8
+ delegate :[], to: :context
9
+ attr_reader :context
10
+
11
+ def initialize(runtime, context)
12
+ @runtime = runtime
13
+ @context = runtime.context.merge(context)
14
+ end
15
+
16
+ def session(context = {})
17
+ context.blank? ? self : self.class.new(self, context)
18
+ end
19
+
20
+ def container
21
+ @runtime.container
22
+ end
23
+
24
+ private
25
+
26
+ def dispatcher
27
+ @dispatcher ||= container.create(Dispatcher, self)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-types'
4
+
5
+ module Realm
6
+ module Types
7
+ include Dry.Types()
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: realm-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - developers@reevoo.com
@@ -170,8 +170,41 @@ executables: []
170
170
  extensions: []
171
171
  extra_rdoc_files: []
172
172
  files:
173
- - README.md
174
- - Rakefile
173
+ - lib/realm-core.rb
174
+ - lib/realm.rb
175
+ - lib/realm/action_handler.rb
176
+ - lib/realm/action_handler/result.rb
177
+ - lib/realm/builder.rb
178
+ - lib/realm/command_handler.rb
179
+ - lib/realm/config.rb
180
+ - lib/realm/container.rb
181
+ - lib/realm/context.rb
182
+ - lib/realm/dependency.rb
183
+ - lib/realm/dispatcher.rb
184
+ - lib/realm/domain_resolver.rb
185
+ - lib/realm/error.rb
186
+ - lib/realm/event.rb
187
+ - lib/realm/event_factory.rb
188
+ - lib/realm/event_handler.rb
189
+ - lib/realm/event_router.rb
190
+ - lib/realm/event_router/gateway.rb
191
+ - lib/realm/event_router/internal_loop_gateway.rb
192
+ - lib/realm/health_status.rb
193
+ - lib/realm/mixins/aggregate_member.rb
194
+ - lib/realm/mixins/context_injection.rb
195
+ - lib/realm/mixins/controller.rb
196
+ - lib/realm/mixins/decorator.rb
197
+ - lib/realm/mixins/dependency_injection.rb
198
+ - lib/realm/mixins/reactive.rb
199
+ - lib/realm/mixins/repository_helper.rb
200
+ - lib/realm/multi_worker.rb
201
+ - lib/realm/persistence.rb
202
+ - lib/realm/persistence/repository_query_handler_adapter.rb
203
+ - lib/realm/plugin.rb
204
+ - lib/realm/query_handler.rb
205
+ - lib/realm/runtime.rb
206
+ - lib/realm/runtime/session.rb
207
+ - lib/realm/types.rb
175
208
  homepage:
176
209
  licenses:
177
210
  - MIT
data/README.md DELETED
@@ -1,40 +0,0 @@
1
- # Realm
2
-
3
- Domain layer framework following Domain-driven/CQRS design principles.
4
-
5
- [![Build status](https://badge.buildkite.com/346cce75f6c31e0a41bb98b198e85eb6b722243624459fad9c.svg)](https://buildkite.com/reevoo/realm)
6
-
7
- ## Service layers
8
-
9
- We follow the standard MVC design pattern of Rails but giving the model layer more structure and guidance regarding where
10
- to put your code. The model is split into domain layer (using our [Realm](https://github.com/reevoo/smart-mono/tree/master/gems/realm) library)
11
- and persistence layer (using [ROM](https://rom-rb.org/) library). The individual components are explained in the following section.
12
-
13
- ![Service layers](https://confluence-connect.gliffy.net/embed/image/d02d04b1-5e40-415f-b7ba-3a631efa9bf3.png?utm_medium=live&utm_source=custom)
14
-
15
- Advanced components are shown in lighter color, those will be needed only later on as the service domain logic grows.
16
-
17
- ## Model layer components
18
-
19
- ![Service external components](https://confluence-connect.gliffy.net/embed/image/c593fcc2-304e-47c3-8e3c-b0cc09e0ed54.png?utm_medium=live&utm_source=custom)
20
-
21
- Each service has one **domain** module which consists of multiple [**aggregate**](https://martinfowler.com/bliki/DDD_Aggregate.html) modules.
22
- Aggregate is a cluster of domain objects that can be treated as a single unit. The only way for outer world to communicate
23
- with aggregate is by **queries** and **commands**. Query exposes aggregate's internal state and command changes it.
24
- The state of an aggregate is represented by tree of **entities** with one being the aggregate root and zero or more dependent
25
- entities with *belongs_to* relation to the root entity. The state of an aggregate (entity tree) is persisted
26
- and retrieved by **repository**. There is generally one repository per aggregate unless we split the read/write
27
- (query/command) persistence model for that particular domain. The repository uses **relations** to access the database
28
- tables. Each relation class represents one table.
29
-
30
-
31
- ## Where to put my code as it grows?
32
-
33
- TODO
34
-
35
-
36
- ## Roadmap
37
-
38
- - [ ] Support Ruby 3
39
- - [ ] Make it work outside of Rails engines
40
- - [ ] Support multiple persistence gateways in one runtime
data/Rakefile DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require 'bundler/setup'
5
- rescue LoadError
6
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
- end
8
-
9
- require 'rdoc/task'
10
-
11
- RDoc::Task.new(:rdoc) do |rdoc|
12
- rdoc.rdoc_dir = 'rdoc'
13
- rdoc.title = 'Realm'
14
- rdoc.options << '--line-numbers'
15
- rdoc.rdoc_files.include('README.md')
16
- rdoc.rdoc_files.include('lib/**/*.rb')
17
- end
18
-
19
- require 'bundler/gem_tasks'