table_sync 1.13.1 → 4.0.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 +4 -4
- data/.gitignore +0 -1
- data/.rubocop.yml +26 -1
- data/.travis.yml +6 -6
- data/CHANGELOG.md +74 -1
- data/Gemfile.lock +262 -0
- data/LICENSE.md +1 -1
- data/README.md +4 -1
- data/docs/message_protocol.md +24 -0
- data/docs/notifications.md +45 -0
- data/docs/publishing.md +147 -0
- data/docs/receiving.md +341 -0
- data/lib/table_sync.rb +23 -33
- data/lib/table_sync/errors.rb +60 -22
- data/lib/table_sync/instrument.rb +2 -2
- data/lib/table_sync/publishing.rb +11 -0
- data/lib/table_sync/{base_publisher.rb → publishing/base_publisher.rb} +1 -1
- data/lib/table_sync/{batch_publisher.rb → publishing/batch_publisher.rb} +12 -13
- data/lib/table_sync/{orm_adapter → publishing/orm_adapter}/active_record.rb +4 -8
- data/lib/table_sync/{orm_adapter → publishing/orm_adapter}/sequel.rb +10 -17
- data/lib/table_sync/{publisher.rb → publishing/publisher.rb} +4 -4
- data/lib/table_sync/receiving.rb +14 -0
- data/lib/table_sync/receiving/config.rb +218 -0
- data/lib/table_sync/receiving/config_decorator.rb +27 -0
- data/lib/table_sync/receiving/dsl.rb +28 -0
- data/lib/table_sync/receiving/handler.rb +131 -0
- data/lib/table_sync/{model → receiving/model}/active_record.rb +37 -23
- data/lib/table_sync/{model → receiving/model}/sequel.rb +13 -8
- data/lib/table_sync/utils.rb +9 -0
- data/lib/table_sync/utils/interface_checker.rb +97 -0
- data/lib/table_sync/utils/proc_array.rb +17 -0
- data/lib/table_sync/utils/proc_keywords_resolver.rb +46 -0
- data/lib/table_sync/version.rb +1 -1
- data/table_sync.gemspec +5 -4
- metadata +48 -30
- data/docs/synopsis.md +0 -318
- data/lib/table_sync/config.rb +0 -105
- data/lib/table_sync/config/callback_registry.rb +0 -53
- data/lib/table_sync/config_decorator.rb +0 -38
- data/lib/table_sync/dsl.rb +0 -25
- data/lib/table_sync/event_actions.rb +0 -96
- data/lib/table_sync/event_actions/data_wrapper.rb +0 -7
- data/lib/table_sync/event_actions/data_wrapper/base.rb +0 -23
- data/lib/table_sync/event_actions/data_wrapper/destroy.rb +0 -19
- data/lib/table_sync/event_actions/data_wrapper/update.rb +0 -21
- data/lib/table_sync/receiving_handler.rb +0 -76
data/lib/table_sync.rb
CHANGED
@@ -1,61 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "memery"
|
4
|
+
require "self_data"
|
4
5
|
require "rabbit_messaging"
|
5
6
|
require "rabbit/event_handler" # NOTE: from rabbit_messaging"
|
6
7
|
require "active_support/core_ext/object/blank"
|
7
8
|
require "active_support/core_ext/numeric/time"
|
8
9
|
|
9
10
|
module TableSync
|
10
|
-
require_relative "
|
11
|
-
require_relative "
|
12
|
-
require_relative "
|
13
|
-
require_relative "
|
14
|
-
require_relative "
|
15
|
-
require_relative "
|
16
|
-
require_relative "
|
17
|
-
require_relative "
|
18
|
-
require_relative "
|
19
|
-
require_relative "./table_sync/base_publisher"
|
20
|
-
require_relative "./table_sync/publisher"
|
21
|
-
require_relative "./table_sync/batch_publisher"
|
22
|
-
require_relative "./table_sync/orm_adapter/active_record"
|
23
|
-
require_relative "./table_sync/orm_adapter/sequel"
|
24
|
-
require_relative "./table_sync/model/active_record"
|
25
|
-
require_relative "./table_sync/model/sequel"
|
26
|
-
require_relative "./table_sync/instrument"
|
27
|
-
require_relative "./table_sync/instrument_adapter/active_support"
|
28
|
-
require_relative "./table_sync/naming_resolver/active_record"
|
29
|
-
require_relative "./table_sync/naming_resolver/sequel"
|
11
|
+
require_relative "table_sync/utils"
|
12
|
+
require_relative "table_sync/version"
|
13
|
+
require_relative "table_sync/errors"
|
14
|
+
require_relative "table_sync/instrument"
|
15
|
+
require_relative "table_sync/instrument_adapter/active_support"
|
16
|
+
require_relative "table_sync/naming_resolver/active_record"
|
17
|
+
require_relative "table_sync/naming_resolver/sequel"
|
18
|
+
require_relative "table_sync/receiving"
|
19
|
+
require_relative "table_sync/publishing"
|
30
20
|
|
31
21
|
class << self
|
32
|
-
include Memery
|
33
|
-
|
34
22
|
attr_accessor :publishing_job_class_callable
|
35
23
|
attr_accessor :batch_publishing_job_class_callable
|
36
24
|
attr_accessor :routing_key_callable
|
37
25
|
attr_accessor :exchange_name
|
38
26
|
attr_accessor :routing_metadata_callable
|
39
27
|
attr_accessor :notifier
|
28
|
+
attr_reader :orm
|
29
|
+
attr_reader :publishing_adapter
|
30
|
+
attr_reader :receiving_model
|
40
31
|
|
41
|
-
def sync(
|
42
|
-
|
32
|
+
def sync(klass, **opts)
|
33
|
+
publishing_adapter.setup_sync(klass, opts)
|
43
34
|
end
|
44
35
|
|
45
36
|
def orm=(val)
|
46
|
-
|
47
|
-
@orm = val
|
48
|
-
end
|
49
|
-
|
50
|
-
memoize def orm
|
51
|
-
case @orm
|
37
|
+
case val
|
52
38
|
when :active_record
|
53
|
-
ORMAdapter::ActiveRecord
|
39
|
+
@publishing_adapter = Publishing::ORMAdapter::ActiveRecord
|
40
|
+
@receiving_model = Receiving::Model::ActiveRecord
|
54
41
|
when :sequel
|
55
|
-
ORMAdapter::Sequel
|
42
|
+
@publishing_adapter = Publishing::ORMAdapter::Sequel
|
43
|
+
@receiving_model = Receiving::Model::Sequel
|
56
44
|
else
|
57
|
-
raise
|
45
|
+
raise ORMNotSupported.new(val.inspect)
|
58
46
|
end
|
47
|
+
|
48
|
+
@orm = val
|
59
49
|
end
|
60
50
|
end
|
61
51
|
end
|
data/lib/table_sync/errors.rb
CHANGED
@@ -4,38 +4,76 @@ module TableSync
|
|
4
4
|
Error = Class.new(StandardError)
|
5
5
|
|
6
6
|
class UpsertError < Error
|
7
|
-
def initialize(data:, target_keys:,
|
8
|
-
super
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
7
|
+
def initialize(data:, target_keys:, result:)
|
8
|
+
super("data: #{data.inspect}, target_keys: #{target_keys.inspect}, result: #{result.inspect}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class DestroyError < Error
|
13
|
+
def initialize(data:, target_keys:, result:)
|
14
|
+
super("data: #{data.inspect}, target_keys: #{target_keys.inspect}, result: #{result.inspect}")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class DataError < Error
|
19
|
+
def initialize(data, target_keys, description)
|
20
|
+
super(<<~MSG.squish)
|
21
|
+
#{description}
|
22
|
+
target_keys: #{target_keys}
|
23
|
+
data: #{data}
|
15
24
|
MSG
|
16
25
|
end
|
17
26
|
end
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
|
28
|
+
# @api public
|
29
|
+
# @since 2.2.0
|
30
|
+
PluginError = Class.new(Error)
|
31
|
+
|
32
|
+
# @api public
|
33
|
+
# @since 2.2.0
|
34
|
+
class UnregisteredPluginError < PluginError
|
35
|
+
# @param plugin_name [Any]
|
36
|
+
def initialize(plugin_name)
|
37
|
+
super("#{plugin_name} plugin is not registered")
|
22
38
|
end
|
23
39
|
end
|
24
40
|
|
25
|
-
|
26
|
-
|
27
|
-
|
41
|
+
# @api public
|
42
|
+
# @since 2.2.0
|
43
|
+
class AlreadyRegisteredPluginError < PluginError
|
44
|
+
# @param plugin_name [Any]
|
45
|
+
def initialize(plugin_name)
|
46
|
+
super("#{plugin_name} plugin already exists")
|
28
47
|
end
|
29
48
|
end
|
30
49
|
|
31
|
-
class
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
50
|
+
class InterfaceError < Error
|
51
|
+
def initialize(object, method_name, parameters, description)
|
52
|
+
parameters = parameters.map do |parameter|
|
53
|
+
type, name = parameter
|
54
|
+
|
55
|
+
case type
|
56
|
+
when :req
|
57
|
+
name.to_s
|
58
|
+
when :keyreq
|
59
|
+
"#{name}:"
|
60
|
+
when :block
|
61
|
+
"&#{name}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
signature = "#{method_name}(#{parameters.join(", ")})"
|
66
|
+
|
67
|
+
super("#{object} has to implement method `#{signature}`\n#{description}")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
UndefinedEvent = Class.new(Error)
|
72
|
+
ORMNotSupported = Class.new(Error)
|
73
|
+
|
74
|
+
class WrongOptionValue < Error
|
75
|
+
def initialize(model, option, value)
|
76
|
+
super("TableSync config for #{model.inspect} can't contain #{value.inspect} as #{option}")
|
39
77
|
end
|
40
78
|
end
|
41
79
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSync
|
4
|
+
module Publishing
|
5
|
+
require_relative "publishing/base_publisher"
|
6
|
+
require_relative "publishing/publisher"
|
7
|
+
require_relative "publishing/batch_publisher"
|
8
|
+
require_relative "publishing/orm_adapter/active_record"
|
9
|
+
require_relative "publishing/orm_adapter/sequel"
|
10
|
+
end
|
11
|
+
end
|
@@ -1,14 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class TableSync::BatchPublisher < TableSync::BasePublisher
|
3
|
+
class TableSync::Publishing::BatchPublisher < TableSync::Publishing::BasePublisher
|
4
4
|
def initialize(object_class, original_attributes_array, **options)
|
5
|
-
@object_class = object_class.constantize
|
6
5
|
@original_attributes_array = original_attributes_array.map do |hash|
|
7
6
|
filter_safe_for_serialization(hash.deep_symbolize_keys)
|
8
7
|
end
|
9
|
-
|
10
|
-
@
|
8
|
+
|
9
|
+
@object_class = object_class.constantize
|
10
|
+
@confirm = options[:confirm] || true
|
11
|
+
@routing_key = options[:routing_key] || resolve_routing_key
|
11
12
|
@push_original_attributes = options[:push_original_attributes] || false
|
13
|
+
@headers = options[:headers]
|
14
|
+
@event = options[:event] || :update
|
12
15
|
end
|
13
16
|
|
14
17
|
def publish
|
@@ -19,7 +22,7 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
|
|
19
22
|
return unless need_publish?
|
20
23
|
Rabbit.publish(params)
|
21
24
|
|
22
|
-
model_naming = TableSync.
|
25
|
+
model_naming = TableSync.publishing_adapter.model_naming(object_class)
|
23
26
|
TableSync::Instrument.notify table: model_naming.table, schema: model_naming.schema,
|
24
27
|
event: event,
|
25
28
|
count: publishing_data[:attributes].size, direction: :publish
|
@@ -27,7 +30,7 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
|
|
27
30
|
|
28
31
|
private
|
29
32
|
|
30
|
-
attr_reader :original_attributes_array, :routing_key
|
33
|
+
attr_reader :original_attributes_array, :routing_key, :headers, :event
|
31
34
|
|
32
35
|
def push_original_attributes?
|
33
36
|
@push_original_attributes
|
@@ -38,7 +41,7 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
|
|
38
41
|
end
|
39
42
|
|
40
43
|
memoize def objects
|
41
|
-
needles.map { |needle| TableSync.
|
44
|
+
needles.map { |needle| TableSync.publishing_adapter.find(object_class, needle) }.compact
|
42
45
|
end
|
43
46
|
|
44
47
|
def job_callable
|
@@ -64,7 +67,7 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
|
|
64
67
|
def params
|
65
68
|
{
|
66
69
|
**super,
|
67
|
-
headers:
|
70
|
+
headers: headers,
|
68
71
|
}
|
69
72
|
end
|
70
73
|
|
@@ -80,10 +83,6 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
|
|
80
83
|
}
|
81
84
|
end
|
82
85
|
|
83
|
-
def event
|
84
|
-
:update
|
85
|
-
end
|
86
|
-
|
87
86
|
def attributes_for_sync
|
88
87
|
return original_attributes_array if push_original_attributes?
|
89
88
|
|
@@ -91,7 +90,7 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
|
|
91
90
|
if attributes_for_sync_defined?
|
92
91
|
object.attributes_for_sync
|
93
92
|
else
|
94
|
-
TableSync.
|
93
|
+
TableSync.publishing_adapter.attributes(object)
|
95
94
|
end
|
96
95
|
end
|
97
96
|
end
|
@@ -1,13 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module TableSync::ORMAdapter
|
3
|
+
module TableSync::Publishing::ORMAdapter
|
4
4
|
module ActiveRecord
|
5
5
|
module_function
|
6
6
|
|
7
|
-
def model
|
8
|
-
::TableSync::Model::ActiveRecord
|
9
|
-
end
|
10
|
-
|
11
7
|
def model_naming(object)
|
12
8
|
::TableSync::NamingResolver::ActiveRecord.new(table_name: object.table_name)
|
13
9
|
end
|
@@ -20,14 +16,14 @@ module TableSync::ORMAdapter
|
|
20
16
|
object.attributes
|
21
17
|
end
|
22
18
|
|
23
|
-
def setup_sync(klass,
|
19
|
+
def setup_sync(klass, opts)
|
24
20
|
debounce_time = opts.delete(:debounce_time)
|
25
21
|
|
26
22
|
klass.instance_exec do
|
27
23
|
{ create: :created, update: :updated, destroy: :destroyed }.each do |event, state|
|
28
24
|
after_commit(on: event, **opts) do
|
29
|
-
TableSync::Publisher.new(self.class.name, attributes,
|
30
|
-
|
25
|
+
TableSync::Publishing::Publisher.new(self.class.name, attributes,
|
26
|
+
state: state, debounce_time: debounce_time).publish
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
@@ -1,13 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module TableSync::ORMAdapter
|
3
|
+
module TableSync::Publishing::ORMAdapter
|
4
4
|
module Sequel
|
5
5
|
module_function
|
6
6
|
|
7
|
-
def model
|
8
|
-
::TableSync::Model::Sequel
|
9
|
-
end
|
10
|
-
|
11
7
|
def model_naming(object)
|
12
8
|
::TableSync::NamingResolver::Sequel.new(table_name: object.table_name, db: object.db)
|
13
9
|
end
|
@@ -20,7 +16,7 @@ module TableSync::ORMAdapter
|
|
20
16
|
object.values
|
21
17
|
end
|
22
18
|
|
23
|
-
def setup_sync(klass,
|
19
|
+
def setup_sync(klass, opts)
|
24
20
|
if_predicate = to_predicate(opts.delete(:if), true)
|
25
21
|
unless_predicate = to_predicate(opts.delete(:unless), false)
|
26
22
|
debounce_time = opts.delete(:debounce_time)
|
@@ -40,24 +36,21 @@ module TableSync::ORMAdapter
|
|
40
36
|
end
|
41
37
|
|
42
38
|
def register_callbacks(klass, if_predicate, unless_predicate, debounce_time)
|
43
|
-
{ create: :created, update: :updated }.each do |event, state|
|
39
|
+
{ create: :created, update: :updated, destroy: :destroyed }.each do |event, state|
|
44
40
|
klass.send(:define_method, :"after_#{event}") do
|
45
41
|
if instance_eval(&if_predicate) && !instance_eval(&unless_predicate)
|
46
42
|
db.after_commit do
|
47
|
-
TableSync::Publisher.new(
|
48
|
-
|
43
|
+
TableSync::Publishing::Publisher.new(
|
44
|
+
self.class.name,
|
45
|
+
values,
|
46
|
+
state: state,
|
47
|
+
debounce_time: debounce_time,
|
48
|
+
).publish
|
49
49
|
end
|
50
50
|
end
|
51
|
-
super()
|
52
|
-
end
|
53
|
-
end
|
54
51
|
|
55
|
-
|
56
|
-
# publish anyway
|
57
|
-
db.after_commit do
|
58
|
-
TableSync::Publisher.new(self.class.name, values, state: :destroyed).publish
|
52
|
+
super()
|
59
53
|
end
|
60
|
-
super()
|
61
54
|
end
|
62
55
|
end
|
63
56
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class TableSync::Publisher < TableSync::BasePublisher
|
3
|
+
class TableSync::Publishing::Publisher < TableSync::Publishing::BasePublisher
|
4
4
|
DEBOUNCE_TIME = 1.minute
|
5
5
|
|
6
6
|
# 'original_attributes' are not published, they are used to resolve the routing key
|
@@ -34,7 +34,7 @@ class TableSync::Publisher < TableSync::BasePublisher
|
|
34
34
|
return if !object && !destroyed?
|
35
35
|
|
36
36
|
Rabbit.publish(params)
|
37
|
-
model_naming = TableSync.
|
37
|
+
model_naming = TableSync.publishing_adapter.model_naming(object_class)
|
38
38
|
TableSync::Instrument.notify table: model_naming.table, schema: model_naming.schema,
|
39
39
|
event: event, direction: :publish
|
40
40
|
end
|
@@ -95,12 +95,12 @@ class TableSync::Publisher < TableSync::BasePublisher
|
|
95
95
|
elsif attributes_for_sync_defined?
|
96
96
|
object.attributes_for_sync
|
97
97
|
else
|
98
|
-
TableSync.
|
98
|
+
TableSync.publishing_adapter.attributes(object)
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
102
|
memoize def object
|
103
|
-
TableSync.
|
103
|
+
TableSync.publishing_adapter.find(object_class, needle)
|
104
104
|
end
|
105
105
|
|
106
106
|
def event
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSync
|
4
|
+
module Receiving
|
5
|
+
AVAILABLE_EVENTS = [:update, :destroy].freeze
|
6
|
+
|
7
|
+
require_relative "receiving/config"
|
8
|
+
require_relative "receiving/config_decorator"
|
9
|
+
require_relative "receiving/dsl"
|
10
|
+
require_relative "receiving/handler"
|
11
|
+
require_relative "receiving/model/active_record"
|
12
|
+
require_relative "receiving/model/sequel"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TableSync::Receiving
|
4
|
+
class Config
|
5
|
+
attr_reader :model, :events
|
6
|
+
|
7
|
+
def initialize(model:, events: AVAILABLE_EVENTS)
|
8
|
+
@model = model
|
9
|
+
|
10
|
+
@events = [events].flatten.map(&:to_sym)
|
11
|
+
|
12
|
+
unless @events.all? { |event| AVAILABLE_EVENTS.include?(event) }
|
13
|
+
raise TableSync::UndefinedEvent.new(events)
|
14
|
+
end
|
15
|
+
|
16
|
+
self.class.default_values_for_options.each do |ivar, default_value_generator|
|
17
|
+
instance_variable_set(ivar, default_value_generator.call(self))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_reader :default_values_for_options
|
23
|
+
|
24
|
+
# In a configs this options are requested as they are
|
25
|
+
# config.option - get value
|
26
|
+
# config.option(args) - set static value
|
27
|
+
# config.option { ... } - set proc as value
|
28
|
+
#
|
29
|
+
# In `Receiving::Handler` or `Receiving::EventActions` this options are requested
|
30
|
+
# through `Receiving::ConfigDecorator#method_missing` which always executes `config.option`
|
31
|
+
|
32
|
+
def add_option(name, value_setter_wrapper:, value_as_proc_setter_wrapper:, default:)
|
33
|
+
ivar = "@#{name}".to_sym
|
34
|
+
|
35
|
+
@default_values_for_options ||= {}
|
36
|
+
@default_values_for_options[ivar] = default
|
37
|
+
|
38
|
+
define_method(name) do |*value, &value_as_proc|
|
39
|
+
return instance_variable_get(ivar) if value.empty? && value_as_proc.nil?
|
40
|
+
|
41
|
+
value = value.first if value.size == 1
|
42
|
+
|
43
|
+
if value_as_proc.present?
|
44
|
+
new_value = TableSync::Utils.proc_keywords_resolver(&value_as_proc)
|
45
|
+
setter_wrapper = value_as_proc_setter_wrapper
|
46
|
+
else
|
47
|
+
new_value = value
|
48
|
+
setter_wrapper = value_setter_wrapper
|
49
|
+
end
|
50
|
+
|
51
|
+
old_value = instance_variable_get(ivar)
|
52
|
+
result_value = instance_exec(name, new_value, old_value, &setter_wrapper)
|
53
|
+
instance_variable_set(ivar, result_value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def allow_event?(name)
|
59
|
+
events.include?(name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Helpers:
|
65
|
+
|
66
|
+
column_key = proc do |option_name, new_value|
|
67
|
+
unless model.columns.include?(new_value)
|
68
|
+
raise TableSync::WrongOptionValue.new(model, option_name, new_value)
|
69
|
+
end
|
70
|
+
new_value
|
71
|
+
end
|
72
|
+
|
73
|
+
exactly_symbol = proc do |option_name, new_value|
|
74
|
+
unless new_value.is_a? Symbol
|
75
|
+
raise TableSync::WrongOptionValue.new(model, option_name, new_value)
|
76
|
+
end
|
77
|
+
new_value
|
78
|
+
end
|
79
|
+
|
80
|
+
to_array = proc do |block|
|
81
|
+
proc do |option_name, new_value|
|
82
|
+
new_value = [new_value].flatten
|
83
|
+
new_value.map { |value| instance_exec(option_name, value, &block) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
exactly_not_array = proc do |block|
|
88
|
+
proc do |option_name, new_value|
|
89
|
+
if new_value.is_a? Array
|
90
|
+
raise TableSync::WrongOptionValue.new(model, option_name, new_value)
|
91
|
+
end
|
92
|
+
instance_exec(option_name, new_value, &block)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
exactly_hash = proc do |block_for_keys, block_for_values|
|
97
|
+
proc do |option_name, new_value|
|
98
|
+
unless new_value.is_a? Hash
|
99
|
+
raise TableSync::WrongOptionValue.new(model, option_name, new_value)
|
100
|
+
end
|
101
|
+
|
102
|
+
new_value.to_a.map do |key, value|
|
103
|
+
[
|
104
|
+
instance_exec("#{option_name} keys", key, &block_for_keys),
|
105
|
+
instance_exec("#{option_name} values", value, &block_for_values),
|
106
|
+
]
|
107
|
+
end.to_h
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
any_value = proc do |_option_name, new_value|
|
112
|
+
new_value
|
113
|
+
end
|
114
|
+
|
115
|
+
raise_error = proc do |option_name, new_value|
|
116
|
+
raise TableSync::WrongOptionValue.new(model, option_name, new_value)
|
117
|
+
end
|
118
|
+
|
119
|
+
exactly_boolean = proc do |option_name, new_value|
|
120
|
+
unless new_value.is_a?(TrueClass) || new_value.is_a?(FalseClass)
|
121
|
+
raise TableSync::WrongOptionValue.new(model, option_name, new_value)
|
122
|
+
end
|
123
|
+
new_value
|
124
|
+
end
|
125
|
+
|
126
|
+
allow_false = proc do |block|
|
127
|
+
proc do |option_name, new_value|
|
128
|
+
next false if new_value.is_a? FalseClass
|
129
|
+
instance_exec(option_name, new_value, &block)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
proc_result = proc do |block|
|
134
|
+
proc do |option_name, new_value|
|
135
|
+
proc do |*args, &b|
|
136
|
+
result = new_value.call(*args, &b)
|
137
|
+
instance_exec(option_name, result, &block)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
accumulate_procs = proc do |block|
|
143
|
+
proc do |option_name, new_value, old_value|
|
144
|
+
old_value.push(&instance_exec(option_name, new_value, &block))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Options:
|
149
|
+
|
150
|
+
# rubocop:disable Layout/ArgumentAlignment
|
151
|
+
|
152
|
+
TableSync::Receiving::Config.add_option :only,
|
153
|
+
value_setter_wrapper: to_array[column_key],
|
154
|
+
value_as_proc_setter_wrapper: proc_result[to_array[column_key]],
|
155
|
+
default: proc { |config| config.model.columns }
|
156
|
+
|
157
|
+
TableSync::Receiving::Config.add_option :target_keys,
|
158
|
+
value_setter_wrapper: to_array[column_key],
|
159
|
+
value_as_proc_setter_wrapper: proc_result[to_array[column_key]],
|
160
|
+
default: proc { |config| Array.wrap(config.model.primary_keys) }
|
161
|
+
|
162
|
+
TableSync::Receiving::Config.add_option :rest_key,
|
163
|
+
value_setter_wrapper: exactly_not_array[allow_false[column_key]],
|
164
|
+
value_as_proc_setter_wrapper: proc_result[exactly_not_array[allow_false[column_key]]],
|
165
|
+
default: proc { :rest }
|
166
|
+
|
167
|
+
TableSync::Receiving::Config.add_option :version_key,
|
168
|
+
value_setter_wrapper: exactly_not_array[column_key],
|
169
|
+
value_as_proc_setter_wrapper: proc_result[exactly_not_array[column_key]],
|
170
|
+
default: proc { :version }
|
171
|
+
|
172
|
+
TableSync::Receiving::Config.add_option :except,
|
173
|
+
value_setter_wrapper: to_array[exactly_symbol],
|
174
|
+
value_as_proc_setter_wrapper: proc_result[to_array[exactly_symbol]],
|
175
|
+
default: proc { [] }
|
176
|
+
|
177
|
+
TableSync::Receiving::Config.add_option :mapping_overrides,
|
178
|
+
value_setter_wrapper: exactly_hash[exactly_symbol, exactly_symbol],
|
179
|
+
value_as_proc_setter_wrapper: proc_result[exactly_hash[exactly_symbol, exactly_symbol]],
|
180
|
+
default: proc { {} }
|
181
|
+
|
182
|
+
TableSync::Receiving::Config.add_option :additional_data,
|
183
|
+
value_setter_wrapper: exactly_hash[exactly_symbol, any_value],
|
184
|
+
value_as_proc_setter_wrapper: proc_result[exactly_hash[exactly_symbol, any_value]],
|
185
|
+
default: proc { {} }
|
186
|
+
|
187
|
+
TableSync::Receiving::Config.add_option :default_values,
|
188
|
+
value_setter_wrapper: exactly_hash[exactly_symbol, any_value],
|
189
|
+
value_as_proc_setter_wrapper: proc_result[exactly_hash[exactly_symbol, any_value]],
|
190
|
+
default: proc { {} }
|
191
|
+
|
192
|
+
TableSync::Receiving::Config.add_option :skip,
|
193
|
+
value_setter_wrapper: exactly_boolean,
|
194
|
+
value_as_proc_setter_wrapper: proc_result[exactly_boolean],
|
195
|
+
default: proc { false }
|
196
|
+
|
197
|
+
TableSync::Receiving::Config.add_option :wrap_receiving,
|
198
|
+
value_setter_wrapper: raise_error,
|
199
|
+
value_as_proc_setter_wrapper: any_value,
|
200
|
+
default: proc { proc { |&block| block.call } }
|
201
|
+
|
202
|
+
%i[
|
203
|
+
before_update
|
204
|
+
after_commit_on_update
|
205
|
+
before_destroy
|
206
|
+
after_commit_on_destroy
|
207
|
+
].each do |option|
|
208
|
+
TableSync::Receiving::Config.add_option option,
|
209
|
+
value_setter_wrapper: raise_error,
|
210
|
+
value_as_proc_setter_wrapper: accumulate_procs[any_value],
|
211
|
+
default: (proc do |_config|
|
212
|
+
TableSync::Utils::ProcArray.new do |array, args, &block|
|
213
|
+
array.map { |pr| pr.call(*args, &block) }
|
214
|
+
end
|
215
|
+
end)
|
216
|
+
end
|
217
|
+
|
218
|
+
# rubocop:enable Layout/ArgumentAlignment
|