realm-core 0.7.1 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +40 -0
- data/Rakefile +19 -0
- metadata +25 -44
- data/lib/realm-core.rb +0 -6
- data/lib/realm.rb +0 -22
- data/lib/realm/action_handler.rb +0 -84
- data/lib/realm/action_handler/result.rb +0 -32
- data/lib/realm/builder.rb +0 -93
- data/lib/realm/command_handler.rb +0 -23
- data/lib/realm/config.rb +0 -57
- data/lib/realm/container.rb +0 -68
- data/lib/realm/context.rb +0 -37
- data/lib/realm/dependency.rb +0 -24
- data/lib/realm/dispatcher.rb +0 -74
- data/lib/realm/domain_resolver.rb +0 -59
- data/lib/realm/error.rb +0 -62
- data/lib/realm/event.rb +0 -56
- data/lib/realm/event_factory.rb +0 -53
- data/lib/realm/event_handler.rb +0 -102
- data/lib/realm/event_router.rb +0 -100
- data/lib/realm/event_router/gateway.rb +0 -50
- data/lib/realm/event_router/internal_loop_gateway.rb +0 -50
- data/lib/realm/health_status.rb +0 -46
- data/lib/realm/mixins/aggregate_member.rb +0 -25
- data/lib/realm/mixins/context_injection.rb +0 -49
- data/lib/realm/mixins/controller.rb +0 -53
- data/lib/realm/mixins/decorator.rb +0 -33
- data/lib/realm/mixins/dependency_injection.rb +0 -52
- data/lib/realm/mixins/reactive.rb +0 -32
- data/lib/realm/mixins/repository_helper.rb +0 -43
- data/lib/realm/multi_worker.rb +0 -30
- data/lib/realm/persistence.rb +0 -54
- data/lib/realm/persistence/repository_query_handler_adapter.rb +0 -24
- data/lib/realm/plugin.rb +0 -20
- data/lib/realm/query_handler.rb +0 -8
- data/lib/realm/runtime.rb +0 -61
- data/lib/realm/runtime/session.rb +0 -33
- data/lib/realm/types.rb +0 -9
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/module/introspection'
|
4
|
-
require 'active_support/core_ext/class/attribute'
|
5
|
-
|
6
|
-
module Realm
|
7
|
-
module Mixins
|
8
|
-
module Controller
|
9
|
-
def self.included(base)
|
10
|
-
base.class_attribute(:aggregate_name)
|
11
|
-
base.extend(ClassMethods)
|
12
|
-
end
|
13
|
-
|
14
|
-
def domain_runtime
|
15
|
-
@domain_runtime ||= root_domain_runtime.session(domain_context)
|
16
|
-
end
|
17
|
-
|
18
|
-
def domain_context
|
19
|
-
{}
|
20
|
-
end
|
21
|
-
|
22
|
-
def query(identifier, params = {})
|
23
|
-
domain_runtime.query(get_dispatchable(identifier), params)
|
24
|
-
end
|
25
|
-
|
26
|
-
def run(identifier, params = {})
|
27
|
-
domain_runtime.run(get_dispatchable(identifier), params)
|
28
|
-
end
|
29
|
-
|
30
|
-
def run_as_job(identifier, params = {})
|
31
|
-
domain_runtime.run_as_job(get_dispatchable(identifier), params)
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def get_dispatchable(identifier)
|
37
|
-
return identifier if identifier.respond_to?(:call)
|
38
|
-
|
39
|
-
[aggregate_name, identifier].compact.join('.')
|
40
|
-
end
|
41
|
-
|
42
|
-
def root_domain_runtime
|
43
|
-
self.class.module_parents[-2].realm
|
44
|
-
end
|
45
|
-
|
46
|
-
module ClassMethods
|
47
|
-
def with_aggregate(name)
|
48
|
-
self.aggregate_name = name
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Realm
|
4
|
-
module Mixins
|
5
|
-
module Decorator
|
6
|
-
def self.[](decorated) # rubocop:disable Metrics/MethodLength
|
7
|
-
Module.new do
|
8
|
-
def method_missing(...)
|
9
|
-
_decorated.send(...)
|
10
|
-
end
|
11
|
-
|
12
|
-
def respond_to_missing?(...)
|
13
|
-
_decorated.respond_to?(...)
|
14
|
-
end
|
15
|
-
|
16
|
-
if decorated.to_s[0] == '@'
|
17
|
-
define_method :initialize do |value|
|
18
|
-
instance_variable_set(decorated, value)
|
19
|
-
end
|
20
|
-
|
21
|
-
define_method :_decorated do
|
22
|
-
instance_variable_get(decorated)
|
23
|
-
end
|
24
|
-
else
|
25
|
-
define_method :_decorated do
|
26
|
-
send(decorated)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/dependency'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
module Mixins
|
7
|
-
module DependencyInjection
|
8
|
-
def self.included(base)
|
9
|
-
base.extend(ClassMethods)
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def new(*args, **kwargs, &block)
|
14
|
-
instance = allocate
|
15
|
-
deps.each { |d| define_dependency_method(instance, kwargs, d) }
|
16
|
-
kwargs_without_dependencies = kwargs.reject { |k, _| deps.any? { |d| d.name == k } }
|
17
|
-
instance.send(:initialize, *args, **kwargs_without_dependencies, &block)
|
18
|
-
instance
|
19
|
-
end
|
20
|
-
|
21
|
-
def inject(*dependables, **options)
|
22
|
-
deps.concat(dependables.map { |d| Dependency.new(d, **options) })
|
23
|
-
end
|
24
|
-
|
25
|
-
def dependencies
|
26
|
-
deps.freeze
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def deps
|
32
|
-
@deps ||= []
|
33
|
-
end
|
34
|
-
|
35
|
-
def define_dependency_method(instance, kwargs, spec)
|
36
|
-
dependency = kwargs[spec.name]
|
37
|
-
instance.singleton_class.class_eval do
|
38
|
-
define_method(spec.name) do
|
39
|
-
return dependency unless spec.lazy?
|
40
|
-
|
41
|
-
var = "@#{spec.name}"
|
42
|
-
return instance_variable_get(var) if instance_variable_defined?(var)
|
43
|
-
|
44
|
-
instance_variable_set(var, dependency.respond_to?(:call) ? dependency.call : dependency)
|
45
|
-
end
|
46
|
-
protected spec.name
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/error'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
module Mixins
|
7
|
-
module Reactive
|
8
|
-
protected
|
9
|
-
|
10
|
-
def run(command, params = {})
|
11
|
-
parts = command.to_s.split('.')
|
12
|
-
parts.prepend(aggregate) if parts.size == 1 && respond_to?(:aggregate) && aggregate
|
13
|
-
@runtime.run(parts.join('.'), params.to_h)
|
14
|
-
end
|
15
|
-
|
16
|
-
def trigger(event_type, attributes = {})
|
17
|
-
attributes = attributes.to_h
|
18
|
-
head = { origin: origin(caller_locations(1, 1)) }.merge(attributes.fetch(:head, {}))
|
19
|
-
final_attrs = attributes.merge(head: head)
|
20
|
-
final_attrs[:cause] ||= context[:cause] if context.key?(:cause)
|
21
|
-
@runtime.trigger(event_type, final_attrs)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
# Detects the class and method from which this event is triggered
|
27
|
-
def origin(backtrace)
|
28
|
-
[self.class.name, backtrace[0].to_s.match(/`([^']+)'/)&.then { |m| "##{m[1]}" }].join
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/error'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
module Mixins
|
7
|
-
module RepositoryHelper
|
8
|
-
class OnlyOneWriteRepo < Realm::Error['You can have only one read/write repo per handler']; end
|
9
|
-
class InjectingRepoOutsideAggregate < Realm::Error['Cannot auto inject repository outside of an aggregate']; end
|
10
|
-
|
11
|
-
def self.included(base)
|
12
|
-
base.extend(ClassMethods)
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
protected
|
17
|
-
|
18
|
-
def use_repo(*names, readonly: self < Realm::QueryHandler)
|
19
|
-
raise OnlyOneWriteRepo if !readonly && (names.size > 1 || defined?(@write_repo_injected))
|
20
|
-
|
21
|
-
names << default_repo_name if names.empty?
|
22
|
-
names.each { |name| inject_repo(name, readonly) }
|
23
|
-
@write_repo_injected = true unless readonly
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def inject_repo(name, readonly)
|
29
|
-
repo_name = "#{name}_repo"
|
30
|
-
return inject(repo_name) unless readonly
|
31
|
-
|
32
|
-
inject(repo_name) { |repo| repo.respond_to?(:readonly) ? repo.readonly : repo }
|
33
|
-
end
|
34
|
-
|
35
|
-
def default_repo_name
|
36
|
-
raise InjectingRepoOutsideAggregate unless respond_to?(:aggregate)
|
37
|
-
|
38
|
-
aggregate
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/realm/multi_worker.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Realm
|
4
|
-
class MultiWorker
|
5
|
-
def initialize(workers = [])
|
6
|
-
@workers = workers
|
7
|
-
end
|
8
|
-
|
9
|
-
def start(*args)
|
10
|
-
@workers.each { |w| w.start(*args) }
|
11
|
-
self
|
12
|
-
end
|
13
|
-
|
14
|
-
def stop(timeout: 30)
|
15
|
-
@workers.each { |w| w.stop(timeout: timeout) }
|
16
|
-
end
|
17
|
-
|
18
|
-
def join
|
19
|
-
@workers.each(&:join)
|
20
|
-
end
|
21
|
-
|
22
|
-
def run
|
23
|
-
%w[INT TERM].each do |signal|
|
24
|
-
Signal.trap(signal) { stop }
|
25
|
-
end
|
26
|
-
start
|
27
|
-
join
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/realm/persistence.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/string'
|
4
|
-
require 'realm/error'
|
5
|
-
|
6
|
-
module Realm
|
7
|
-
class Persistence
|
8
|
-
class InvalidPersistanceType < Realm::Error; end
|
9
|
-
class Conflict < Realm::Error; end
|
10
|
-
|
11
|
-
class RelationIsReadOnly < Realm::Error
|
12
|
-
def initialize(relation, msg: "Cannot write using read-only relation #{relation.class}")
|
13
|
-
super(msg)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class RepositoryIsReadOnly < Realm::Error
|
18
|
-
def initialize(repo, msg: "Cannot write using read-only repository #{repo.class}")
|
19
|
-
super(msg)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.setup(...)
|
24
|
-
new(...).setup
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(container, repositories)
|
28
|
-
@container = container
|
29
|
-
@repositories = repositories
|
30
|
-
end
|
31
|
-
|
32
|
-
def setup
|
33
|
-
register_repos
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def gateway
|
39
|
-
@gateway ||= @container.resolve('persistence.gateway')
|
40
|
-
end
|
41
|
-
|
42
|
-
def register_repos
|
43
|
-
@repositories.each do |repo_class|
|
44
|
-
@container.register_factory(repo_class, gateway, as: "#{repo_class.name.demodulize.underscore}_repo")
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def constantize(*parts)
|
49
|
-
return parts[0] unless parts[0].is_a?(String)
|
50
|
-
|
51
|
-
parts.join('::').safe_constantize
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/persistence'
|
4
|
-
require 'realm/error'
|
5
|
-
|
6
|
-
module Realm
|
7
|
-
class Persistence
|
8
|
-
class QueryCannotModifyState < Realm::Error; end
|
9
|
-
|
10
|
-
class RepositoryQueryHandlerAdapter
|
11
|
-
def initialize(repo)
|
12
|
-
@repo = repo.respond_to?(:readonly) ? repo.readonly : repo
|
13
|
-
end
|
14
|
-
|
15
|
-
def call(action:, params: {}, **)
|
16
|
-
raise CannotHandleAction.new(self, action) unless @repo.respond_to?(action)
|
17
|
-
|
18
|
-
@repo.send(action, **params)
|
19
|
-
rescue RepositoryIsReadOnly
|
20
|
-
raise QueryCannotModifyState
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/realm/plugin.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/class'
|
4
|
-
require 'active_support/core_ext/string'
|
5
|
-
|
6
|
-
module Realm
|
7
|
-
class Plugin
|
8
|
-
class << self
|
9
|
-
def plugin_name(value = :not_provided)
|
10
|
-
@plugin_name = value.to_sym unless value == :not_provided
|
11
|
-
@plugin_name = name.split('::')[-2].underscore.to_sym unless defined?(@plugin_name)
|
12
|
-
@plugin_name
|
13
|
-
end
|
14
|
-
|
15
|
-
def setup(_config, _container)
|
16
|
-
raise NotImplementedError
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
data/lib/realm/query_handler.rb
DELETED
data/lib/realm/runtime.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/core_ext/module/delegation'
|
4
|
-
require 'active_support/core_ext/object/try'
|
5
|
-
require 'realm/context'
|
6
|
-
require 'realm/container'
|
7
|
-
require 'realm/dispatcher'
|
8
|
-
require 'realm/event_router'
|
9
|
-
require 'realm/multi_worker'
|
10
|
-
require 'realm/health_status'
|
11
|
-
require 'realm/runtime/session'
|
12
|
-
|
13
|
-
module Realm
|
14
|
-
class Runtime
|
15
|
-
delegate :query, :run, :run_as_job, :wait_for_jobs, to: :dispatcher
|
16
|
-
delegate :trigger, :add_listener, to: :event_router
|
17
|
-
delegate :[], to: :context
|
18
|
-
attr_reader :container
|
19
|
-
|
20
|
-
def initialize(container = Container.new)
|
21
|
-
@container = Container[container]
|
22
|
-
end
|
23
|
-
|
24
|
-
def context
|
25
|
-
@context ||= Context.new(@container)
|
26
|
-
end
|
27
|
-
|
28
|
-
def session(context = {})
|
29
|
-
context.blank? ? self : Session.new(self, context)
|
30
|
-
end
|
31
|
-
|
32
|
-
def worker(*args)
|
33
|
-
MultiWorker.new(event_router.try(:workers, *args) || [])
|
34
|
-
end
|
35
|
-
|
36
|
-
def health
|
37
|
-
component_statuses = container.each_with_object({}) do |(name, component), map|
|
38
|
-
map[name] = component.health if component.respond_to?(:health) && !component.is_a?(Runtime)
|
39
|
-
end
|
40
|
-
HealthStatus.combine(component_statuses)
|
41
|
-
end
|
42
|
-
|
43
|
-
# Get all active messaging queues. For maintenance purpose only.
|
44
|
-
# TODO: Introduce component container and allow to call those method directly on components instead of
|
45
|
-
# polluting runtime
|
46
|
-
# Example: engine.realm.components.find(type: Realm::EventRouter::SNSGateway).try(:active_queues)
|
47
|
-
def active_queues
|
48
|
-
event_router.try(:active_queues) || []
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def dispatcher
|
54
|
-
@dispatcher ||= container.create(Dispatcher, self)
|
55
|
-
end
|
56
|
-
|
57
|
-
def event_router
|
58
|
-
@container[EventRouter]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'realm/dispatcher'
|
4
|
-
|
5
|
-
module Realm
|
6
|
-
class Runtime
|
7
|
-
class Session
|
8
|
-
delegate :query, :run, :run_as_job, :wait_for_jobs, to: :dispatcher
|
9
|
-
delegate :add_listener, :trigger, :worker, to: :@runtime
|
10
|
-
delegate :[], to: :context
|
11
|
-
attr_reader :context
|
12
|
-
|
13
|
-
def initialize(runtime, context)
|
14
|
-
@runtime = runtime
|
15
|
-
@context = runtime.context.merge(context)
|
16
|
-
end
|
17
|
-
|
18
|
-
def session(context = {})
|
19
|
-
context.blank? ? self : self.class.new(self, context)
|
20
|
-
end
|
21
|
-
|
22
|
-
def container
|
23
|
-
@runtime.container
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def dispatcher
|
29
|
-
@dispatcher ||= container.create(Dispatcher, self)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|