table_sync 1.13.0 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01c6a6ad4b67454e29e7eaf06f85c09f4d786fc7842ef34cc87bc1db29937765
4
- data.tar.gz: 5ffdfad99bdd53182870f0297c9bba8181884b51fc8a7bcc234ec8fd7a5035ee
3
+ metadata.gz: f0b124973e82ee0bf943d61fb64b4ef0eb2798d1bca0b9c6396a597b2bf00ca5
4
+ data.tar.gz: d119902d368a1af85d954f586036b4f2e12b727f82bf4901b1f852b86e047627
5
5
  SHA512:
6
- metadata.gz: b7c21a601fa063b33ee9f13d580700c5ba2f70c88cdf59fbccc1fe5e9bb4a88d7cba8336dae55be7154e4aaf07194f869789c0b6a6886a04d7dc08db2dfa3f15
7
- data.tar.gz: 378f2049f688922282d0b99972b28e021b36508fc153c8546085b710ca1649993d4e19f1dfa5eaebe9041dfdbd0b871ddef1f042a0bf29825dee8ebfa6ac69bc
6
+ metadata.gz: 653ffcb319c370378c8e861b0dd0c3468970dc10c8736a570c9f6fabbb1af05ade6a0506a744617bb9b9c2b07f218405ab17ecf969c9e7fd584ef96468d8e990
7
+ data.tar.gz: 0d080baf2462565addf4cfada754a5ba1ef67772a5e155d3958a354b938e190a99eb2d961dc56c70f26fa903cdc1ee76d0f4761999a13caf05c7e93c351ac22c
data/.gitignore CHANGED
@@ -9,5 +9,4 @@
9
9
  /spec/reports/
10
10
  /tmp/
11
11
  .ruby-version
12
- Gemfile.lock
13
12
  *.gem
@@ -2,7 +2,7 @@ inherit_gem:
2
2
  rubocop-config-umbrellio: lib/rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.3
5
+ TargetRubyVersion: 2.5
6
6
  Include:
7
7
  - bin/*
8
8
  - lib/**/*.rb
@@ -10,3 +10,7 @@ AllCops:
10
10
  - Gemfile
11
11
  - Rakefile
12
12
  - table_sync.gemspec
13
+
14
+ Style/Alias:
15
+ Enabled: true
16
+ EnforcedStyle: prefer_alias_method
@@ -1,13 +1,13 @@
1
1
  language: ruby
2
2
 
3
+ rvm:
4
+ - 2.5
5
+ - 2.6
6
+ - 2.7
7
+ - ruby-head
8
+
3
9
  matrix:
4
10
  fast_finish: true
5
- include:
6
- - rvm: 2.3
7
- - rvm: 2.4
8
- - rvm: 2.5
9
- - rvm: 2.6
10
- - rvm: ruby-head
11
11
  allow_failures:
12
12
  - rvm: ruby-head
13
13
 
@@ -1,6 +1,43 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [2.3.0] - 2020-07-22
5
+ ### Added
6
+ - ruby 2.7 in Travis
7
+ - Gemfile.lock
8
+
9
+ ### Changed
10
+ - some fixes to get rid of warnings for ruby 2.7 (implicit conversion of hashes into kwargs will be dropped)
11
+ - TableSync.sync now explicitly expects klass and kwargs (it converts them into hash)
12
+ - TableSync::Instrument.notify now explicitly expects kwargs and delegates them further as kwargs
13
+
14
+ ### Removed
15
+ - ruby 2.3, 2.4 from Travis
16
+
17
+ ## [2.2.0] - 2020-04-12
18
+ ### Added
19
+ - Introduce Plugin ecosystem (**TableSync::Plugins**);
20
+
21
+ ## [2.1.1] - 2020-04-10
22
+ ### Fixed
23
+ - Updated docs for batch_publishing to fully reflect changes in 2.1.0
24
+
25
+ ## [2.1.0] - 2020-04-09
26
+ ### Added
27
+ - **TableSync::BatchPublisher**: custom headers;
28
+ - **TableSync::BatchPublisher**: custom events;
29
+
30
+ ### Changed
31
+ - Slight changes to specs
32
+
33
+ ## [2.0.0] - 2020-04-06
34
+ ### Changed
35
+ - Sequel publishing hooks: checking for `:destroy` events inside `:if`/`:unless` predicates
36
+
37
+ ## [1.13.1] - 2020-03-24
38
+ ### Fixed
39
+ - **TableSync::BatchPublisher**: incorrect `attrs_for_metadata` definition (typo in method name);
40
+
4
41
  ## [1.13.0] - 2019-11-02
5
42
  ### Added
6
43
  - Wrapping interface around receiving logic (`wrap_receiving`);
@@ -0,0 +1,257 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ table_sync (2.2.0)
5
+ memery
6
+ rabbit_messaging (~> 0.3)
7
+ rails
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actioncable (6.0.3.2)
13
+ actionpack (= 6.0.3.2)
14
+ nio4r (~> 2.0)
15
+ websocket-driver (>= 0.6.1)
16
+ actionmailbox (6.0.3.2)
17
+ actionpack (= 6.0.3.2)
18
+ activejob (= 6.0.3.2)
19
+ activerecord (= 6.0.3.2)
20
+ activestorage (= 6.0.3.2)
21
+ activesupport (= 6.0.3.2)
22
+ mail (>= 2.7.1)
23
+ actionmailer (6.0.3.2)
24
+ actionpack (= 6.0.3.2)
25
+ actionview (= 6.0.3.2)
26
+ activejob (= 6.0.3.2)
27
+ mail (~> 2.5, >= 2.5.4)
28
+ rails-dom-testing (~> 2.0)
29
+ actionpack (6.0.3.2)
30
+ actionview (= 6.0.3.2)
31
+ activesupport (= 6.0.3.2)
32
+ rack (~> 2.0, >= 2.0.8)
33
+ rack-test (>= 0.6.3)
34
+ rails-dom-testing (~> 2.0)
35
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
+ actiontext (6.0.3.2)
37
+ actionpack (= 6.0.3.2)
38
+ activerecord (= 6.0.3.2)
39
+ activestorage (= 6.0.3.2)
40
+ activesupport (= 6.0.3.2)
41
+ nokogiri (>= 1.8.5)
42
+ actionview (6.0.3.2)
43
+ activesupport (= 6.0.3.2)
44
+ builder (~> 3.1)
45
+ erubi (~> 1.4)
46
+ rails-dom-testing (~> 2.0)
47
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
+ activejob (6.0.3.2)
49
+ activesupport (= 6.0.3.2)
50
+ globalid (>= 0.3.6)
51
+ activemodel (6.0.3.2)
52
+ activesupport (= 6.0.3.2)
53
+ activerecord (6.0.3.2)
54
+ activemodel (= 6.0.3.2)
55
+ activesupport (= 6.0.3.2)
56
+ activestorage (6.0.3.2)
57
+ actionpack (= 6.0.3.2)
58
+ activejob (= 6.0.3.2)
59
+ activerecord (= 6.0.3.2)
60
+ marcel (~> 0.3.1)
61
+ activesupport (6.0.3.2)
62
+ concurrent-ruby (~> 1.0, >= 1.0.2)
63
+ i18n (>= 0.7, < 2)
64
+ minitest (~> 5.1)
65
+ tzinfo (~> 1.1)
66
+ zeitwerk (~> 2.2, >= 2.2.2)
67
+ amq-protocol (2.3.2)
68
+ ast (2.4.1)
69
+ builder (3.2.4)
70
+ bundler-audit (0.7.0.1)
71
+ bundler (>= 1.2.0, < 3)
72
+ thor (>= 0.18, < 2)
73
+ bunny (2.15.0)
74
+ amq-protocol (~> 2.3, >= 2.3.1)
75
+ coderay (1.1.3)
76
+ concurrent-ruby (1.1.6)
77
+ coveralls (0.8.23)
78
+ json (>= 1.8, < 3)
79
+ simplecov (~> 0.16.1)
80
+ term-ansicolor (~> 1.3)
81
+ thor (>= 0.19.4, < 2.0)
82
+ tins (~> 1.6)
83
+ crass (1.0.6)
84
+ diff-lcs (1.4.4)
85
+ docile (1.3.2)
86
+ erubi (1.9.0)
87
+ exception_notification (4.4.3)
88
+ actionmailer (>= 4.0, < 7)
89
+ activesupport (>= 4.0, < 7)
90
+ globalid (0.4.2)
91
+ activesupport (>= 4.2.0)
92
+ i18n (1.8.4)
93
+ concurrent-ruby (~> 1.0)
94
+ jaro_winkler (1.5.4)
95
+ json (2.3.1)
96
+ lamian (1.2.0)
97
+ rails (>= 4.2)
98
+ loofah (2.6.0)
99
+ crass (~> 1.0.2)
100
+ nokogiri (>= 1.5.9)
101
+ mail (2.7.1)
102
+ mini_mime (>= 0.1.1)
103
+ marcel (0.3.3)
104
+ mimemagic (~> 0.3.2)
105
+ memery (1.3.0)
106
+ ruby2_keywords (~> 0.0.2)
107
+ method_source (1.0.0)
108
+ mimemagic (0.3.5)
109
+ mini_mime (1.0.2)
110
+ mini_portile2 (2.4.0)
111
+ minitest (5.14.1)
112
+ nio4r (2.5.2)
113
+ nokogiri (1.10.10)
114
+ mini_portile2 (~> 2.4.0)
115
+ parallel (1.19.2)
116
+ parser (2.7.1.4)
117
+ ast (~> 2.4.1)
118
+ pg (0.21.0)
119
+ pry (0.13.1)
120
+ coderay (~> 1.1)
121
+ method_source (~> 1.0)
122
+ rabbit_messaging (0.7.1)
123
+ bunny (~> 2.0)
124
+ exception_notification
125
+ lamian
126
+ rails
127
+ sneakers (~> 2.0)
128
+ tainbox
129
+ rack (2.2.3)
130
+ rack-test (1.1.0)
131
+ rack (>= 1.0, < 3)
132
+ rails (6.0.3.2)
133
+ actioncable (= 6.0.3.2)
134
+ actionmailbox (= 6.0.3.2)
135
+ actionmailer (= 6.0.3.2)
136
+ actionpack (= 6.0.3.2)
137
+ actiontext (= 6.0.3.2)
138
+ actionview (= 6.0.3.2)
139
+ activejob (= 6.0.3.2)
140
+ activemodel (= 6.0.3.2)
141
+ activerecord (= 6.0.3.2)
142
+ activestorage (= 6.0.3.2)
143
+ activesupport (= 6.0.3.2)
144
+ bundler (>= 1.3.0)
145
+ railties (= 6.0.3.2)
146
+ sprockets-rails (>= 2.0.0)
147
+ rails-dom-testing (2.0.3)
148
+ activesupport (>= 4.2.0)
149
+ nokogiri (>= 1.6)
150
+ rails-html-sanitizer (1.3.0)
151
+ loofah (~> 2.3)
152
+ railties (6.0.3.2)
153
+ actionpack (= 6.0.3.2)
154
+ activesupport (= 6.0.3.2)
155
+ method_source
156
+ rake (>= 0.8.7)
157
+ thor (>= 0.20.3, < 2.0)
158
+ rainbow (3.0.0)
159
+ rake (13.0.1)
160
+ rexml (3.2.4)
161
+ rspec (3.9.0)
162
+ rspec-core (~> 3.9.0)
163
+ rspec-expectations (~> 3.9.0)
164
+ rspec-mocks (~> 3.9.0)
165
+ rspec-core (3.9.2)
166
+ rspec-support (~> 3.9.3)
167
+ rspec-expectations (3.9.2)
168
+ diff-lcs (>= 1.2.0, < 2.0)
169
+ rspec-support (~> 3.9.0)
170
+ rspec-mocks (3.9.1)
171
+ diff-lcs (>= 1.2.0, < 2.0)
172
+ rspec-support (~> 3.9.0)
173
+ rspec-support (3.9.3)
174
+ rubocop (0.81.0)
175
+ jaro_winkler (~> 1.5.1)
176
+ parallel (~> 1.10)
177
+ parser (>= 2.7.0.1)
178
+ rainbow (>= 2.2.2, < 4.0)
179
+ rexml
180
+ ruby-progressbar (~> 1.7)
181
+ unicode-display_width (>= 1.4.0, < 2.0)
182
+ rubocop-config-umbrellio (0.81.0.78)
183
+ rubocop (= 0.81.0)
184
+ rubocop-performance (= 1.5.2)
185
+ rubocop-rails (= 2.5.0)
186
+ rubocop-rspec (= 1.38.1)
187
+ rubocop-performance (1.5.2)
188
+ rubocop (>= 0.71.0)
189
+ rubocop-rails (2.5.0)
190
+ activesupport
191
+ rack (>= 1.1)
192
+ rubocop (>= 0.72.0)
193
+ rubocop-rspec (1.38.1)
194
+ rubocop (>= 0.68.1)
195
+ ruby-progressbar (1.10.1)
196
+ ruby2_keywords (0.0.2)
197
+ sequel (5.34.0)
198
+ serverengine (2.0.7)
199
+ sigdump (~> 0.2.2)
200
+ sigdump (0.2.4)
201
+ simplecov (0.16.1)
202
+ docile (~> 1.1)
203
+ json (>= 1.8, < 3)
204
+ simplecov-html (~> 0.10.0)
205
+ simplecov-html (0.10.2)
206
+ sneakers (2.11.0)
207
+ bunny (~> 2.12)
208
+ concurrent-ruby (~> 1.0)
209
+ rake
210
+ serverengine (~> 2.0.5)
211
+ thor
212
+ sprockets (4.0.2)
213
+ concurrent-ruby (~> 1.0)
214
+ rack (> 1, < 3)
215
+ sprockets-rails (3.2.1)
216
+ actionpack (>= 4.0)
217
+ activesupport (>= 4.0)
218
+ sprockets (>= 3.0.0)
219
+ sync (0.5.0)
220
+ tainbox (2.1.2)
221
+ activesupport
222
+ term-ansicolor (1.7.1)
223
+ tins (~> 1.0)
224
+ thor (1.0.1)
225
+ thread_safe (0.3.6)
226
+ timecop (0.9.1)
227
+ tins (1.25.0)
228
+ sync
229
+ tzinfo (1.2.7)
230
+ thread_safe (~> 0.1)
231
+ unicode-display_width (1.7.0)
232
+ websocket-driver (0.7.3)
233
+ websocket-extensions (>= 0.1.0)
234
+ websocket-extensions (0.1.5)
235
+ zeitwerk (2.4.0)
236
+
237
+ PLATFORMS
238
+ ruby
239
+
240
+ DEPENDENCIES
241
+ activejob (>= 6.0)
242
+ activerecord (>= 6.0)
243
+ bundler
244
+ bundler-audit
245
+ coveralls (~> 0.8)
246
+ pg (~> 0.18)
247
+ pry
248
+ rake
249
+ rspec (~> 3.8)
250
+ rubocop-config-umbrellio (~> 0.81)
251
+ sequel
252
+ simplecov (~> 0.16)
253
+ table_sync!
254
+ timecop
255
+
256
+ BUNDLED WITH
257
+ 2.1.4
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019 Umbrellio
3
+ Copyright (c) 2019-2020 Umbrellio
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  DB Table synchronization between microservices based on Model's event system and RabbitMQ messaging
4
4
 
5
- ## Instalation
5
+ ## Installation
6
6
 
7
7
  ```ruby
8
8
  gem 'table_sync'
@@ -21,6 +21,7 @@ require 'table_sync'
21
21
  ## Usage
22
22
 
23
23
  - [Documentation](docs/synopsis.md)
24
+ - [Development](docs/development.md)
24
25
 
25
26
  ## Contributing
26
27
 
@@ -0,0 +1,43 @@
1
+ # TableSync (development)
2
+
3
+ ## Table of Contents
4
+
5
+ - [Creation and registration of the new plugin](#creation-and-registration-of-the-new-plugin)
6
+
7
+ ### Creation and registration of the new plugin
8
+
9
+ * Create a class inherited from `TableSync::Plugins::Abstract` (recommendation: place it in the plugins directory (`lib/plugins/`));
10
+ * Implement `.install!` method (`TableSync::Plugins::Abstract.install!`)
11
+ * Register the newly created class in plugins ecosystem (`TableSync.register_plugin('plugin_name', PluginClass))`);
12
+ * Usage: `TableSync.enable(:plugin_name)` / `TableSync.plugin(:plugin_name)` / `TableSync.load(:plugin_name)` (string name is supported too);
13
+
14
+ Example:
15
+
16
+ ```ruby
17
+ # 1) creation (lib/plugins/global_method.rb)
18
+ class TableSync::Plugins::GlobalMethod < TableSync::Plugins::Abstract
19
+ class << self
20
+ # 2) plugin loader method implementation
21
+ def install!
22
+ ::TableSync.extend(Module.new do
23
+ def global_method
24
+ :works!
25
+ end
26
+ end)
27
+ end
28
+ end
29
+ end
30
+
31
+ # 3) plugin registration
32
+ TableSync.register('global_method', TableSync::Plugins::GlobalMethod)
33
+
34
+ # 4) enable registerd plugin
35
+ TableSync.plugin(:global_method) # string is supported too
36
+ # --- or ---
37
+ TableSync.enable(:global_method) # string is supported too
38
+ # --- or ---
39
+ TableSync.load(:global_method) # string is supported too
40
+
41
+ # Your new functionality
42
+ TableSync.global_method # => :works!
43
+ ```
@@ -90,11 +90,10 @@ where state is one of `:created / :updated / :destroyed` and `confirm` is Rabbit
90
90
  # Manual publishing with batches
91
91
 
92
92
  You can use `TableSync::BatchPublisher` to publish changes in batches (array of hashes in `attributes`).
93
- For now, only the following changes in the table can be published: `create` and` update`.
94
93
 
95
94
  When using `TableSync::BatchPublisher`,` TableSync.routing_key_callable` is called as follows:
96
95
  `TableSync.routing_key_callable.call(klass, {})`, i.e. empty hash is passed instead of attributes.
97
- And `TableSync.routing_metadata_callable` is not called at all: header value is set to empty hash.
96
+ And `TableSync.routing_metadata_callable` is not called at all: metadata is set to empty hash.
98
97
 
99
98
  `TableSync::BatchPublisher.new(object_class, original_attributes_array, **options)`, where `original_attributes_array` is an array with hash of attributes of published objects and `options` is a hash of options.
100
99
 
@@ -103,21 +102,30 @@ And `TableSync.routing_metadata_callable` is not called at all: header value is
103
102
  - `routing_key`, which is a custom key used (if given) to override one from `TableSync.routing_key_callable`, `nil` by default
104
103
  - `push_original_attributes` (default value is `false`), if this option is set to `true`,
105
104
  original_attributes_array will be pushed to Rabbit instead of fetching records from database and sending their mapped attributes.
105
+ - `headers`, which is an option for custom headers (can be used for headers exchanges routes), `nil` by default
106
+ - `event`, which is an option for event specification (`:destroy` or `:update`), `:update` by default
106
107
 
107
108
  Example:
108
109
 
109
110
  ```ruby
110
- TableSync::BatchPublisher.new("SomeClass", [{ id: 1 }, { id: 2 }], confirm: false, routing_key: "custom_routing_key")
111
+ TableSync::BatchPublisher.new(
112
+ "SomeClass",
113
+ [{ id: 1 }, { id: 2 }],
114
+ confirm: false,
115
+ routing_key: "custom_routing_key",
116
+ push_original_attributes: true,
117
+ headers: { key: :value },
118
+ event: :destroy,
119
+ )
111
120
  ```
112
121
 
113
122
  # Manual publishing with batches (Russian)
114
123
 
115
124
  С помощью класса `TableSync::BatchPublisher` вы можете опубликовать изменения батчами (массивом в `attributes`).
116
- Пока можно публиковать только следующие изменения в таблице: `создание записи` и `обновление записи`.
117
125
 
118
126
  При использовании `TableSync::BatchPublisher`, `TableSync.routing_key_callable` вызывается следующим образом:
119
127
  `TableSync.routing_key_callable.call(klass, {})`, то есть вместо аттрибутов передается пустой хэш.
120
- А `TableSync.routing_metadata_callable` не вызывается вовсе: в хидерах устанавливается пустой хэш.
128
+ А `TableSync.routing_metadata_callable` не вызывается вовсе: в метадате устанавливается пустой хэш.
121
129
 
122
130
  `TableSync::BatchPublisher.new(object_class, original_attributes_array, **options)`, где `original_attributes_array` - массив с аттрибутами публикуемых объектов и `options`- это хэш с дополнительными опциями.
123
131
 
@@ -125,11 +133,21 @@ TableSync::BatchPublisher.new("SomeClass", [{ id: 1 }, { id: 2 }], confirm: fals
125
133
  - `confirm`, флаг для RabbitMQ, по умолчанию - `true`
126
134
  - `routing_key`, ключ, который (если указан) замещает ключ, получаемый из `TableSync.routing_key_callable`, по умолчанию - `nil`
127
135
  - `push_original_attributes` (значение по умолчанию `false`), если для этой опции задано значение true, в Rabbit будут отправлены original_attributes_array, вместо получения значений записей из базы непосредственно перед отправкой.
136
+ - `headers`, опция для задания headers (можно использовать для задания маршрутов в headers exchange'ах), `nil` по умолчанию
137
+ - `event`, опция для указания типа события (`:destroy` или `:update`), `:update` по умолчанию
128
138
 
129
139
  Example:
130
140
 
131
141
  ```ruby
132
- TableSync::BatchPublisher.new("SomeClass", [{ id: 1 }, { id: 2 }], confirm: false, routing_key: "custom_routing_key")
142
+ TableSync::BatchPublisher.new(
143
+ "SomeClass",
144
+ [{ id: 1 }, { id: 2 }],
145
+ confirm: false,
146
+ routing_key: "custom_routing_key",
147
+ push_original_attributes: true,
148
+ headers: { key: :value },
149
+ event: :destroy,
150
+ )
133
151
  ```
134
152
 
135
153
  # Receiving changes
@@ -7,26 +7,31 @@ require "active_support/core_ext/object/blank"
7
7
  require "active_support/core_ext/numeric/time"
8
8
 
9
9
  module TableSync
10
- require_relative "./table_sync/version"
11
- require_relative "./table_sync/errors"
12
- require_relative "./table_sync/event_actions"
13
- require_relative "./table_sync/event_actions/data_wrapper"
14
- require_relative "./table_sync/config"
15
- require_relative "./table_sync/config/callback_registry"
16
- require_relative "./table_sync/config_decorator"
17
- require_relative "./table_sync/dsl"
18
- require_relative "./table_sync/receiving_handler"
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"
10
+ require_relative "table_sync/version"
11
+ require_relative "table_sync/errors"
12
+ require_relative "table_sync/plugins"
13
+ require_relative "table_sync/event_actions"
14
+ require_relative "table_sync/event_actions/data_wrapper"
15
+ require_relative "table_sync/config"
16
+ require_relative "table_sync/config/callback_registry"
17
+ require_relative "table_sync/config_decorator"
18
+ require_relative "table_sync/dsl"
19
+ require_relative "table_sync/receiving_handler"
20
+ require_relative "table_sync/base_publisher"
21
+ require_relative "table_sync/publisher"
22
+ require_relative "table_sync/batch_publisher"
23
+ require_relative "table_sync/orm_adapter/active_record"
24
+ require_relative "table_sync/orm_adapter/sequel"
25
+ require_relative "table_sync/model/active_record"
26
+ require_relative "table_sync/model/sequel"
27
+ require_relative "table_sync/instrument"
28
+ require_relative "table_sync/instrument_adapter/active_support"
29
+ require_relative "table_sync/naming_resolver/active_record"
30
+ require_relative "table_sync/naming_resolver/sequel"
31
+
32
+ # @api public
33
+ # @since 2.2.0
34
+ extend Plugins::AccessMixin
30
35
 
31
36
  class << self
32
37
  include Memery
@@ -38,8 +43,8 @@ module TableSync
38
43
  attr_accessor :routing_metadata_callable
39
44
  attr_accessor :notifier
40
45
 
41
- def sync(*args)
42
- orm.setup_sync(*args)
46
+ def sync(klass, **opts)
47
+ orm.setup_sync(klass, opts)
43
48
  end
44
49
 
45
50
  def orm=(val)
@@ -2,13 +2,16 @@
2
2
 
3
3
  class TableSync::BatchPublisher < TableSync::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
- @confirm = options[:confirm] || true
10
- @routing_key = options[:routing_key] || resolve_routing_key
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
@@ -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
@@ -57,14 +60,14 @@ class TableSync::BatchPublisher < TableSync::BasePublisher
57
60
  {}
58
61
  end
59
62
 
60
- def attr_for_metadata
63
+ def attrs_for_metadata
61
64
  {}
62
65
  end
63
66
 
64
67
  def params
65
68
  {
66
69
  **super,
67
- headers: nil,
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
 
@@ -44,7 +44,7 @@ module TableSync
44
44
 
45
45
  # wrapper for proc-value, this wrapper receives all params (model, version, project_id...)
46
46
  # and filters them for proc-value
47
- unified_block = proc { |hash = {}| block.call(hash.slice(*params)) }
47
+ unified_block = proc { |hash = {}| block.call(**hash.slice(*params)) }
48
48
 
49
49
  # set wrapped proc-value as ivar value
50
50
  instance_variable_set(ivar, unified_block)
@@ -38,4 +38,26 @@ module TableSync
38
38
  MSG
39
39
  end
40
40
  end
41
+
42
+ # @api public
43
+ # @since 2.2.0
44
+ PluginError = Class.new(Error)
45
+
46
+ # @api public
47
+ # @since 2.2.0
48
+ class UnregisteredPluginError < PluginError
49
+ # @param plugin_name [Any]
50
+ def initialize(plugin_name)
51
+ super("#{plugin_name} plugin is not registered")
52
+ end
53
+ end
54
+
55
+ # @api public
56
+ # @since 2.2.0
57
+ class AlreadyRegisteredPluginError < PluginError
58
+ # @param plugin_name [Any]
59
+ def initialize(plugin_name)
60
+ super("#{plugin_name} plugin already exists")
61
+ end
62
+ end
41
63
  end
@@ -3,7 +3,7 @@
3
3
  module TableSync::Instrument
4
4
  module_function
5
5
 
6
- def notify(*args)
7
- TableSync.notifier&.notify(*args)
6
+ def notify(**args)
7
+ TableSync.notifier&.notify(**args)
8
8
  end
9
9
  end
@@ -115,7 +115,7 @@ module TableSync::Model
115
115
  end
116
116
 
117
117
  def row_to_hash(row)
118
- row.attributes.each_with_object({}) { |(k, v), o| o[k.to_sym] = v }
118
+ row.attributes.transform_keys(&:to_sym)
119
119
  end
120
120
  end
121
121
  end
@@ -20,7 +20,7 @@ module TableSync::ORMAdapter
20
20
  object.attributes
21
21
  end
22
22
 
23
- def setup_sync(klass, **opts)
23
+ def setup_sync(klass, opts)
24
24
  debounce_time = opts.delete(:debounce_time)
25
25
 
26
26
  klass.instance_exec do
@@ -20,7 +20,7 @@ module TableSync::ORMAdapter
20
20
  object.values
21
21
  end
22
22
 
23
- def setup_sync(klass, **opts)
23
+ def setup_sync(klass, opts)
24
24
  if_predicate = to_predicate(opts.delete(:if), true)
25
25
  unless_predicate = to_predicate(opts.delete(:unless), false)
26
26
  debounce_time = opts.delete(:debounce_time)
@@ -40,24 +40,21 @@ module TableSync::ORMAdapter
40
40
  end
41
41
 
42
42
  def register_callbacks(klass, if_predicate, unless_predicate, debounce_time)
43
- { create: :created, update: :updated }.each do |event, state|
43
+ { create: :created, update: :updated, destroy: :destroyed }.each do |event, state|
44
44
  klass.send(:define_method, :"after_#{event}") do
45
45
  if instance_eval(&if_predicate) && !instance_eval(&unless_predicate)
46
46
  db.after_commit do
47
- TableSync::Publisher.new(self.class.name, values,
48
- state: state, debounce_time: debounce_time).publish
47
+ TableSync::Publisher.new(
48
+ self.class.name,
49
+ values,
50
+ state: state,
51
+ debounce_time: debounce_time,
52
+ ).publish
49
53
  end
50
54
  end
51
- super()
52
- end
53
- end
54
55
 
55
- klass.send(:define_method, :after_destroy) do
56
- # publish anyway
57
- db.after_commit do
58
- TableSync::Publisher.new(self.class.name, values, state: :destroyed).publish
56
+ super()
59
57
  end
60
- super()
61
58
  end
62
59
  end
63
60
  end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 2.2.0
5
+ module TableSync::Plugins
6
+ require_relative "plugins/registry"
7
+ require_relative "plugins/access_mixin"
8
+ require_relative "plugins/abstract"
9
+
10
+ # @since 2.2.0
11
+ @plugin_registry = Registry.new
12
+ # @since 2.2.0
13
+ @access_lock = Mutex.new
14
+
15
+ class << self
16
+ # @param plugin_name [Symbol, String]
17
+ # @return [void]
18
+ #
19
+ # @api public
20
+ # @since 2.2.0
21
+ def load(plugin_name)
22
+ thread_safe { plugin_registry[plugin_name].load! }
23
+ end
24
+
25
+ # @return [Array<String>]
26
+ #
27
+ # @api public
28
+ # @since 2.2.0
29
+ def loaded_plugins
30
+ thread_safe { plugin_registry.loaded.keys }
31
+ end
32
+
33
+ # @return [Array<String>]
34
+ #
35
+ # @api public
36
+ # @since 2.2.0
37
+ def names
38
+ thread_safe { plugin_registry.names }
39
+ end
40
+
41
+ # @param plugin_name [Symbol, String]
42
+ # @return [void]
43
+ #
44
+ # @api private
45
+ # @since 2.2.0
46
+ def register_plugin(plugin_name, plugin_module)
47
+ thread_safe { plugin_registry[plugin_name] = plugin_module }
48
+ end
49
+
50
+ private
51
+
52
+ # @return [TableSync::Plugins::Registry]
53
+ #
54
+ # @api private
55
+ # @since 2.2.0
56
+ attr_reader :plugin_registry
57
+
58
+ # @return [Mutex]
59
+ #
60
+ # @api private
61
+ # @since 2.2.0
62
+ attr_reader :access_lock
63
+
64
+ # @return [void]
65
+ #
66
+ # @api private
67
+ # @since 2.2.0
68
+ def thread_safe
69
+ access_lock.synchronize { yield if block_given? }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ class TableSync::Plugins::Abstract
6
+ class << self
7
+ # @param child_klass [Class]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 2.2.0
12
+ def inherited(child_klass)
13
+ child_klass.instance_variable_set(:@__loaded__, false)
14
+ child_klass.instance_variable_set(:@__lock__, Mutex.new)
15
+ super
16
+ end
17
+
18
+ # @return [void]
19
+ #
20
+ # @api private
21
+ # @since 2.2.0
22
+ def load!
23
+ __thread_safe__ do
24
+ unless @__loaded__
25
+ @__loaded__ = true
26
+ install!
27
+ end
28
+ end
29
+ end
30
+
31
+ # @return [Boolean]
32
+ #
33
+ # @api private
34
+ # @since 2.2.0
35
+ def loaded?
36
+ __thread_safe__ { @__loaded__ }
37
+ end
38
+
39
+ private
40
+
41
+ # @return [void]
42
+ #
43
+ # @api private
44
+ # @since 2.2.0
45
+ def install!; end
46
+
47
+ # @return [Any]
48
+ #
49
+ # @api private
50
+ # @since 2.2.0
51
+ def __thread_safe__
52
+ @__lock__.synchronize { yield }
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ module TableSync::Plugins::AccessMixin
6
+ # @param plugin_name [Symbol, String]
7
+ # @return [void]
8
+ #
9
+ # @see TableSync::Plugins
10
+ #
11
+ # @api public
12
+ # @since 2.2.0
13
+ def plugin(plugin_name)
14
+ TableSync::Plugins.load(plugin_name)
15
+ end
16
+ alias_method :enable, :plugin
17
+ alias_method :load, :plugin
18
+
19
+ # @return [Array<String>]
20
+ #
21
+ # @see TableSync::Plugins
22
+ #
23
+ # @api public
24
+ # @since 2.2.0
25
+ def plugins
26
+ TableSync::Plugins.names
27
+ end
28
+
29
+ # @return [Hash<String,Class<TableSync::Plugins::Abstract>>]
30
+ #
31
+ # @api private
32
+ # @since 2.2.0
33
+ def loaded_plugins
34
+ TableSync::Plugins.loaded_plugins
35
+ end
36
+ alias_method :enabled_plugins, :loaded_plugins
37
+
38
+ # @param plugin_name [String, Symbol]
39
+ # @param plugin_klass [Class<TableSync::Plugins::Abstract>]
40
+ # @return [void]
41
+ #
42
+ # @see TableSync::Plugins
43
+ #
44
+ # @api public
45
+ # @since 2.2.0
46
+ def register_plugin(plugin_name, plugin_klass)
47
+ TableSync::Plugins.register_plugin(plugin_name, plugin_klass)
48
+ end
49
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 2.2.0
5
+ class TableSync::Plugins::Registry
6
+ include Enumerable
7
+
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 2.2.0
12
+ def initialize
13
+ @plugin_set = {}
14
+ @access_lock = Mutex.new
15
+ end
16
+
17
+ # @param plugin_name [Symbol, String]
18
+ # @return [TableSync::Plugins::Abstract]
19
+ #
20
+ # @api private
21
+ # @since 2.2.0
22
+ def [](plugin_name)
23
+ thread_safe { fetch(plugin_name) }
24
+ end
25
+
26
+ # @param plugin_name [Symbol, String]
27
+ # @param plugin_module [TableSync::Plugins::Abstract]
28
+ # @return [void]
29
+ #
30
+ # @api private
31
+ # @since 2.2.0
32
+ def register(plugin_name, plugin_module)
33
+ thread_safe { apply(plugin_name, plugin_module) }
34
+ end
35
+ alias_method :[]=, :register
36
+
37
+ # @return [Array<String>]
38
+ #
39
+ # @api private
40
+ # @since 2.2.0
41
+ def names
42
+ thread_safe { plugin_names }
43
+ end
44
+
45
+ # @return [Hash<String,Class<TableSync::Plugins::Abstract>>]
46
+ #
47
+ # @api private
48
+ # @since 2.2.0
49
+ def loaded
50
+ thread_safe { loaded_plugins }
51
+ end
52
+
53
+ # @param block [Block]
54
+ # @return [Enumerable]
55
+ #
56
+ # @api private
57
+ # @since 2.2.0
58
+ def each(&block)
59
+ thread_safe { iterate(&block) }
60
+ end
61
+
62
+ private
63
+
64
+ # @return [Hash]
65
+ #
66
+ # @api private
67
+ # @since 2.2.0
68
+ attr_reader :plugin_set
69
+
70
+ # @return [Mutex]
71
+ #
72
+ # @api private
73
+ # @since 2.2.0
74
+ attr_reader :access_lock
75
+
76
+ # @return [void]
77
+ #
78
+ # @api private
79
+ # @since 2.2.0
80
+ def thread_safe
81
+ access_lock.synchronize { yield if block_given? }
82
+ end
83
+
84
+ # @return [Array<String>]
85
+ #
86
+ # @api private
87
+ # @since 2.2.0
88
+ def plugin_names
89
+ plugin_set.keys
90
+ end
91
+
92
+ # @param block [Block]
93
+ # @return [Enumerable]
94
+ #
95
+ # @api private
96
+ # @since 2.2.0
97
+ def iterate(&block)
98
+ block_given? ? plugin_set.each_pair(&block) : plugin_set.each_pair
99
+ end
100
+
101
+ # @param plugin_name [String]
102
+ # @return [Boolean]
103
+ #
104
+ # @api private
105
+ # @since 2.2.0
106
+ def registered?(plugin_name)
107
+ plugin_set.key?(plugin_name)
108
+ end
109
+
110
+ # @return [Array<TableSync::Plugins::Abstract>]
111
+ #
112
+ # @api private
113
+ # @since 2.2.0
114
+ def loaded_plugins
115
+ plugin_set.select { |_plugin_name, plugin_module| plugin_module.loaded? }
116
+ end
117
+
118
+ # @param plugin_name [Symbol, String]
119
+ # @param plugin_module [TableSync::Plugins::Abstract]
120
+ # @return [void]
121
+ #
122
+ # @raise [TableSync::AlreadyRegisteredPluginError]
123
+ #
124
+ # @api private
125
+ # @since 2.2.0
126
+ def apply(plugin_name, plugin_module)
127
+ plugin_name = indifferently_accessible_plugin_name(plugin_name)
128
+ raise(TableSync::AlreadyRegisteredPluginError.new(plugin_name)) if registered?(plugin_name)
129
+ plugin_set[plugin_name] = plugin_module
130
+ end
131
+
132
+ # @param plugin_name [Symbol, String]
133
+ # @return [TableSync::Plugins::Abstract]
134
+ #
135
+ # @raise [TableSync::UnregisteredPluginError]
136
+ #
137
+ # @api private
138
+ # @since 2.2.0
139
+ def fetch(plugin_name)
140
+ plugin_name = indifferently_accessible_plugin_name(plugin_name)
141
+ raise(TableSync::UnregisteredPluginError.new(plugin_name)) unless registered?(plugin_name)
142
+ plugin_set[plugin_name]
143
+ end
144
+
145
+ # @param key [Symbol, String]
146
+ # @return [String]
147
+ #
148
+ # @api private
149
+ # @since 2.2.0
150
+ def indifferently_accessible_plugin_name(plugin_name)
151
+ plugin_name.to_s
152
+ end
153
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TableSync
4
- VERSION = "1.13.0"
4
+ VERSION = "2.3.0"
5
5
  end
@@ -5,7 +5,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "table_sync/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.required_ruby_version = ">= 2.3.8"
8
+ spec.required_ruby_version = ">= 2.5.6"
9
9
 
10
10
  spec.name = "table_sync"
11
11
  spec.version = TableSync::VERSION
@@ -32,11 +32,11 @@ Gem::Specification.new do |spec|
32
32
 
33
33
  spec.add_development_dependency "coveralls", "~> 0.8"
34
34
  spec.add_development_dependency "rspec", "~> 3.8"
35
- spec.add_development_dependency "rubocop-config-umbrellio", "~> 0.74"
35
+ spec.add_development_dependency "rubocop-config-umbrellio", "~> 0.81"
36
36
  spec.add_development_dependency "simplecov", "~> 0.16"
37
37
 
38
- spec.add_development_dependency "activejob", ">= 4.2.11"
39
- spec.add_development_dependency "activerecord"
38
+ spec.add_development_dependency "activejob", ">= 6.0"
39
+ spec.add_development_dependency "activerecord", ">= 6.0"
40
40
  spec.add_development_dependency "pg", "~> 0.18"
41
41
  spec.add_development_dependency "sequel"
42
42
  spec.add_development_dependency "timecop"
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: 1.13.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Umbrellio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-02 00:00:00.000000000 Z
11
+ date: 2020-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: memery
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.74'
89
+ version: '0.81'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.74'
96
+ version: '0.81'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -114,28 +114,28 @@ dependencies:
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: 4.2.11
117
+ version: '6.0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 4.2.11
124
+ version: '6.0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: activerecord
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: '0'
131
+ version: '6.0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
- version: '0'
138
+ version: '6.0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: pg
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -248,11 +248,13 @@ files:
248
248
  - ".travis.yml"
249
249
  - CHANGELOG.md
250
250
  - Gemfile
251
+ - Gemfile.lock
251
252
  - LICENSE.md
252
253
  - README.md
253
254
  - Rakefile
254
255
  - bin/console
255
256
  - bin/setup
257
+ - docs/development.md
256
258
  - docs/synopsis.md
257
259
  - lib/table_sync.rb
258
260
  - lib/table_sync/base_publisher.rb
@@ -275,6 +277,10 @@ files:
275
277
  - lib/table_sync/naming_resolver/sequel.rb
276
278
  - lib/table_sync/orm_adapter/active_record.rb
277
279
  - lib/table_sync/orm_adapter/sequel.rb
280
+ - lib/table_sync/plugins.rb
281
+ - lib/table_sync/plugins/abstract.rb
282
+ - lib/table_sync/plugins/access_mixin.rb
283
+ - lib/table_sync/plugins/registry.rb
278
284
  - lib/table_sync/publisher.rb
279
285
  - lib/table_sync/receiving_handler.rb
280
286
  - lib/table_sync/version.rb
@@ -292,14 +298,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
292
298
  requirements:
293
299
  - - ">="
294
300
  - !ruby/object:Gem::Version
295
- version: 2.3.8
301
+ version: 2.5.6
296
302
  required_rubygems_version: !ruby/object:Gem::Requirement
297
303
  requirements:
298
304
  - - ">="
299
305
  - !ruby/object:Gem::Version
300
306
  version: '0'
301
307
  requirements: []
302
- rubygems_version: 3.0.3
308
+ rubygems_version: 3.1.2
303
309
  signing_key:
304
310
  specification_version: 4
305
311
  summary: DB Table synchronization between microservices based on Model's event system