table_sync 5.1.0 → 6.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/CHANGELOG.md +42 -0
- data/Gemfile.lock +3 -3
- data/README.md +3 -0
- data/docs/publishing/configuration.md +143 -0
- data/docs/publishing/manual.md +155 -0
- data/docs/publishing/publishers.md +162 -0
- data/docs/publishing.md +35 -105
- data/lib/table_sync/errors.rb +31 -22
- data/lib/table_sync/event.rb +35 -0
- data/lib/table_sync/orm_adapter/active_record.rb +25 -0
- data/lib/table_sync/orm_adapter/base.rb +92 -0
- data/lib/table_sync/orm_adapter/sequel.rb +29 -0
- data/lib/table_sync/publishing/batch.rb +53 -0
- data/lib/table_sync/publishing/data/objects.rb +50 -0
- data/lib/table_sync/publishing/data/raw.rb +27 -0
- data/lib/table_sync/publishing/helpers/attributes.rb +63 -0
- data/lib/table_sync/publishing/helpers/debounce.rb +134 -0
- data/lib/table_sync/publishing/helpers/objects.rb +39 -0
- data/lib/table_sync/publishing/message/base.rb +73 -0
- data/lib/table_sync/publishing/message/batch.rb +14 -0
- data/lib/table_sync/publishing/message/raw.rb +54 -0
- data/lib/table_sync/publishing/message/single.rb +13 -0
- data/lib/table_sync/publishing/params/base.rb +66 -0
- data/lib/table_sync/publishing/params/batch.rb +23 -0
- data/lib/table_sync/publishing/params/raw.rb +7 -0
- data/lib/table_sync/publishing/params/single.rb +31 -0
- data/lib/table_sync/publishing/raw.rb +21 -0
- data/lib/table_sync/publishing/single.rb +65 -0
- data/lib/table_sync/publishing.rb +20 -5
- data/lib/table_sync/receiving/config.rb +6 -4
- data/lib/table_sync/receiving/handler.rb +10 -6
- data/lib/table_sync/receiving.rb +0 -2
- data/lib/table_sync/setup/active_record.rb +22 -0
- data/lib/table_sync/setup/base.rb +67 -0
- data/lib/table_sync/setup/sequel.rb +26 -0
- data/lib/table_sync/version.rb +1 -1
- data/lib/table_sync.rb +31 -8
- metadata +28 -7
- data/lib/table_sync/publishing/base_publisher.rb +0 -110
- data/lib/table_sync/publishing/batch_publisher.rb +0 -109
- data/lib/table_sync/publishing/orm_adapter/active_record.rb +0 -32
- data/lib/table_sync/publishing/orm_adapter/sequel.rb +0 -57
- data/lib/table_sync/publishing/publisher.rb +0 -129
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen-string_literal: true
|
2
|
+
|
3
|
+
module TableSync::Setup
|
4
|
+
class Base
|
5
|
+
include Tainbox
|
6
|
+
|
7
|
+
EVENTS = %i[create update destroy].freeze
|
8
|
+
INVALID_EVENT = Class.new(StandardError)
|
9
|
+
INVALID_CONDITION = Class.new(StandardError)
|
10
|
+
|
11
|
+
attribute :object_class
|
12
|
+
attribute :debounce_time
|
13
|
+
attribute :on
|
14
|
+
attribute :if_condition
|
15
|
+
attribute :unless_condition
|
16
|
+
|
17
|
+
def initialize(attrs)
|
18
|
+
super(attrs)
|
19
|
+
|
20
|
+
self.on = Array.wrap(on).map(&:to_sym)
|
21
|
+
|
22
|
+
self.if_condition ||= proc { true }
|
23
|
+
self.unless_condition ||= proc { false }
|
24
|
+
|
25
|
+
raise INVALID_EVENTS unless valid_events?
|
26
|
+
raise INVALID_CONDITION unless valid_conditions?
|
27
|
+
end
|
28
|
+
|
29
|
+
def register_callbacks
|
30
|
+
applicable_events.each { |event| define_after_commit(event) }
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# VALIDATION
|
36
|
+
|
37
|
+
def valid_events?
|
38
|
+
on.all? { |event| event.in?(EVENTS) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def valid_conditions?
|
42
|
+
if_condition.is_a?(Proc) && unless_condition.is_a?(Proc)
|
43
|
+
end
|
44
|
+
|
45
|
+
# EVENTS
|
46
|
+
|
47
|
+
def applicable_events
|
48
|
+
on.presence || EVENTS
|
49
|
+
end
|
50
|
+
|
51
|
+
# CREATING HOOKS
|
52
|
+
|
53
|
+
# :nocov:
|
54
|
+
def define_after_commit(event)
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
# :nocov:
|
58
|
+
|
59
|
+
def options_exposed_for_block
|
60
|
+
{
|
61
|
+
if: if_condition,
|
62
|
+
unless: unless_condition,
|
63
|
+
debounce_time: debounce_time,
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen-string_literal: true
|
2
|
+
|
3
|
+
module TableSync::Setup
|
4
|
+
class Sequel < Base
|
5
|
+
private
|
6
|
+
|
7
|
+
def define_after_commit(event)
|
8
|
+
options = options_exposed_for_block
|
9
|
+
|
10
|
+
object_class.define_method("after_#{event}".to_sym) do
|
11
|
+
if instance_eval(&options[:if]) && !instance_eval(&options[:unless])
|
12
|
+
db.after_commit do
|
13
|
+
TableSync::Publishing::Single.new(
|
14
|
+
object_class: self.class.name,
|
15
|
+
original_attributes: values,
|
16
|
+
event: event,
|
17
|
+
debounce_time: options[:debounce_time],
|
18
|
+
).publish_later
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
super()
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/table_sync/version.rb
CHANGED
data/lib/table_sync.rb
CHANGED
@@ -8,39 +8,62 @@ require "active_support/core_ext/object/blank"
|
|
8
8
|
require "active_support/core_ext/numeric/time"
|
9
9
|
|
10
10
|
module TableSync
|
11
|
+
require_relative "table_sync/event"
|
11
12
|
require_relative "table_sync/utils"
|
12
13
|
require_relative "table_sync/version"
|
13
14
|
require_relative "table_sync/errors"
|
15
|
+
|
14
16
|
require_relative "table_sync/instrument"
|
15
17
|
require_relative "table_sync/instrument_adapter/active_support"
|
18
|
+
|
16
19
|
require_relative "table_sync/naming_resolver/active_record"
|
17
20
|
require_relative "table_sync/naming_resolver/sequel"
|
21
|
+
|
22
|
+
require_relative "table_sync/orm_adapter/base"
|
23
|
+
require_relative "table_sync/orm_adapter/active_record"
|
24
|
+
require_relative "table_sync/orm_adapter/sequel"
|
25
|
+
|
18
26
|
require_relative "table_sync/receiving"
|
19
27
|
require_relative "table_sync/publishing"
|
20
28
|
|
29
|
+
require_relative "table_sync/setup/base"
|
30
|
+
require_relative "table_sync/setup/active_record"
|
31
|
+
require_relative "table_sync/setup/sequel"
|
32
|
+
|
21
33
|
class << self
|
22
|
-
attr_accessor :
|
34
|
+
attr_accessor :raise_on_empty_message
|
35
|
+
attr_accessor :single_publishing_job_class_callable
|
23
36
|
attr_accessor :batch_publishing_job_class_callable
|
24
37
|
attr_accessor :routing_key_callable
|
25
38
|
attr_accessor :exchange_name
|
26
|
-
attr_accessor :
|
39
|
+
attr_accessor :headers_callable
|
27
40
|
attr_accessor :notifier
|
41
|
+
|
28
42
|
attr_reader :orm
|
29
43
|
attr_reader :publishing_adapter
|
30
44
|
attr_reader :receiving_model
|
45
|
+
attr_reader :setup
|
31
46
|
|
32
|
-
def sync(
|
33
|
-
|
47
|
+
def sync(object_class, **options)
|
48
|
+
setup.new(
|
49
|
+
object_class: object_class,
|
50
|
+
on: options[:on],
|
51
|
+
if_condition: options[:if],
|
52
|
+
unless_condition: options[:unless],
|
53
|
+
debounce_time: options[:debounce_time],
|
54
|
+
).register_callbacks
|
34
55
|
end
|
35
56
|
|
36
57
|
def orm=(val)
|
37
58
|
case val
|
38
59
|
when :active_record
|
39
|
-
@publishing_adapter =
|
40
|
-
@receiving_model
|
60
|
+
@publishing_adapter = TableSync::ORMAdapter::ActiveRecord
|
61
|
+
@receiving_model = Receiving::Model::ActiveRecord
|
62
|
+
@setup = TableSync::Setup::ActiveRecord
|
41
63
|
when :sequel
|
42
|
-
@publishing_adapter =
|
43
|
-
@receiving_model
|
64
|
+
@publishing_adapter = TableSync::ORMAdapter::Sequel
|
65
|
+
@receiving_model = Receiving::Model::Sequel
|
66
|
+
@setup = TableSync::Setup::Sequel
|
44
67
|
else
|
45
68
|
raise ORMNotSupported.new(val.inspect)
|
46
69
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: table_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '6.0'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Umbrellio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: memery
|
@@ -271,19 +271,37 @@ files:
|
|
271
271
|
- docs/message_protocol.md
|
272
272
|
- docs/notifications.md
|
273
273
|
- docs/publishing.md
|
274
|
+
- docs/publishing/configuration.md
|
275
|
+
- docs/publishing/manual.md
|
276
|
+
- docs/publishing/publishers.md
|
274
277
|
- docs/receiving.md
|
275
278
|
- lib/table_sync.rb
|
276
279
|
- lib/table_sync/errors.rb
|
280
|
+
- lib/table_sync/event.rb
|
277
281
|
- lib/table_sync/instrument.rb
|
278
282
|
- lib/table_sync/instrument_adapter/active_support.rb
|
279
283
|
- lib/table_sync/naming_resolver/active_record.rb
|
280
284
|
- lib/table_sync/naming_resolver/sequel.rb
|
285
|
+
- lib/table_sync/orm_adapter/active_record.rb
|
286
|
+
- lib/table_sync/orm_adapter/base.rb
|
287
|
+
- lib/table_sync/orm_adapter/sequel.rb
|
281
288
|
- lib/table_sync/publishing.rb
|
282
|
-
- lib/table_sync/publishing/
|
283
|
-
- lib/table_sync/publishing/
|
284
|
-
- lib/table_sync/publishing/
|
285
|
-
- lib/table_sync/publishing/
|
286
|
-
- lib/table_sync/publishing/
|
289
|
+
- lib/table_sync/publishing/batch.rb
|
290
|
+
- lib/table_sync/publishing/data/objects.rb
|
291
|
+
- lib/table_sync/publishing/data/raw.rb
|
292
|
+
- lib/table_sync/publishing/helpers/attributes.rb
|
293
|
+
- lib/table_sync/publishing/helpers/debounce.rb
|
294
|
+
- lib/table_sync/publishing/helpers/objects.rb
|
295
|
+
- lib/table_sync/publishing/message/base.rb
|
296
|
+
- lib/table_sync/publishing/message/batch.rb
|
297
|
+
- lib/table_sync/publishing/message/raw.rb
|
298
|
+
- lib/table_sync/publishing/message/single.rb
|
299
|
+
- lib/table_sync/publishing/params/base.rb
|
300
|
+
- lib/table_sync/publishing/params/batch.rb
|
301
|
+
- lib/table_sync/publishing/params/raw.rb
|
302
|
+
- lib/table_sync/publishing/params/single.rb
|
303
|
+
- lib/table_sync/publishing/raw.rb
|
304
|
+
- lib/table_sync/publishing/single.rb
|
287
305
|
- lib/table_sync/receiving.rb
|
288
306
|
- lib/table_sync/receiving/config.rb
|
289
307
|
- lib/table_sync/receiving/config_decorator.rb
|
@@ -291,6 +309,9 @@ files:
|
|
291
309
|
- lib/table_sync/receiving/handler.rb
|
292
310
|
- lib/table_sync/receiving/model/active_record.rb
|
293
311
|
- lib/table_sync/receiving/model/sequel.rb
|
312
|
+
- lib/table_sync/setup/active_record.rb
|
313
|
+
- lib/table_sync/setup/base.rb
|
314
|
+
- lib/table_sync/setup/sequel.rb
|
294
315
|
- lib/table_sync/utils.rb
|
295
316
|
- lib/table_sync/utils/interface_checker.rb
|
296
317
|
- lib/table_sync/utils/proc_array.rb
|
@@ -1,110 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class TableSync::Publishing::BasePublisher
|
4
|
-
include Memery
|
5
|
-
|
6
|
-
BASE_SAFE_JSON_TYPES = [NilClass, String, TrueClass, FalseClass, Numeric, Symbol].freeze
|
7
|
-
NOT_MAPPED = Object.new
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
attr_accessor :object_class
|
12
|
-
|
13
|
-
# @!method job_callable
|
14
|
-
# @!method job_callable_error_message
|
15
|
-
# @!method attrs_for_callables
|
16
|
-
# @!method attrs_for_routing_key
|
17
|
-
# @!method attrs_for_metadata
|
18
|
-
# @!method attributes_for_sync
|
19
|
-
|
20
|
-
memoize def current_time
|
21
|
-
Time.current
|
22
|
-
end
|
23
|
-
|
24
|
-
memoize def primary_keys
|
25
|
-
Array(object_class.primary_key).map(&:to_sym)
|
26
|
-
end
|
27
|
-
|
28
|
-
memoize def attributes_for_sync_defined?
|
29
|
-
object_class.method_defined?(:attributes_for_sync)
|
30
|
-
end
|
31
|
-
|
32
|
-
def resolve_routing_key
|
33
|
-
routing_key_callable.call(object_class.name, attrs_for_routing_key)
|
34
|
-
end
|
35
|
-
|
36
|
-
def metadata
|
37
|
-
TableSync.routing_metadata_callable&.call(object_class.name, attrs_for_metadata)
|
38
|
-
end
|
39
|
-
|
40
|
-
def confirm?
|
41
|
-
@confirm
|
42
|
-
end
|
43
|
-
|
44
|
-
def routing_key_callable
|
45
|
-
return TableSync.routing_key_callable if TableSync.routing_key_callable
|
46
|
-
raise "Can't publish, set TableSync.routing_key_callable"
|
47
|
-
end
|
48
|
-
|
49
|
-
def filter_safe_for_serialization(object)
|
50
|
-
case object
|
51
|
-
when Array
|
52
|
-
object.each_with_object([]) do |value, memo|
|
53
|
-
value = filter_safe_for_serialization(value)
|
54
|
-
memo << value if object_mapped?(value)
|
55
|
-
end
|
56
|
-
when Hash
|
57
|
-
object.each_with_object({}) do |(key, value), memo|
|
58
|
-
key = filter_safe_for_serialization(key)
|
59
|
-
value = filter_safe_hash_values(value)
|
60
|
-
memo[key] = value if object_mapped?(key) && object_mapped?(value)
|
61
|
-
end
|
62
|
-
when Float::INFINITY
|
63
|
-
NOT_MAPPED
|
64
|
-
when *BASE_SAFE_JSON_TYPES
|
65
|
-
object
|
66
|
-
else # rubocop:disable Lint/DuplicateBranch
|
67
|
-
NOT_MAPPED
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def filter_safe_hash_values(value)
|
72
|
-
case value
|
73
|
-
when Symbol
|
74
|
-
value.to_s
|
75
|
-
else
|
76
|
-
filter_safe_for_serialization(value)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def object_mapped?(object)
|
81
|
-
object != NOT_MAPPED
|
82
|
-
end
|
83
|
-
|
84
|
-
def job_class
|
85
|
-
job_callable ? job_callable.call : raise(job_callable_error_message)
|
86
|
-
end
|
87
|
-
|
88
|
-
def publishing_data
|
89
|
-
{
|
90
|
-
model: object_class.try(:table_sync_model_name) || object_class.name,
|
91
|
-
attributes: attributes_for_sync,
|
92
|
-
version: current_time.to_f,
|
93
|
-
}
|
94
|
-
end
|
95
|
-
|
96
|
-
def params
|
97
|
-
params = {
|
98
|
-
event: :table_sync,
|
99
|
-
data: publishing_data,
|
100
|
-
confirm_select: confirm?,
|
101
|
-
routing_key: routing_key,
|
102
|
-
realtime: true,
|
103
|
-
headers: metadata,
|
104
|
-
}
|
105
|
-
|
106
|
-
params[:exchange_name] = TableSync.exchange_name if TableSync.exchange_name
|
107
|
-
|
108
|
-
params
|
109
|
-
end
|
110
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class TableSync::Publishing::BatchPublisher < TableSync::Publishing::BasePublisher
|
4
|
-
def initialize(object_class, original_attributes_array, **options)
|
5
|
-
@original_attributes_array = original_attributes_array.map do |hash|
|
6
|
-
filter_safe_for_serialization(hash.deep_symbolize_keys)
|
7
|
-
end
|
8
|
-
|
9
|
-
@object_class = object_class.constantize
|
10
|
-
@confirm = options[:confirm] || true
|
11
|
-
@routing_key = options[:routing_key] || resolve_routing_key
|
12
|
-
@push_original_attributes = options[:push_original_attributes] || false
|
13
|
-
@headers = options[:headers]
|
14
|
-
@event = options[:event] || :update
|
15
|
-
end
|
16
|
-
|
17
|
-
def publish
|
18
|
-
enqueue_job
|
19
|
-
end
|
20
|
-
|
21
|
-
def publish_now
|
22
|
-
return unless need_publish?
|
23
|
-
Rabbit.publish(params)
|
24
|
-
|
25
|
-
model_naming = TableSync.publishing_adapter.model_naming(object_class)
|
26
|
-
TableSync::Instrument.notify table: model_naming.table, schema: model_naming.schema,
|
27
|
-
event: event,
|
28
|
-
count: publishing_data[:attributes].size, direction: :publish
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
attr_reader :original_attributes_array, :routing_key, :headers, :event
|
34
|
-
|
35
|
-
def push_original_attributes?
|
36
|
-
@push_original_attributes
|
37
|
-
end
|
38
|
-
|
39
|
-
def need_publish?
|
40
|
-
(push_original_attributes? && original_attributes_array.present?) || objects.present?
|
41
|
-
end
|
42
|
-
|
43
|
-
memoize def objects
|
44
|
-
needles.map { |needle| TableSync.publishing_adapter.find(object_class, needle) }.compact
|
45
|
-
end
|
46
|
-
|
47
|
-
def job_callable
|
48
|
-
TableSync.batch_publishing_job_class_callable
|
49
|
-
end
|
50
|
-
|
51
|
-
def job_callable_error_message
|
52
|
-
"Can't publish, set TableSync.batch_publishing_job_class_callable"
|
53
|
-
end
|
54
|
-
|
55
|
-
def attrs_for_callables
|
56
|
-
{}
|
57
|
-
end
|
58
|
-
|
59
|
-
def attrs_for_routing_key
|
60
|
-
{}
|
61
|
-
end
|
62
|
-
|
63
|
-
def attrs_for_metadata
|
64
|
-
{}
|
65
|
-
end
|
66
|
-
|
67
|
-
def params
|
68
|
-
{
|
69
|
-
**super,
|
70
|
-
headers: headers,
|
71
|
-
}
|
72
|
-
end
|
73
|
-
|
74
|
-
def needles
|
75
|
-
original_attributes_array.map { |original_attributes| original_attributes.slice(*primary_keys) }
|
76
|
-
end
|
77
|
-
|
78
|
-
def publishing_data
|
79
|
-
{
|
80
|
-
**super,
|
81
|
-
event: event,
|
82
|
-
metadata: {},
|
83
|
-
}
|
84
|
-
end
|
85
|
-
|
86
|
-
def attributes_for_sync
|
87
|
-
return original_attributes_array if push_original_attributes?
|
88
|
-
|
89
|
-
objects.map do |object|
|
90
|
-
if attributes_for_sync_defined?
|
91
|
-
object.attributes_for_sync
|
92
|
-
else
|
93
|
-
TableSync.publishing_adapter.attributes(object)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def enqueue_job
|
99
|
-
job_class.perform_later(
|
100
|
-
object_class.name,
|
101
|
-
original_attributes_array,
|
102
|
-
enqueue_additional_options,
|
103
|
-
)
|
104
|
-
end
|
105
|
-
|
106
|
-
def enqueue_additional_options
|
107
|
-
{ confirm: confirm?, push_original_attributes: push_original_attributes? }
|
108
|
-
end
|
109
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableSync::Publishing::ORMAdapter
|
4
|
-
module ActiveRecord
|
5
|
-
module_function
|
6
|
-
|
7
|
-
def model_naming(object)
|
8
|
-
::TableSync::NamingResolver::ActiveRecord.new(table_name: object.table_name)
|
9
|
-
end
|
10
|
-
|
11
|
-
def find(dataset, conditions)
|
12
|
-
dataset.find_by(conditions)
|
13
|
-
end
|
14
|
-
|
15
|
-
def attributes(object)
|
16
|
-
object.attributes
|
17
|
-
end
|
18
|
-
|
19
|
-
def setup_sync(klass, opts)
|
20
|
-
debounce_time = opts.delete(:debounce_time)
|
21
|
-
|
22
|
-
klass.instance_exec do
|
23
|
-
{ create: :created, update: :updated, destroy: :destroyed }.each do |event, state|
|
24
|
-
after_commit(on: event, **opts) do
|
25
|
-
TableSync::Publishing::Publisher.new(self.class.name, attributes,
|
26
|
-
state: state, debounce_time: debounce_time).publish
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module TableSync::Publishing::ORMAdapter
|
4
|
-
module Sequel
|
5
|
-
module_function
|
6
|
-
|
7
|
-
def model_naming(object)
|
8
|
-
::TableSync::NamingResolver::Sequel.new(table_name: object.table_name, db: object.db)
|
9
|
-
end
|
10
|
-
|
11
|
-
def find(dataset, conditions)
|
12
|
-
dataset.find(conditions)
|
13
|
-
end
|
14
|
-
|
15
|
-
def attributes(object)
|
16
|
-
object.values
|
17
|
-
end
|
18
|
-
|
19
|
-
def setup_sync(klass, opts)
|
20
|
-
if_predicate = to_predicate(opts.delete(:if), true)
|
21
|
-
unless_predicate = to_predicate(opts.delete(:unless), false)
|
22
|
-
debounce_time = opts.delete(:debounce_time)
|
23
|
-
|
24
|
-
if opts.any?
|
25
|
-
raise "Only :if, :skip_debounce and :unless options are currently " \
|
26
|
-
"supported for Sequel hooks"
|
27
|
-
end
|
28
|
-
|
29
|
-
register_callbacks(klass, if_predicate, unless_predicate, debounce_time)
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_predicate(val, default)
|
33
|
-
return val.to_proc if val.respond_to?(:to_proc)
|
34
|
-
|
35
|
-
-> (*) { default }
|
36
|
-
end
|
37
|
-
|
38
|
-
def register_callbacks(klass, if_predicate, unless_predicate, debounce_time)
|
39
|
-
{ create: :created, update: :updated, destroy: :destroyed }.each do |event, state|
|
40
|
-
klass.send(:define_method, :"after_#{event}") do
|
41
|
-
if instance_eval(&if_predicate) && !instance_eval(&unless_predicate)
|
42
|
-
db.after_commit do
|
43
|
-
TableSync::Publishing::Publisher.new(
|
44
|
-
self.class.name,
|
45
|
-
values,
|
46
|
-
state: state,
|
47
|
-
debounce_time: debounce_time,
|
48
|
-
).publish
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
super()
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,129 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class TableSync::Publishing::Publisher < TableSync::Publishing::BasePublisher
|
4
|
-
DEBOUNCE_TIME = 1.minute
|
5
|
-
|
6
|
-
# 'original_attributes' are not published, they are used to resolve the routing key
|
7
|
-
def initialize(object_class, original_attributes, **opts)
|
8
|
-
@object_class = object_class.constantize
|
9
|
-
@original_attributes = filter_safe_for_serialization(original_attributes.deep_symbolize_keys)
|
10
|
-
@confirm = opts.fetch(:confirm, true)
|
11
|
-
@debounce_time = opts[:debounce_time]&.seconds || DEBOUNCE_TIME
|
12
|
-
@state = opts.fetch(:state, :updated).to_sym
|
13
|
-
validate_state
|
14
|
-
end
|
15
|
-
|
16
|
-
def publish
|
17
|
-
return enqueue_job if destroyed? || debounce_time.zero?
|
18
|
-
|
19
|
-
sync_time = Rails.cache.read(cache_key) || current_time - debounce_time - 1.second
|
20
|
-
return if sync_time > current_time
|
21
|
-
|
22
|
-
next_sync_time = sync_time + debounce_time
|
23
|
-
next_sync_time <= current_time ? enqueue_job : enqueue_job(next_sync_time)
|
24
|
-
end
|
25
|
-
|
26
|
-
def publish_now
|
27
|
-
# Update request and object does not exist -> skip publishing
|
28
|
-
return if !object && !destroyed?
|
29
|
-
|
30
|
-
Rabbit.publish(params)
|
31
|
-
model_naming = TableSync.publishing_adapter.model_naming(object_class)
|
32
|
-
TableSync::Instrument.notify table: model_naming.table, schema: model_naming.schema,
|
33
|
-
event: event, direction: :publish
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
attr_reader :original_attributes
|
39
|
-
attr_reader :state
|
40
|
-
attr_reader :debounce_time
|
41
|
-
|
42
|
-
def attrs_for_callables
|
43
|
-
attributes_for_sync
|
44
|
-
end
|
45
|
-
|
46
|
-
def attrs_for_routing_key
|
47
|
-
if object.respond_to?(:attrs_for_routing_key)
|
48
|
-
object.attrs_for_routing_key
|
49
|
-
else
|
50
|
-
attrs_for_callables
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def attrs_for_metadata
|
55
|
-
if object.respond_to?(:attrs_for_metadata)
|
56
|
-
object.attrs_for_metadata
|
57
|
-
else
|
58
|
-
attrs_for_callables
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def job_callable
|
63
|
-
TableSync.publishing_job_class_callable
|
64
|
-
end
|
65
|
-
|
66
|
-
def job_callable_error_message
|
67
|
-
"Can't publish, set TableSync.publishing_job_class_callable"
|
68
|
-
end
|
69
|
-
|
70
|
-
def enqueue_job(perform_at = current_time)
|
71
|
-
job = job_class.set(wait_until: perform_at)
|
72
|
-
job.perform_later(object_class.name, original_attributes, state: state.to_s, confirm: confirm?)
|
73
|
-
Rails.cache.write(cache_key, perform_at)
|
74
|
-
end
|
75
|
-
|
76
|
-
def routing_key
|
77
|
-
resolve_routing_key
|
78
|
-
end
|
79
|
-
|
80
|
-
def publishing_data
|
81
|
-
{
|
82
|
-
**super,
|
83
|
-
event: event,
|
84
|
-
metadata: { created: created? },
|
85
|
-
}
|
86
|
-
end
|
87
|
-
|
88
|
-
memoize def attributes_for_sync
|
89
|
-
if destroyed?
|
90
|
-
if object_class.respond_to?(:table_sync_destroy_attributes)
|
91
|
-
object_class.table_sync_destroy_attributes(original_attributes)
|
92
|
-
else
|
93
|
-
original_attributes
|
94
|
-
end
|
95
|
-
elsif attributes_for_sync_defined?
|
96
|
-
object.attributes_for_sync
|
97
|
-
else
|
98
|
-
TableSync.publishing_adapter.attributes(object)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
memoize def object
|
103
|
-
TableSync.publishing_adapter.find(object_class, needle)
|
104
|
-
end
|
105
|
-
|
106
|
-
def event
|
107
|
-
destroyed? ? :destroy : :update
|
108
|
-
end
|
109
|
-
|
110
|
-
def needle
|
111
|
-
original_attributes.slice(*primary_keys)
|
112
|
-
end
|
113
|
-
|
114
|
-
def cache_key
|
115
|
-
"#{object_class}/#{needle}_table_sync_time".delete(" ")
|
116
|
-
end
|
117
|
-
|
118
|
-
def destroyed?
|
119
|
-
state == :destroyed
|
120
|
-
end
|
121
|
-
|
122
|
-
def created?
|
123
|
-
state == :created
|
124
|
-
end
|
125
|
-
|
126
|
-
def validate_state
|
127
|
-
raise "Unknown state: #{state.inspect}" unless %i[created updated destroyed].include?(state)
|
128
|
-
end
|
129
|
-
end
|