lib/ledger_sync/domains/operation.rb in ledger_sync-domains-1.0.0.rc4 vs lib/ledger_sync/domains/operation.rb in ledger_sync-domains-1.0.0.rc6
- old
+ new
@@ -1,9 +1,18 @@
# frozen_string_literal: true
+unless Object.const_defined?('ActiveRecord')
+ # reopen AR module for non-rails apps
+ module ActiveRecord
+ module Base; end
+ end
+end
+
module LedgerSync
module Domains
+ class InternalOperationError < LedgerSync::Error::OperationError; end
+
class Operation
class OperationResult
module ResultTypeBase
attr_reader :meta
@@ -20,31 +29,21 @@
end
include LedgerSync::ResultBase
end
- module Mixin
+ module Mixin # rubocop:disable Metrics/ModuleLength
module ClassMethods
- def inferred_resource_class
- name = to_s.split('::')
- name.pop # remove serializer/operation class from name
- resource = name.pop.singularize # pluralized resource module name
+ @internal = false
- const_get((name + [resource]).join('::'))
+ def internal
+ @internal = true
end
- def inferred_serializer_class
- const_get("#{inferred_resource_class}Serializer")
+ def internal?
+ !!@internal
end
-
- def inferred_deserializer_class
- const_get("#{inferred_resource_class}Deserializer")
- end
-
- def inferred_validation_contract_class
- const_get('Contract')
- end
end
def self.included(base)
base.include SimplySerializable::Mixin
base.include Fingerprintable::Mixin
@@ -59,18 +58,26 @@
end
end
attr_reader :params, :result
- def initialize(serializer: nil, deserializer: nil, **params)
- @serializer = serializer
- @deserializer = deserializer
+ def initialize(domain:, **params)
+ @domain = domain
@params = params
@result = nil
end
def perform # rubocop:disable Metrics/MethodLength
+ unless allowed?
+ return failure(
+ LedgerSync::Domains::InternalOperationError.new(
+ operation: self,
+ message: 'Cross-domain operation execution is not allowed'
+ )
+ )
+ end
+
if performed?
return failure(
LedgerSync::Error::OperationError::PerformedOperationError.new(
operation: self
)
@@ -91,36 +98,51 @@
ensure
@performed = true
end
end
+ def allowed?
+ return true unless self.class.internal?
+
+ local_domain == @domain
+ end
+
def performed?
@performed == true
end
def serialize(resource:)
- serializer.serialize(resource: resource)
+ serializer_for(resource: resource).serialize(resource: resource)
end
- def deserializer
- @deserializer ||= deserializer_class.new
+ def serializer_for(resource:)
+ serializer_class_for(resource: resource).new
end
- def deserializer_class
- @deserializer_class ||= self.class.inferred_deserializer_class
+ def serializer_class_for(resource:)
+ Object.const_get(
+ [
+ serializer_module_for(resource: resource),
+ "#{domain}Serializer"
+ ].join('::')
+ )
end
- def serializer
- @serializer ||= serializer_class.new
+ def serializer_module_for(resource:)
+ (
+ resource.class.try(:serializer_module) || resource.class
+ ).to_s.pluralize
end
- def serializer_class
- @serializer_class ||= self.class.inferred_serializer_class
+ def domain
+ LedgerSync::Domains.domains.module_for(domain: @domain)
end
- def resource_class
- @resource_class ||= self.class.inferred_resource_class
+ def local_domain
+ LedgerSync::Domains.domains.domain_for(
+ base_module: self.class.to_s.split('::').first.constantize
+ )
end
# Results
def failure(error)
@@ -130,29 +152,46 @@
def failure?
result.failure?
end
def success(value, meta: nil)
- @result = OperationResult.Success(value, meta: meta)
+ @result = OperationResult.Success(deep_serialize(value), meta: meta)
end
+ def deep_serialize(value)
+ case value
+ when ActiveRecord::Base, LedgerSync::Resource
+ serialize(resource: value)
+ when Hash
+ value.transform_values { deep_serialize(_1) }
+ when Array
+ value.map { deep_serialize(_1) }
+ else
+ value
+ end
+ end
+
def success?
result.success?
end
def valid?
validate.success?
end
def validate
LedgerSync::Util::Validator.new(
- contract: validation_contract,
+ contract: validation_contract_class,
data: params
).validate
end
- def validation_contract
- @validation_contract ||= self.class.inferred_validation_contract_class
+ def validation_contract_class
+ @validation_contract_class ||= inferred_validation_contract_class
+ end
+
+ def inferred_validation_contract_class
+ self.class.const_get('Contract')
end
def errors
validate.validator.errors
end