fury_dumper 0.1.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 +7 -0
- data/.github/workflows/build.yaml +43 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +67 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/Breadth-first.png +0 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Depth-first.png +0 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +202 -0
- data/README.md +383 -0
- data/README.ru.md +382 -0
- data/Rakefile +8 -0
- data/app/controllers/fury_dumper/dump_process_controller.rb +25 -0
- data/config/routes.rb +6 -0
- data/fury_dumper.gemspec +37 -0
- data/lib/fury_dumper/api.rb +82 -0
- data/lib/fury_dumper/config.rb +113 -0
- data/lib/fury_dumper/dumper.rb +632 -0
- data/lib/fury_dumper/dumpers/dump_state.rb +61 -0
- data/lib/fury_dumper/dumpers/model.rb +131 -0
- data/lib/fury_dumper/dumpers/model_queue.rb +34 -0
- data/lib/fury_dumper/dumpers/relation_items.rb +79 -0
- data/lib/fury_dumper/encrypter.rb +17 -0
- data/lib/fury_dumper/engine.rb +7 -0
- data/lib/fury_dumper/version.rb +5 -0
- data/lib/fury_dumper.rb +102 -0
- data/lib/generators/fury_dumper/config_generator.rb +21 -0
- data/rails_generators/fury_dumper_config/fury_dumper_config_generator.rb +10 -0
- data/rails_generators/fury_dumper_config/templates/fury_dumper.rb +1 -0
- data/rails_generators/fury_dumper_config/templates/fury_dumper.yml +44 -0
- metadata +181 -0
data/README.ru.md
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
# FuryDumper π§β
|
2
|
+
|
3
|
+
ΠΠΎΠ±ΡΠΎ ΠΏΠΎΠΆΠ°Π»ΠΎΠ²Π°ΡΡ Π³Π΅ΠΌ Π΄Π»Ρ Π±ΡΡΡΡΠΎΠ³ΠΎ ΠΈ Π»Π΅Π³ΠΊΠΎΠ³ΠΎ Π΄Π°ΠΏΠΌΠ° ΠΈΠ· ΡΠ΄Π°Π»Π΅Π½ΠΎΠΉ ΠΠ!
|
4
|
+
|
5
|
+
ΠΠ°Π½Π½Π°Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ Π²Π°ΠΌ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π΄Π°ΠΌΠΏ ΠΈΠ· ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ
Π² main service ΠΈΠ»ΠΈ Π΄ΡΡΠ³ΠΈΡ
ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ°Ρ
, ΠΈΠΌΠ΅ΡΡΠΈΡ
Π³Π΅ΠΌ `fury_dumper`.\
|
6
|
+
*ΠΠΎΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΈΡΠ°ΡΡ Π½Π° Π΄ΡΡΠ³ΠΈΡ
ΡΠ·ΡΠΊΠ°Ρ
: [English](README.md).*
|
7
|
+
|
8
|
+
Π ΡΡΠΎΠΌ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΈ Π²Ρ Π½Π°ΠΉΠ΄Π΅ΡΠ΅ ΡΠ°ΠΉΠ»Ρ, Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΡΠ΅ Π΄Π»Ρ Π΄Π°Π½Π½ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ Π½Π° Ruby.
|
9
|
+
ΠΡΠ»ΠΈ Ρ
ΠΎΡΠΈΡΠ΅ ΠΏΠΎΠΌΠΎΡΡ - ΠΊΠΎΠ΄ΠΈΡΡ ΡΡΡΡ `lib / fury_dumper` π.\
|
10
|
+
*ΠΡΠΎΠ±Π΅Π½Π½ΠΎΡΡΠΈ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ Π·Π΄Π΅ΡΡ: [English](README.md#dev-documentation), [Russian](README.ru.md#Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ-Π΄Π»Ρ-ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ²).*
|
11
|
+
|
12
|
+
## Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ°
|
13
|
+
|
14
|
+
ΠΠΈΡΠ΅ΠΌ Π² Gemfile Π²Π°ΡΠ΅Π³ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠ°:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'fury_dumper'
|
18
|
+
```
|
19
|
+
|
20
|
+
ΠΡΠΏΠΎΠ»Π½ΡΠ΅ΠΌ:
|
21
|
+
|
22
|
+
bundle install
|
23
|
+
|
24
|
+
Π ΠΎΠ΄ΠΈΠ½ΠΎΡΠΊΡ ΠΌΠΎΠΆΠ½ΠΎ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΠ°ΠΊ:
|
25
|
+
|
26
|
+
gem install fury_dumper
|
27
|
+
|
28
|
+
## ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅
|
29
|
+
|
30
|
+
### ΠΠΎΠ½ΡΠΈΠ³ΠΈ
|
31
|
+
|
32
|
+
Π§ΡΠΎΠ±Ρ ΡΠΎΠ·Π΄Π°ΡΡ Π΄Π΅ΡΠΎΠ»ΡΠ½ΡΡ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ:
|
33
|
+
|
34
|
+
bundle exec rails generate fury_dumper:config
|
35
|
+
|
36
|
+
ΠΠ»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠΉ ΡΠ°Π±ΠΎΡΡ Ρ Π΄ΡΡΠ³ΠΈΠΌΠΈ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ°ΠΌΠΈ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠ½ΠΎ Π½Π°ΡΡΡΠΎΠΈΡΡ `fury_dumper.yml` ΠΊΠΎΠ½ΡΠΈΠ³. ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π΅Π³ΠΎ ΡΡΡΡΠΊΡΡΡΡ:
|
37
|
+
|
38
|
+
```yaml
|
39
|
+
# Π Π°Π·ΠΌΠ΅Ρ Π±Π°ΡΡΠ° Π½Π° ΠΏΠ΅ΡΠ²ΠΎΠΉ ΠΈΡΠ΅ΡΠ°ΡΠΈΠΈ
|
40
|
+
#
|
41
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ; ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ 100
|
42
|
+
batch_size: 100
|
43
|
+
|
44
|
+
# Π‘ΠΎΠΎΡΠ½ΠΎΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° Π·Π°ΠΏΠΈΡΠ΅ΠΉ (fetching_records), Π²ΡΠ³ΡΡΠΆΠ°Π΅ΠΌΡΡ
ΠΈΠ· ΠΠ, ΠΊ ΡΠ°Π·ΠΌΠ΅ΡΡ Π±Π°ΡΡΠ°
|
45
|
+
# Π€ΠΎΡΠΌΡΠ»Π°: fetching_records = ratio_records_batches * batch_size
|
46
|
+
# fetching_records Π²ΡΡΡΡΠΏΠ°Π΅Ρ Π² ΡΠΎΠ»ΠΈ Π·Π½Π°ΡΠ΅Π½ΠΈΡ limit'Π° Π΄Π»Ρ sql Π·Π°ΠΏΡΠΎΡΠΎΠ²
|
47
|
+
#
|
48
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ; ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ 10
|
49
|
+
ratio_records_batches: 10
|
50
|
+
|
51
|
+
# Π Π΅ΠΆΠΈΠΌ ΠΎΠ±Ρ
ΠΎΠ΄Π° Π³ΡΠ°ΡΠ° ΡΠ²ΡΠ·Π΅ΠΉ - Π² ΡΠΈΡΠΈΠ½Ρ(:wide) ΠΈΠ»ΠΈ Π³Π»ΡΠ±ΠΈΠ½Ρ(:depth)
|
52
|
+
#
|
53
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ; ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ ΡΠ²ΡΠ·ΠΈ Π² ΡΠΈΡΠΈΠ½Ρ
|
54
|
+
mode: wide
|
55
|
+
|
56
|
+
# Π‘Π²ΡΠ·ΠΈ ΠΊΠΎΡΠΎΡΡΠ΅ Π±ΡΠ΄ΡΡ ΠΈΡΠΊΠ»ΡΡΠ΅Π½Ρ ΠΈΠ· Π΄Π°ΠΌΠΏΠ°,
|
57
|
+
# ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π΄Π»Ρ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ ΡΠΊΠΎΡΠΎΡΡΠΈ Π²ΡΠ³ΡΡΠ·ΠΊΠΈ ΠΈ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ
|
58
|
+
# ΠΈΠ· Π½Π΅Π΅ Π»ΠΈΡΠ½ΠΈΡ
Π΄Π°Π½Π½ΡΡ
:
|
59
|
+
# < ΠΈΠΌΡ ΠΊΠ»Π°ΡΡΠ° >.< ΠΈΠΌΡ ΡΠ²ΡΠ·ΠΈ >
|
60
|
+
#
|
61
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ; ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ ΠΏΡΡΡΠΎΠΉ ΠΌΠ°ΡΡΠΈΠ²
|
62
|
+
exclude_relations: User.friends, Post.author
|
63
|
+
|
64
|
+
# ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Π΄Π°Π½Π½ΡΠ΅ Π²ΡΠ³ΡΡΠΆΠ°ΡΡΡΡ Π±ΡΡΡΡΠΎ (Π±Π΅Π· ΡΠΎΡΡΠΈΡΠΎΠΊΠΈ)
|
65
|
+
# fast ΡΠ΅ΠΆΠΈΠΌ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π²ΡΠ³ΡΡΠΆΠ°ΡΡ Π·Π°ΠΏΠΈΡΠΈ, ΠΎΡΡΠΎΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΏΠΎ ΠΏΡΠ΅Π²ΡΠΈΠ½ΠΎΠΌΡ ΠΊΠ»ΡΡΡ(false) ΠΈΠ»ΠΈ Π½Π΅Ρ(true),
|
66
|
+
# ΠΏΠΎΠ»Π΅Π·Π½ΠΎ Π΄Π»Ρ ΠΏΡΠΈ ΡΠΎΠ·Π΄Π°Π½ΠΈΠΈ Π΄Π°ΠΌΠΏΠΎΠ² Π΄Π»Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ².
|
67
|
+
#
|
68
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ; ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ true
|
69
|
+
fast: true
|
70
|
+
|
71
|
+
# Π‘ΠΏΠΈΡΠΎΠΊ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ½ΡΡ
ΡΠ²ΡΠ·Π΅ΠΉ
|
72
|
+
#
|
73
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
74
|
+
relative_services:
|
75
|
+
# ΠΠΌΡ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ°
|
76
|
+
#
|
77
|
+
# ΠΠ΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
78
|
+
post_service:
|
79
|
+
# ΠΠΌΡ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ Π΄Π»Ρ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ°
|
80
|
+
# Ρ ΠΊΠΎΡΠΎΡΠΎΠΉ Π±ΡΠ΄ΡΡ ΡΡΠ½ΡΡΡΡΡ Π΄Π°Π½Π½ΡΠ΅
|
81
|
+
#
|
82
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
83
|
+
database: 'post_service_development_dump'
|
84
|
+
|
85
|
+
# Π₯ΠΎΡΡ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ
|
86
|
+
#
|
87
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
88
|
+
host: 'localhost'
|
89
|
+
|
90
|
+
# ΠΠΎΡΡ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ
|
91
|
+
#
|
92
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
93
|
+
port: '5432'
|
94
|
+
|
95
|
+
# ΠΠΌΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ
|
96
|
+
#
|
97
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
98
|
+
user: 'user'
|
99
|
+
|
100
|
+
# ΠΠ°ΡΠΎΠ»Ρ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ
|
101
|
+
#
|
102
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
103
|
+
password: 'password'
|
104
|
+
|
105
|
+
# Π‘ΠΏΠΈΡΠΎΠΊ ΡΠ°Π±Π»ΠΈΡ, ΠΈΠΌΠ΅ΡΡΠΈΡ
ΡΠ²ΡΠ·ΠΈ Ρ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠΎΠΌ (post_service)
|
106
|
+
#
|
107
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
108
|
+
tables:
|
109
|
+
# ΠΠΌΡ ΡΠ°Π±Π»ΠΈΡΡ Ρ ΡΠ΅ΠΊΡΡΠ΅ΠΌ ΡΠ΅ΡΠ²ΠΈΡΠ΅
|
110
|
+
#
|
111
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
112
|
+
users:
|
113
|
+
# ΠΠΌΡ ΡΠ°Π±Π»ΠΈΡΡ Π² ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ΅ (post_service)
|
114
|
+
#
|
115
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
116
|
+
users:
|
117
|
+
# ΠΠΌΡ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠΈ ΠΊ ΡΠ°Π±Π»ΠΈΡΠ΅ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΡΠ΅ΡΠ²ΠΈΡΠ° (users)
|
118
|
+
#
|
119
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
120
|
+
self_field_name: 'id'
|
121
|
+
|
122
|
+
# ΠΠΌΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π² ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ΅ (post_service)
|
123
|
+
#
|
124
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
125
|
+
ms_model_name: 'User'
|
126
|
+
|
127
|
+
# ΠΠΌΡ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠΈ ΠΊ ΡΠ°Π±Π»ΠΈΡΠ΅ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ° (involved_users)
|
128
|
+
#
|
129
|
+
# ΠΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΡΠΉ
|
130
|
+
ms_field_name: 'root_user_id'
|
131
|
+
root_posts:
|
132
|
+
posts:
|
133
|
+
self_field_name: 'id'
|
134
|
+
ms_model_name: 'Post'
|
135
|
+
ms_field_name: 'root_post_id'
|
136
|
+
logs_service:
|
137
|
+
database: 'logs_service_development_dump'
|
138
|
+
host: 'localhost'
|
139
|
+
port: '5432'
|
140
|
+
user: 'user'
|
141
|
+
password: 'password'
|
142
|
+
tables:
|
143
|
+
users:
|
144
|
+
logs:
|
145
|
+
self_field_name: "log :: json - >> 'id'"
|
146
|
+
ms_model_name: 'Log'
|
147
|
+
ms_field_name: 'id'
|
148
|
+
```
|
149
|
+
|
150
|
+
### Routing Π΄Π»Ρ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠΎΠ²
|
151
|
+
|
152
|
+
ΠΠ΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΡΡΠΎΡ ΠΊΠΎΠ΄ Π² `config/routes.rb` Π΄Π»Ρ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ Π΄ΡΡΠ³ΠΈΠΌ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ°ΠΌ Π΄Π°ΠΌΠΏΠ°ΡΡ ΠΠ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠ°.
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
mount FuryDumper::Engine => "fury_dumper" unless Rails.env.production?
|
156
|
+
```
|
157
|
+
|
158
|
+
### ΠΡΠ·ΠΎΠ² ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΡΡΠΊΡΠΈΠΈ
|
159
|
+
|
160
|
+
**β οΈ β οΈ β οΈ ΠΠ½ΠΈΠΌΠ°Π½ΠΈΠ΅! ΠΡΠΈ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ Π΄Π°Π½Π½ΡΡ
, Π² ΡΠ»ΡΡΠ°Π΅ ΠΊΠΎΠ½ΡΠ»ΠΈΠΊΡΠ° Ρ ΠΈΠΌΠ΅ΡΡΠΈΠΌΠΈΡΡ Π΄Π°Π½Π½ΡΠΌΠΈ, Π±ΠΎΠ»Π΅Π΅ ΠΏΡΠΈΠΎΡΠΈΡΠ΅ΡΠ½ΡΠΌΠΈ ΡΡΠΈΡΠ°ΡΡΡΡ Π² ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ (ΡΠ΅ΠΊΡΡΠΈΠ΅ ΠΏΠ΅ΡΠ΅ΡΡΡΡΡΡ)! β οΈ β οΈ β οΈ**
|
161
|
+
|
162
|
+
ΠΠ»Ρ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ Π½Π°ΡΠ°ΡΡ Π΄Π°ΠΌΠΏ Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ, Π² ΠΊΠΎΠ½ΡΠΎΠ»Π΅ ΡΠΊΠ°ΠΆΠΈΡΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
FuryDumper.dump(password: 'password',
|
166
|
+
host: 'localhost',
|
167
|
+
port: '5632',
|
168
|
+
user: 'username',
|
169
|
+
model_name: 'User',
|
170
|
+
field_name: 'token',
|
171
|
+
field_values: ['99999999-8888-4444-1212-111111111111'],
|
172
|
+
database: 'staging',
|
173
|
+
debug_mode: :short)
|
174
|
+
```
|
175
|
+
|
176
|
+
ΠΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π΄Π»Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌΡ Ρ
ΠΎΡΡΡ, Π±ΡΠ΄Π΅Ρ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡ ssh ΠΊΠΎΠΌΠ°Π½Π΄Ρ. ΠΡΠΈΠΌΠ΅Ρ Π΄Π»Ρ ΠΠ ΡΡΠ΅ΠΉΠ΄ΠΆΠ° ΡΠ΅Π»ΠΈΠΊΡΠ°:
|
177
|
+
```
|
178
|
+
ssh -NL <local_port>:<host>:<db_port> username@<host>
|
179
|
+
```
|
180
|
+
|
181
|
+
ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠΎΠ²:
|
182
|
+
|
183
|
+
| ΠΡΠ³ΡΠΌΠ΅Π½Ρ | ΠΠΏΠΈΡΠ°Π½ΠΈΠ΅ |
|
184
|
+
| --- | --- |
|
185
|
+
| host | Ρ
ΠΎΡΡ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ |
|
186
|
+
| port | ΠΏΠΎΡΡ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ |
|
187
|
+
| user | ΠΈΠΌΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ |
|
188
|
+
| password | ΠΏΠ°ΡΠΎΠ»Ρ Π΄Π»Ρ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ |
|
189
|
+
| database | ΠΈΠΌΡ ΠΠ |
|
190
|
+
| model_name |ΠΈΠΌΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π΄Π»Ρ Π΄Π°ΠΌΠΏΠ° |
|
191
|
+
| field_name | ΠΈΠΌΡ ΠΏΠΎΠ»Ρ, ΠΏΠΎ ΠΊΠΎΡΠΎΡΠΎΠΌΡ Π±ΡΠ΄Π΅Ρ Π΄Π°ΠΌΠΏ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ - 'id' ΠΈΠ»ΠΈ 'admin_token', default='id') |
|
192
|
+
| field_values | Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ»Ρ field_name |
|
193
|
+
| debug_mode | ΡΠ΅ΠΆΠΈΠΌ ΠΎΡΠ»Π°Π΄ΠΊΠΈ (full Π²ΡΠ²ΠΎΠ΄ΠΈΡ Π²ΡΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ, short - ΠΊΠΎΡΠΎΡΠΊΠΈΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ, none - Π½ΠΈΡΠ΅Π³ΠΎ) |
|
194
|
+
| ask | Π·Π°ΠΏΡΠ°ΡΠΈΠ²Π°ΡΡ ΠΏΠΎΠ΄ΡΠ²Π΅ΡΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΏΡΠΈ ΡΠ°Π·Π»ΠΈΡΠΈΡΡ
Π² ΡΠ΅ΠΊΡΡΠ΅ΠΉ ΠΈ ΡΠ΄Π°Π»Π΅Π½Π½ΠΎΠΉ ΠΠ |
|
195
|
+
|
196
|
+
### ΠΡΠΈΠΌΠ΅ΡΡΠΈΠΊΠΈ
|
197
|
+
|
198
|
+
Π ΡΡΠΈΡ
ΠΏΡΠΈΠΌΠ΅ΡΠ°Ρ
Π½Π΅ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎ ΠΌΠ΅Π½ΡΡΡ `fury_dumper.yml` ΠΊΠΎΠ½ΡΠΈΠ³, Π²ΠΎΠ·ΠΌΠΈΡΠ΅ [Π΄Π΅ΡΠΎΠ»ΡΠ½ΡΠΉ](README.ru.md#ΠΊΠΎΠ½ΡΠΈΠ³ΠΈ).
|
199
|
+
|
200
|
+
ΠΠ°ΠΌΠΏ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΏΠΎ admin_token:
|
201
|
+
```ruby
|
202
|
+
FuryDumper.dump(password: 'password',
|
203
|
+
host: 'localhost',
|
204
|
+
port: '5632',
|
205
|
+
user: 'username',
|
206
|
+
model_name: 'User',
|
207
|
+
field_name: 'admin_token',
|
208
|
+
field_values: [admin_token_value],
|
209
|
+
database: 'staging',
|
210
|
+
debug_mode: :short)
|
211
|
+
```
|
212
|
+
ΠΠ°ΠΌΠΏ 1000 ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΉ (Π·Π΄Π΅ΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄ΠΊΡΡΡΠΈΡΡ batch_size - ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ batch_size = 100, ΡΡΠΎΠ± Π΄Π°ΠΌΠΏΠ΅Ρ ΠΎΡΡΠ°Π±ΠΎΡΠ°Π» Π½Π΅ 10 ΡΠ°Π·):
|
213
|
+
```ruby
|
214
|
+
FuryDumper.dump(password: 'password',
|
215
|
+
host: 'localhost',
|
216
|
+
port: '5632',
|
217
|
+
user: 'username',
|
218
|
+
model_name: 'User',
|
219
|
+
field_values: (500..1500),
|
220
|
+
database: 'staging',
|
221
|
+
debug_mode: :short)
|
222
|
+
```
|
223
|
+
ΠΠ°ΠΌΠΏ AdminUser:
|
224
|
+
```ruby
|
225
|
+
FuryDumper.dump(password: 'password',
|
226
|
+
host: 'localhost',
|
227
|
+
port: '5632',
|
228
|
+
user: 'username',
|
229
|
+
model_name: 'AdminUser',
|
230
|
+
field_values: 3368,
|
231
|
+
database: 'staging',
|
232
|
+
debug_mode: :short)
|
233
|
+
```
|
234
|
+
|
235
|
+
ΠΠ°ΠΌΠΏ ΡΠΎ ΡΡΠ΅ΠΉΠ΄ΠΆΠ°:
|
236
|
+
|
237
|
+
```bash
|
238
|
+
ssh -NL <port>:<host>:<hostport> username@<host>
|
239
|
+
```
|
240
|
+
|
241
|
+
```ruby
|
242
|
+
FuryDumper.dump(password: 'password',
|
243
|
+
host: 'localhost',
|
244
|
+
port: '5632',
|
245
|
+
user: 'username',
|
246
|
+
model_name: 'User',
|
247
|
+
field_values: 1,
|
248
|
+
database: 'staging',
|
249
|
+
debug_mode: :short)
|
250
|
+
```
|
251
|
+
ΠΠ°ΠΌΠΏ Ρ ΡΠ΅ΠΏΠ»ΠΈΠΊΠΈ ΠΏΡΠΎΠ΄Π°:
|
252
|
+
|
253
|
+
```bash
|
254
|
+
ssh -NL <port>:<host>:<hostport> username@<host>
|
255
|
+
```
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
FuryDumper.dump(password: 'password',
|
259
|
+
host: 'localhost',
|
260
|
+
port: '5632',
|
261
|
+
user: 'username',
|
262
|
+
model_name: 'User',
|
263
|
+
field_values: 1,
|
264
|
+
database: 'production',
|
265
|
+
debug_mode: :short)
|
266
|
+
```
|
267
|
+
|
268
|
+
### Π‘ΡΠ°ΡΠΈΡΡΠΈΠΊΠ° π
|
269
|
+
|
270
|
+
Π‘ΡΠ°ΡΠΈΡΡΠΈΠΊΠ° Π΄Π°ΠΌΠΏΠ° Ρ ΡΠ΅ΠΏΠ»ΠΈΠΊΠΈ main service (ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ ΡΡΠ°Π½Π΄Π°ΡΡΠ½Π°Ρ, ΡΠΌ [ΡΡΠΎΡ ΠΊΠΎΠ½ΡΠΈΠ³](README.ru.md#ΠΊΠΎΠ½ΡΠΈΠ³ΠΈ))
|
271
|
+
|
272
|
+
| ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ user | ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ²ΡΠ·Π°Π½Π½ΡΡ
ΡΡΡΠ½ΠΎΡΡΠ΅ΠΉ | ΠΡΠ΅ΠΌΡ |
|
273
|
+
| --- | --- | --- |
|
274
|
+
| 1 | ~ 150* | 2 min 14 sec |
|
275
|
+
| 10 | ~ 3 500* | 6 min 15 sec |
|
276
|
+
| 100 | ~ 10 000* | 11 min 8 sec |
|
277
|
+
| 1 000 | ~ 10 000* | 16 min 6 sec |
|
278
|
+
|
279
|
+
\* ΠΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΡΠ°ΡΠ°ΡΡΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠ°Π· ΠΏΠΎ ΡΠ°Π·Π½ΡΠΌ ΠΏΡΡΡΠΌ ΠΈ ΠΌΠΎΠ³ΡΡ Π΄ΡΠ±Π»ΠΈΡΠΎΠ²Π°ΡΡΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠΎΠ±ΠΎΠΉ, ΠΈΠ·-Π·Π° ΡΡΠΎΠ³ΠΎ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½Π½ΠΎΠ΅ Π² ΡΠ°Π±Π»ΠΈΡΠ΅ ΡΠΈΡΠ»ΠΎ ΠΏΡΠΈΠΌΠ΅ΡΠ½ΠΎ ΡΠ°Π²Π½ΠΎ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Ρ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΡ
Π·Π°ΠΏΠΈΡΠ΅ΠΉ Π² ΠΠ.
|
280
|
+
|
281
|
+
ΠΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΠ΅: ΠΡΠ΅ΠΌΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΌΠΎΠΆΠ΅Ρ ΠΎΡΠ»ΠΈΡΠ°ΡΡΡΡ Π΄Π»Ρ ΡΠ°Π·Π½ΡΡ
ΡΠ·Π΅ΡΠΎΠ² Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²Π° ΡΠ²ΡΠ·Π°Π½Π½ΡΡ
ΡΡΡΠ½ΠΎΡΡΠ΅ΠΉ.
|
282
|
+
|
283
|
+
# ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ Π΄Π»Ρ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΎΠ²
|
284
|
+
|
285
|
+
Π‘ΠΎΠΊΡΠ°ΡΠ΅Π½ΠΈΡ Π΄Π»Ρ Π±ΠΎΠ»ΡΡΠ΅Π³ΠΎ ΡΠ΄ΠΎΠ±ΡΡΠ²Π°
|
286
|
+
* PK - primary key
|
287
|
+
* FK - foreign key
|
288
|
+
* remote DB - ΡΠ΄Π°Π»Π΅Π½Π½Π°Ρ ΠΠ, ΠΈΠ· ΠΊΠΎΡΠΎΡΠΎΠΉ Π±ΡΠ΄ΡΡ ΡΡΠ½ΡΡΡΡΡ Π΄Π°Π½ΡΠ΅
|
289
|
+
* target DB - ΡΠ΅ΠΊΡΡΠ°Ρ ΠΠ, Π² ΠΊΠΎΡΠΎΡΡΡ Π±ΡΠ΄Π΅Ρ ΠΎΡΡΡΠ΅ΡΡΠ²Π»Π΅Π½ΠΎ ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅
|
290
|
+
|
291
|
+
|
292
|
+
## ΠΠ±Ρ
ΠΎΠ΄ Π³ΡΠ°ΡΠ° ΡΠ²ΡΠ·Π΅ΠΉ
|
293
|
+
|
294
|
+
Π Π΄Π°Π½Π½ΡΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ ΡΠ΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΎ 2 Π²Π°ΡΠΈΠ°Π½ΡΠ° ΠΎΠ±Ρ
Π»Π΄Π° Π³ΡΠ°ΡΠ° ΡΠ²ΡΠ·Π΅ΠΉ - Π² Π³Π»ΡΠ±ΠΈΠ½Ρ ΠΈ Π² ΡΠΈΡΠΈΠ½Ρ.
|
295
|
+
|
296
|
+
### ΠΠ±Ρ
ΠΎΠ΄ Π² Π³Π»ΡΠ±ΠΈΠ½Ρ
|
297
|
+
|
298
|
+
ΠΠ°ΠΊ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π°Π»Π³ΠΎΡΠΈΡΠΌ Π²ΠΊΡΠ°ΡΡΠ΅:
|
299
|
+
|
300
|
+
1. ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»Ρ
|
301
|
+
2. ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ Π²ΡΠ΅ ΡΠ²ΡΠ·ΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ
|
302
|
+
3. ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ²ΡΠ·ΠΈ:
|
303
|
+
1. ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ Π²ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ (PK/FK, ΠΈΡ
Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΈ ΡΠ΄)
|
304
|
+
2. ΠΠ°ΠΌΠΏΠ°Π΅ΠΌ Π½Π°ΠΉΠ΄Π΅Π½Π½ΡΡ ΡΠ²ΡΠ·Ρ
|
305
|
+
|
306
|
+
Π’ΠΎ Π΅ΡΡΡ ΠΊΠ»Π°ΡΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΠΎΠ±Ρ
ΠΎΠ΄ Π² Π³Π»ΡΠ±ΠΈΠ½Ρ
|
307
|
+
|
308
|
+

|
309
|
+
|
310
|
+
### ΠΠ±Ρ
ΠΎΠ΄ Π² ΡΠΈΡΠΈΠ½Ρ
|
311
|
+
|
312
|
+
ΠΠ°ΠΊ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π°Π»Π³ΠΎΡΠΈΡΠΌ Π²ΠΊΡΠ°ΡΡΠ΅:
|
313
|
+
|
314
|
+
1. ΠΠΎΠ»ΡΡΠ°Π΅ΠΌ ΠΌΠΎΠ΄Π΅Π»Ρ Π΄Π»Ρ Π΄Π°ΠΌΠΏΠ° (Π²Ρ
ΠΎΠ΄Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅) ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ Π΅Π΅ Π² ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ
|
315
|
+
2. ΠΠΎΠΊΠ° Π² ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ Π΅ΡΡΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ
|
316
|
+
1. Π’Π΅ΠΊΡΡΠ΅ΠΉ ΠΌΠΎΠ΄Π΅Π»ΡΡ ΡΡΠΈΡΠ°Π΅ΠΌ ΠΏΠ΅ΡΠ²ΡΡ Π² ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ
|
317
|
+
2. ΠΠΎΠΏΠΈΡΡΠ΅ΠΌ Π΄Π°Π½Π½ΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ ΠΈΠ· remote DB
|
318
|
+
3. ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ²ΡΠ·ΠΈ Π΄Π°Π½Π½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ:
|
319
|
+
1. ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ Π²ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ (PK/FK, ΠΈΡ
Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΈ ΡΠ΄)
|
320
|
+
2. ΠΠΎΠΌΠ΅ΡΠ°Π΅ΠΌ ΡΠ²ΡΠ·Π°Π½Π½ΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ Π² ΠΊΠΎΠ½Π΅Ρ ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ
|
321
|
+
|
322
|
+
Π’ΠΎ Π΅ΡΡΡ ΠΊΠ»Π°ΡΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΠΎΠ±Ρ
ΠΎΠ΄ Π² ΡΠΈΡΠΈΠ½Ρ
|
323
|
+
|
324
|
+

|
325
|
+
|
326
|
+
ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Π΄Π°ΠΌΠΏΠ΅Ρ ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π² ΡΠΈΡΠΈΠ½Ρ. ΠΡΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ ΠΏΡΠΈΠ½ΡΡΠΎ, Π² ΡΠ²ΡΠ·ΠΈ c ΡΠ΅ΠΌ, ΡΡΠΎ Π΄Π°ΠΌΠΏΠ΅Ρ ΡΡΠΈΡΠ°Π΅Ρ Π±Π»ΠΈΠΆΠ½ΠΈΠ΅ ΡΠ²ΡΠ·ΠΈ Π±ΠΎΠ»Π΅Π΅ ΠΏΡΠΈΠΎΡΠΈΡΠ΅ΡΠ½ΡΠΌΠΈ.\
|
327
|
+
ΠΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ²Π½ΠΎ Π·Π°ΡΡΠ°Π²ΠΈΡΡ Π΄Π°ΠΌΠΏΠ΅Ρ ΡΠ°Π±ΠΎΡΠ°Ρ Π² Π³Π»ΡΠ±ΠΈΠ½Ρ, ΡΠΊΠ°Π·Π°Π² Π² ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠΌ ΡΠ°ΠΉΠ»Π΅ `fury_dumper.yml` ΡΡΡΠΎΠΊΡ `mode: depth`.
|
328
|
+
|
329
|
+
## ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠ²ΡΠ·Π΅ΠΉ Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ
|
330
|
+
|
331
|
+
Π£ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΠΌΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π΅ΡΡΡ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ ΡΠ²ΡΠ·Π΅ΠΉ, ΠΌΡ ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΠΌ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ Π²ΡΠ΅. ΠΠΎΡ ΡΠΏΠΈΡΠΎΠΊ ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΠΌΡΡ
ΡΠ²Π·ΡΠ΅ΠΉ:
|
332
|
+
* has_one ΠΈ has_many (ΡΠ°ΡΡΠΌΠ°ΡΡΠΈΠ²Π°Π΅ΠΌ Π²ΠΌΠ΅ΡΡΠ΅; has_one Π½Π΅ ΡΡΠΈΡΠ²Π°Π΅ΡΡΡ ΠΊΠ°ΠΊ LIMIT 1, ΡΠ°ΠΊΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²ΡΠ²Π°ΡΡΡ Π² has_many)
|
333
|
+
* belongs_to
|
334
|
+
* has_and_belongs_to_many
|
335
|
+
|
336
|
+
ΠΠΎ Π΅ΡΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ ΠΈΠ³Π½ΠΎΡΠΈΡΡΡΡΡΡ ΡΠ²ΡΠ·ΠΈ through.
|
337
|
+
|
338
|
+
Π Π½Π΅ΠΌΠ½ΠΎΠΆΠΊΠΎ ΠΎ ΡΠΊΠΎΡΠΏΠ°Ρ
Π² ΡΠ²ΡΠ·ΠΈ - ΠΎΠ½ΠΈ ΡΡΠΈΡΡΠ²Π°ΡΡΡΡ. ΠΠΎ Π΅ΡΠ»ΠΈ Π΅ΡΡΡ Π±ΠΎΠ»Π΅Π΅ ΡΠΈΡΠΎΠΊΠ°Ρ (ΠΏΠΎΠΊΡΡΠ²Π°ΡΡΠ°Ρ ΡΠ²ΡΠ·Ρ) - Π±Π΅Π· sΡope, ΡΠΎ Π±ΡΠ΄Π΅Ρ Π΄Π°ΠΌΠΏΠ°ΡΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΠΊΡΡΠ²Π°ΡΡΠ°Ρ ΡΠ²ΡΠ·Ρ.
|
339
|
+
|
340
|
+
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ - Ρ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π΅ΡΡΡ Π²ΡΠ΅ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΡ ΠΈ Π³Π»Π°Π²Π½ΡΠΉ Π΄ΠΎΠΊΡΠΌΠ΅Π½Ρ:
|
341
|
+
* has_many :documents, class_name: 'User::Document'\
|
342
|
+
* has_one :main_document, -> { main }, class_name: 'User::Document'
|
343
|
+
|
344
|
+
Π‘Π²ΡΠ·Ρ main_document Π½Π΅ Π±ΡΠ΄Π΅Ρ ΡΡΡΠ΅Π½Π° ΠΏΡΠΈ Π΄Π°ΠΌΠΏΠ΅ Π² ΡΠ²ΡΠ·ΠΈ Ρ ΡΠ΅ΠΌ, ΡΡΠΎ documents - ΠΏΠΎΠΊΡΡΠ²Π°ΡΡΠ°Ρ ΡΠ²ΡΠ·Ρ, ΡΠ°ΠΊ ΠΊΠ°ΠΊ Π±ΠΎΠ»Π΅Π΅ ΡΠΈΡΠΎΠΊΠ°Ρ ΠΈ Π±Π΅Π· sΡope.\
|
345
|
+
ΠΡΠ»ΠΈ Π±Ρ ΡΠ²ΡΠ·ΠΈ documents Π½Π΅ Π±ΡΠ»ΠΎ, main_document Π΄Π°ΠΌΠΏΠ°Π»Π°ΡΡ Π±Ρ Ρ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΠΌ.
|
346
|
+
|
347
|
+
Π’Π°ΠΊΠΆΠ΅ Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ ΡΡΠΈΡΡΠ²Π°ΡΡΡΡ ΠΏΠΎΠ»ΠΈΠΌΠΎΡΡΠ½ΡΠ΅ ΡΠ²ΡΠ·ΠΈ ( `belongs_to :resource, polymorphic: true` ΠΈ `has_many :devices, as: :owner` ).
|
348
|
+
|
349
|
+
### ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠ²ΡΠ·Π΅ΠΉ has_and_belongs_to_many
|
350
|
+
|
351
|
+
Π‘Π²ΡΠ·ΠΈ has_and_belongs_to_many ΠΈΠΌΠ΅ΡΡ ΠΏΡΠΎΠΊΡΠΈΡΡΡΡΡΡ ΡΠ°Π±Π»ΠΈΡΡ, ΠΊΠΎΡΠΎΡΡΡ ΡΠΎΠΆΠ΅ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ ΡΠ΄Π°ΠΌΠΏΠ°ΡΡ. ΠΡΠΎ ΠΏΡΠΎΠΈΡΡ
ΠΎΠ΄ΠΈΡ Π² ΠΌΠΎΠΌΠ΅Π½Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΌΠΎΠ΄Π΅Π»ΠΈ Ρ ΠΊΠΎΡΠΎΡΠΎΠΉ Π΅ΡΡΡ Π΄Π°Π½Π½Π°Ρ ΡΠ²ΡΠ·Ρ.
|
352
|
+
|
353
|
+
### ΠΡΠΎΠ±Π΅Π½Π½ΠΎΡΡΠΈ ΡΠ°Π±ΠΎΡΡ c as-ΡΠ²ΡΠ·ΡΠΌΠΈ
|
354
|
+
|
355
|
+
Π‘Π²ΡΠ·ΠΈ ΡΠΈΠΏΠ° as ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡΡΡ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΎΡΠ»ΠΈΡΠ½ΠΎ ΠΎΡ ΠΎΡΡΠ°Π»ΡΠ½ΡΡ
. Π ΡΠ²ΡΠ·ΠΈ Ρ ΡΠ΅ΠΌ, ΡΡΠΎ ΠΊ ΡΡΠΎΠΉ ΡΠ°Π±Π»ΠΈΡΡ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²ΠΎ ΡΠ²ΡΠ·Π΅ΠΉ ΠΈ ΠΎΠ½ΠΈ Π½Π΅ Π±ΡΠ΄ΡΡ Π΄ΡΠ±Π»ΠΈΡΡΡΡΠΈΠΌΠΈΡΡ, Π½Π΅ΡΡ ΠΊΠ°ΠΆΠ΄Π°Ρ ΡΠ²ΠΎΠΉ ΡΠΌΡΡΠ» ΠΈ ΠΏΠΎΡΠ΅ΡΡΡΡ ΠΈΡ
Π½Π΅Π»ΡΠ·Ρ.\
|
356
|
+
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, ΡΠ²ΡΠ·Ρ Π΄Π»Ρ ΡΠ·Π΅ΡΠ° `has_many :devices, as: :owner` ΠΌΠΎΠΆΠ΅Ρ ΠΏΡΠΈΡΡΡΡΡΠ²ΠΎΠ²Π°ΡΡ ΠΈ Ρ Π»ΠΈΠ΄Π°. Π Π² ΠΈΠ΄Π΅Π°Π»ΡΠΎΠΉ Π²ΡΠ΅Π»Π΅Π½Π½ΠΎΠΉ π¦ Π½ΡΠΆΠ½ΠΎ Π²ΡΡΠ°ΡΠΈΡΡ ΠΎΠ±Π΅.\
|
357
|
+
ΠΠ»Ρ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ± Π΄Π°ΠΌΠΏΠ°ΡΡ ΠΎΠ±Π΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ, Π±ΡΠ»ΠΎ ΠΏΡΠΈΠ½ΡΡΠΎ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π·Π°ΠΏΠΈΡΡΠ²Π°ΡΡ ΠΏΡΡΡ ΡΠ²ΡΠ·Π΅ΠΉ (ΡΠΎΠ»ΡΠΊΠΎ as) ΠΏΠΎ ΠΊΠΎΡΠΎΡΠΎΠΉ ΠΏΡΠΈΡΠ»Π° ΠΌΠΎΠ΄Π΅Π»Ρ. Π Π΅ΡΠ»ΠΈ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· ΠΏΡΡΠ΅ΠΉ ΡΠ²Π»ΡΠ΅ΡΡΡ ΠΏΠΎΠ΄ΠΏΡΡΠ΅ΠΌ Π΄Π»Ρ Π΄ΡΡΠ³ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ, ΡΠΎ ΠΎΠ½ΠΈ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΡΠ΅ ΠΈ Π½Π΅ Π±ΡΠ΄ΡΡ Π΄Π°ΠΌΠΏΠ°ΡΡΡΡ.
|
358
|
+
|
359
|
+
## Π Π΅ΠΆΠΈΠΌ Π±ΡΡΡΡΡΡ
Π·Π°ΠΏΡΠΎΠΎΠ²
|
360
|
+
|
361
|
+
Π Π΅ΠΆΠΈΠΌ Π±ΡΡΡΡΡΡ
sql-Π·Π°ΠΏΡΠΎΡΠΎΠ² ΡΠ°Π±ΠΎΠ°ΡΠ΅Ρ Π±Π΅Π· ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠΈ ΠΏΠΎ ΠΏΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠΌΡ ΠΊΠ»ΡΡΡ. ΠΡΠ»ΠΈ Π²Ρ Ρ
ΠΎΡΠΈΡΠ΅ ΡΠ΄Π°ΠΌΠΏΠ°ΡΡ **ΠΏΠΎΡΠ»Π΅Π΄Π½ΠΈΠ΅** Π·Π°ΠΏΠΈΡΠΈ Π² ΠΌΠΎΠ΄Π΅Π»ΠΈ, ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ `fast: false` Π² ΠΊΠΎΠ½ΡΠΈΠ³Π΅. \
|
362
|
+
Π Π±ΡΡΡΡΠΎΠΌ ΡΠ΅ΠΆΠΈΠΌΠ΅ sql Π·Π°ΠΏΡΠΎΡΡ Π²ΡΠ³Π»ΡΠ΄ΡΡ ΡΠ°ΠΊ:
|
363
|
+
```sql
|
364
|
+
SELECT * FROM table WHERE fk_id IN (...) LIMIT 1000;
|
365
|
+
```
|
366
|
+
Π Π½Π΅ Π±ΡΡΡΡΠΎΠΌ ΡΠ΅ΠΆΠΈΠΌΠ΅ sql Π·Π°ΠΏΡΠΎΡΡ Π²ΡΠ³Π»ΡΠ΄ΡΡ ΡΠ°ΠΊ:
|
367
|
+
```sql
|
368
|
+
SELECT * FROM table WHERE fk_id IN (...) ORDER BY table.id LIMIT 1000
|
369
|
+
```
|
370
|
+
ΠΠΎ Π½Π΅Π±ΡΡΡΡΡΠΉ ΡΠ΅ΠΆΠΈΠΌ Π΄Π΅Π»Π°Π΅Ρ Π·Π°ΠΏΡΠΎΡΡ ΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅ ΠΈΠ·-Π·Π° ΡΠΎΠ³ΠΎ, ΡΡΠΎ pg-ΠΏΠ»Π°Π½ΠΈΡΠΎΠ²ΡΠΈΠΊ ΡΡΡΠΎΠΈΡ Π·Π°ΠΏΡΠΎΡ ΠΏΠΎ ΠΈΠ½Π΄Π΅ΠΊΡΡ ΠΏΠ΅ΡΠ²ΠΈΡΠ½ΠΎΠ³ΠΎ ΠΊΠ»ΡΡΠ°, Π° fk_id IN (...) ΡΠΈΠ»ΡΡΡΡΠ΅Ρ ΠΏΡΠΈ ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠ΅, ΡΡΠΎ ΡΠ°Π±ΠΎΡΠ΅Ρ Π΄ΠΎΠ»ΡΡΠ΅.
|
371
|
+
|
372
|
+
## ΠΡΠ°ΡΠΊΠΎ ΠΎ ΠΊΠ»Π°ΡΡΠ°Ρ
|
373
|
+
|
374
|
+
* FuryDumper - ΠΈΠ½ΠΈΡΠΈΠΈΡΡΠ΅Ρ ΠΏΡΠΎΡΠ΅ΡΡ Π΄Π°ΠΌΠΏΠ°, ΠΎΡΡΡΠ΅ΡΡΠ²Π»ΡΠ΅Ρ Π±Π°ΡΡΠΈΠ½Π³ Π½Π° ΠΏΠ΅ΡΠ²ΠΎΠΉ ΠΈΡΠ΅ΡΠ°ΡΠΈΠΈ
|
375
|
+
* FuryDumper::Dumper - ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠ»Π°ΡΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΎΡΡΡΠ΅ΡΡΠ²Π»ΡΠ΅Ρ ΠΏΡΠΎΡΠ΅ΡΡ Π΄Π°ΠΌΠΏΠ°, Π·Π΄Π°ΡΡ Π»Π΅ΠΆΠΈΡ ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ Π°Π»Π³ΠΎΡΠΈΡΠΌ ΠΎΠ±Ρ
ΠΎΠ΄Π° ΡΠ²ΡΠ·Π΅ΠΉ
|
376
|
+
* FuryDumper::Dumpers::Model - ΠΊΠ»Π°ΡΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ
|
377
|
+
* FuryDumper::Dumpers::ModelQueue - ΠΎΡΠ΅ΡΠ΅Π΄Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π΄Π»Ρ Π΄Π°ΠΌΠΏΠ° Π² ΡΠΈΡΠΈΠ½Ρ
|
378
|
+
* FuryDumper::Dumpers::DumpState - ΠΊΠ»Π°ΡΡ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ Π΄Π°ΠΌΠΏΠ°, ΡΡΡ Ρ
ΡΠ°Π½ΠΈΡΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΡΠ΅Ρ
ΠΌΠΎΠ΄Π΅Π»ΡΡ
, ΡΡΠΎ ΡΠΆΠ΅ Π΄Π°ΠΌΠΏΠ°Π»ΠΈ ΠΈ ΠΏΠΎΠ΄Π²ΠΎΠ΄ΠΈΡΡΡ Π½Π΅Π±ΠΎΠ»ΡΡΠ°Ρ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ° ΠΏΠΎ Π΄Π°ΠΌΠΏΡ
|
379
|
+
* FuryDumper::Dumpers::RelationItem - ΡΡΡΡΠΊΡΡΡΠ° ΡΠ²ΡΠ·ΠΈ - ΠΊΠ»ΡΡΠΈ ΠΈ Π·Π½Π°ΡΠ΅Π½ΠΈΡ, ΠΏΠΎ ΠΊΠΎΡΠΎΡΡΠΌ Π΄Π°ΠΌΠΏΠ°Π»ΠΈ. ΠΠ»Ρ ΠΎΠ±ΡΡΠ½ΡΡ
ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Π² RelationItem ΡΡΠ°Π²Π½ΠΈΠ²Π°Π΅ΡΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠΎΠ±ΠΎΠΉ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎ ΠΊΠ»ΡΡΠ°ΠΌ. Additional ΠΎΠΏΡΠΈΡ Π΄Π°Π΅Ρ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΡΡΠ°Π²Π½ΠΈΡΡ ΠΏΠΎ ΠΊΠ»ΡΡΡ ΠΈ Π·Π½Π°ΡΠ΅Π½ΠΈΡ. Complex - ΡΠ²Π½ΠΎ Π³ΠΎΠ²ΠΎΡΠΈΡ ΠΎ ΡΠΎΠΌ, ΡΡΠΎ Π±ΡΠ΄Π΅Ρ ΡΠΎΠ»ΡΠΊΠΎ ΠΊΠ»ΡΡ, ΡΠΎ Π΅ΡΡΡ Π² ΠΊΠ»ΡΡΠ΅ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡΡΡ ΡΡΡΠΎΠΊΠ° ΡΠΈΠΏΠ° `date_from IS NULL`, ΡΠ²Π»ΡΡΡΠ°ΡΡΡ ΡΡΠ»ΠΎΠ²ΠΈΠ΅ΠΌ Π΄Π»Ρ ΡΠ²ΡΠ·ΠΈ.
|
380
|
+
* FuryDumper::Api - ΠΊΠ»Π°ΡΡ Π΄Π»Ρ ΡΠ²ΡΠ·ΠΈ Ρ ΠΌΠΈΠΊΡΠΎΡΠ΅ΡΠ²ΠΈΡΠ°ΠΌΠΈ
|
381
|
+
* FuryDumper::Config - ΠΊΠ»Π°ΡΡ ΠΊΠΎΠ½ΡΠΈΠ³Π°
|
382
|
+
* FuryDumper::Encrypter - ΠΊΠ»Π°ΡΡ Π΄Π»Ρ ΡΠΈΡΡΠΎΠ²Π°Π½ΠΈΡ ΠΏΠ°ΡΠΎΠ»Π΅ΠΉ
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FuryDumper
|
4
|
+
class DumpProcessController < ApplicationController
|
5
|
+
def dump
|
6
|
+
data = JSON.parse(request.body.read)
|
7
|
+
FuryDumper.dump(password: Encrypter.decrypt(data['password']),
|
8
|
+
host: data['host'],
|
9
|
+
port: data['port'],
|
10
|
+
user: data['user'],
|
11
|
+
database: data['database'],
|
12
|
+
model_name: data['model_name'],
|
13
|
+
field_values: data['field_values'],
|
14
|
+
field_name: data['field_name'],
|
15
|
+
debug_mode: :none,
|
16
|
+
ask: false)
|
17
|
+
|
18
|
+
render json: { message: :ok }
|
19
|
+
end
|
20
|
+
|
21
|
+
def health
|
22
|
+
render json: { message: :ok }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/config/routes.rb
ADDED
data/fury_dumper.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/fury_dumper/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'fury_dumper'
|
7
|
+
spec.version = FuryDumper::VERSION
|
8
|
+
spec.authors = ['Nastya Patutina']
|
9
|
+
spec.email = ['npatutina@gmail.con']
|
10
|
+
|
11
|
+
spec.summary = 'Simple dump for main service and other microservices'
|
12
|
+
spec.description = 'Dump from remote DB by lead_ids interval'
|
13
|
+
spec.homepage = 'https://github.com/NastyaPatutina/fury_dumper'
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0') # rubocop:disable Gemspec/RequiredRubyVersion
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/NastyaPatutina/fury_dumper'
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
22
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
end
|
24
|
+
spec.bindir = 'exe'
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ['lib']
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
31
|
+
|
32
|
+
spec.add_runtime_dependency 'highline', '~> 1.6'
|
33
|
+
spec.add_runtime_dependency 'httpclient', '~> 2.8'
|
34
|
+
spec.add_runtime_dependency 'pg', '~> 1.4'
|
35
|
+
spec.add_runtime_dependency 'rails', '~> 5.0', '>= 4.0.13'
|
36
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
37
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FuryDumper
|
4
|
+
class Api
|
5
|
+
HEALTH_URL = 'fury_dumper/health'
|
6
|
+
|
7
|
+
# @param ms_name[String] - name of microservice for request
|
8
|
+
def initialize(ms_name)
|
9
|
+
@ms_name = ms_name
|
10
|
+
@http_client = init_http_client(ms_name)
|
11
|
+
@ms_config = FuryDumper::Config.fetch_service_config(@ms_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Send dumping request to microservice
|
15
|
+
#
|
16
|
+
# @param ms_model[String] - name of table to start dumping
|
17
|
+
# @param ms_field_name[String] - field in table for find records for dump
|
18
|
+
# @param field_values[Array] - values of access_way for dumping
|
19
|
+
#
|
20
|
+
# @example FuryDumper::Dumper.dump("users", "id", [1,2,3])
|
21
|
+
def send_request(ms_model, ms_field_name, field_values)
|
22
|
+
# Check gem is included to microservice(ms)
|
23
|
+
return unless check_ms_health
|
24
|
+
|
25
|
+
message = {
|
26
|
+
model_name: ms_model,
|
27
|
+
field_name: ms_field_name,
|
28
|
+
field_values: field_values,
|
29
|
+
password: Encrypter.encrypt(@ms_config['password']),
|
30
|
+
host: @ms_config['host'],
|
31
|
+
port: @ms_config['port'],
|
32
|
+
user: @ms_config['user'],
|
33
|
+
database: @ms_config['database']
|
34
|
+
}.to_json
|
35
|
+
|
36
|
+
response = @http_client.post('fury_dumper/dump', message)
|
37
|
+
|
38
|
+
ok_responce?(response)
|
39
|
+
rescue StandardError => e
|
40
|
+
notify_error(e)
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_ms_health
|
45
|
+
response = @http_client.get('fury_dumper/health')
|
46
|
+
|
47
|
+
ok_responce?(response)
|
48
|
+
rescue StandardError => e
|
49
|
+
notify_error(e)
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
def notify_error(error)
|
54
|
+
context = { error: error }
|
55
|
+
BugTracker.notify error_message: "ΠΠ΅ ΡΠΌΠΎΠ³Π»ΠΈ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π΄Π°Π½Π½ΡΠ΅ ΠΈΠ· #{@ms_name}", context: context
|
56
|
+
end
|
57
|
+
|
58
|
+
def init_http_client(ms_name)
|
59
|
+
base_url = Rails.application.class.parent_name.constantize.config.deep_symbolize_keys[ms_name.to_sym][:endpoint]
|
60
|
+
HTTPClient.new(base_url: base_url, default_header: default_header)
|
61
|
+
rescue StandardError => e
|
62
|
+
notify_error(e)
|
63
|
+
nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_header
|
67
|
+
{
|
68
|
+
'Content-Type' => 'application/x-www-form-urlencoded, charset=utf-8',
|
69
|
+
'Authorization' => 'Bearer 40637702df32be88886c7083c4fdb075',
|
70
|
+
'Accept' => 'application/x-protobuf,application/json'
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def ok_responce?(response)
|
75
|
+
unless response.status == 200
|
76
|
+
raise "[#{@ms_name}] invalid response status => #{response.status}/#{response.body.inspect}"
|
77
|
+
end
|
78
|
+
|
79
|
+
true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module FuryDumper
|
6
|
+
class Config
|
7
|
+
MODES = %i[wide depth].freeze
|
8
|
+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE', 'off', 'OFF'].freeze
|
9
|
+
|
10
|
+
def self.config
|
11
|
+
@config || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load(file)
|
15
|
+
@config = ::YAML.safe_load(file.respond_to?(:read) ? file : File.open(file))
|
16
|
+
validate_config
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.tables
|
20
|
+
return @tables if @tables
|
21
|
+
|
22
|
+
@tables = []
|
23
|
+
relative_services&.each do |_ms_name, ms_config|
|
24
|
+
@tables += ms_config['tables'].keys
|
25
|
+
end
|
26
|
+
@tables
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.batch_size
|
30
|
+
@batch_size ||= (config['batch_size'] || 100).to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.limit
|
34
|
+
batch_size * ratio_records_batches
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.ms_relations?(table_name)
|
38
|
+
tables.include?(table_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.exclude_relation?(relation_name)
|
42
|
+
exclude_relations.include?(relation_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.mode
|
46
|
+
@mode ||= config['mode'].to_sym if !@mode && MODES.include?(config['mode']&.to_sym)
|
47
|
+
|
48
|
+
@mode ||= :wide
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.fetch_service_config(ms_name)
|
52
|
+
relative_services[ms_name]
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.relative_services
|
56
|
+
config['relative_services']
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.fast?
|
60
|
+
!config['fast'].in?(FALSE_VALUES)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.validate_config
|
64
|
+
return true unless relative_services
|
65
|
+
|
66
|
+
relative_services.each do |ms_name, ms_config|
|
67
|
+
check_presented(ms_config, "[#{ms_name}]")
|
68
|
+
%w[database host port user password].each do |required_field|
|
69
|
+
check_required_key(ms_config, required_field, "[#{ms_name}]")
|
70
|
+
end
|
71
|
+
|
72
|
+
check_presented(ms_config['tables'], "[#{ms_name}] tables")
|
73
|
+
validate_tables_config(ms_config['tables'], ms_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.validate_tables_config(config, ms_name)
|
80
|
+
config.each do |this_table, table_config|
|
81
|
+
check_presented(table_config, "[#{ms_name}] -> #{this_table}")
|
82
|
+
|
83
|
+
table_config.each do |ms_table, ms_table_config|
|
84
|
+
check_presented(ms_table_config, "[#{ms_name}] -> #{this_table} -> #{ms_table}")
|
85
|
+
|
86
|
+
%w[self_field_name ms_model_name ms_field_name].each do |required_field|
|
87
|
+
check_required_key(ms_table_config, required_field, "[#{ms_name}] -> #{this_table} -> #{ms_table}")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.check_presented(config, prefix)
|
94
|
+
return if config.present?
|
95
|
+
|
96
|
+
raise "Configuration error! #{prefix} isn't describe"
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.check_required_key(config, field, prefix)
|
100
|
+
return if config[field]
|
101
|
+
|
102
|
+
raise "Configuration error! #{prefix} #{field} expected"
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.ratio_records_batches
|
106
|
+
@ratio_records_batches ||= (config['ratio_records_batches'] || 10).to_i
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.exclude_relations
|
110
|
+
@exclude_relations ||= config['exclude_relations']&.split(',')&.map(&:strip) || []
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|