fury_dumper 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Depth_first_example](Depth-first.png)
|
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
|
+
![Breadth_first_example](Breadth-first.png)
|
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
|