master_data_tool 0.18.0 → 0.19.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: 553fcd688f3ae346cc356961473852142c87f0ee66145b9e1892bfac3e230927
4
- data.tar.gz: 64813eea92f8afc4612cdeb19f281c11ecef5537a207a736cd38ef68d57d9adf
3
+ metadata.gz: 5d77c4691ca7880f5b1ab73c4d0e5d424e743cb2973e88cb2fc45e7d15cf7acf
4
+ data.tar.gz: a18d5f0ec46051a0c45db4e369270a5387a827cafa6b17760ead426152a1fd3e
5
5
  SHA512:
6
- metadata.gz: 9b617aed72fbd9bc0a355e81baef951c4f7f3d4cdf3838cf80b7e35533c98ba4fdfc0c01137d6b28e81f4d60798f21c4b81c94f1c53badba689edfe6d9c0c117
7
- data.tar.gz: 0d1daa98e982a6bb918d6dc63dde683b8ce65181337a6fb1754a124d7f93d0e6daa7b25e5cfa5f31a16261c8c4624d6544313a72105dff7746d9df69c28277d5
6
+ metadata.gz: 644b4a2322932c327a75d1cd955458689e4e08151301cbb1f5782a7465a62bfc80ba823774b0d77b2a525ce9cbd68dd28e6a14b354473608c4a7b61ef4cbf9b1
7
+ data.tar.gz: 91eb8811ca518eb91311c2d4a50dea7bb778edfa7f106e0d6d09e6bc5b866d4e12c6375936aa31f02f918c73979e9b81fa1038531f1ca9281e6a80d246516aa7
data/README.md CHANGED
@@ -35,18 +35,18 @@ Or install it yourself as:
35
35
 
36
36
  ### マスタデータの投入
37
37
 
38
- | option | default | 内容 |
39
- |----------------------| --- |-----------------------------------------------------------------|
40
- | --dry-run | true | dry-runモードで実行する(データ変更は行わない) |
41
- | --verify | true | データ投入後に全テーブル・全レコードのバリデーションチェックを行う |
42
- | --only-import-tables | [] | 指定したテーブルのみデータ投入を行う |
43
- | --except-import-tables | [] | 指定したテーブルのデータ投入を行わない |
44
- | --only-verify-tables | [] | 指定したテーブルのみ投入後のバリデーションチェックを行う |
45
- | --except-verify-tables | [] | 指定したテーブルのバリデーションチェックを行わない |
46
- | --skip-no-change | true | CSVファイルに更新がないテーブルをスキップする |
47
- | --silent | false | 結果の出力をやめる |
38
+ | option | default | 内容 |
39
+ |---------------------------------| --- |-----------------------------------------------------------------|
40
+ | --dry-run | true | dry-runモードで実行する(データ変更は行わない) |
41
+ | --verify | true | データ投入後に全テーブル・全レコードのバリデーションチェックを行う |
42
+ | --only-import-tables | [] | 指定したテーブルのみデータ投入を行う |
43
+ | --except-import-tables | [] | 指定したテーブルのデータ投入を行わない |
44
+ | --only-verify-tables | [] | 指定したテーブルのみ投入後のバリデーションチェックを行う |
45
+ | --except-verify-tables | [] | 指定したテーブルのバリデーションチェックを行わない |
46
+ | --skip-no-change | true | CSVファイルに更新がないテーブルをスキップする |
47
+ | --silent | false | 結果の出力をやめる |
48
48
  | --delete-all-ignore-foreign-key | false | 外部キー制約を無視してレコードを消すかどうか |
49
- | --override_identifier | nil | fixtures/#{override_identifier} のディレクトリにある内容でfixturesを上書きして投入する |
49
+ | --override-identifier | nil | fixtures/#{override_identifier} のディレクトリにある内容でfixturesを上書きして投入する |
50
50
 
51
51
  ```bash
52
52
  bundle exec master_data_tool import
@@ -27,11 +27,13 @@ module MasterDataTool
27
27
  @override_identifier = override_identifier
28
28
  @report_printer = report_printer
29
29
  @report_printer.silent = silent
30
+ @master_data_statuses = []
30
31
  end
31
32
 
32
33
  def execute
33
34
  ApplicationRecord.transaction do
34
35
  print_execute_options
36
+ load_master_data_statuses
35
37
 
36
38
  master_data_collection = build_master_data_collection
37
39
 
@@ -51,6 +53,8 @@ module MasterDataTool
51
53
 
52
54
  private
53
55
 
56
+ attr_reader :master_data_statuses
57
+
54
58
  def print_execute_options
55
59
  return if @silent
56
60
 
@@ -115,7 +119,10 @@ module MasterDataTool
115
119
  return true if import_skip_table?(master_data_file.table_name)
116
120
  return false unless @skip_no_change
117
121
 
118
- !MasterDataTool::MasterDataStatus.master_data_will_change?(master_data_file)
122
+ master_data_status = master_data_statuses.dig(master_data_file.table_name)
123
+ return false unless master_data_status
124
+
125
+ !master_data_status.will_change?(master_data_file)
119
126
  end
120
127
 
121
128
  def import_skip_table?(table_name)
@@ -152,6 +159,10 @@ module MasterDataTool
152
159
  pattern = Pathname.new(MasterDataTool.config.master_data_dir).join(@override_identifier).join('*.csv').to_s
153
160
  Pathname.glob(pattern).select(&:file?)
154
161
  end
162
+
163
+ def load_master_data_statuses
164
+ @master_data_statuses = MasterDataTool::MasterDataStatus.fetch_all
165
+ end
155
166
  end
156
167
  end
157
168
  end
@@ -142,9 +142,13 @@ module MasterDataTool
142
142
  scoped.find_each do |record|
143
143
  valid = record.valid?
144
144
  report.append(MasterDataTool::Report::VerifyReport.build_verify_record_report(self, record, valid))
145
+ next if valid
145
146
  next if ignore_fail
146
147
 
147
- raise MasterDataTool::VerifyFailed.new("[#{table_name}] id = #{record.id} is invalid") unless valid
148
+ e = MasterDataTool::VerifyFailed.new("[#{table_name}] id = #{record.id} is invalid")
149
+ e.errors = record.errors
150
+
151
+ raise e
148
152
  end
149
153
  end
150
154
  end
@@ -14,7 +14,17 @@ module MasterDataTool
14
14
  validates :version,
15
15
  presence: true
16
16
 
17
+ def will_change?(master_data_file)
18
+ raise unless name == master_data_file.table_name
19
+
20
+ version != self.class.decide_version(master_data_file.path)
21
+ end
22
+
17
23
  class << self
24
+ def fetch_all
25
+ all.index_by(&:name)
26
+ end
27
+
18
28
  def build(master_data_file)
19
29
  version = decide_version(master_data_file.path)
20
30
  new(name: MasterDataTool.resolve_table_name(master_data_file.path, master_data_file.override_identifier), version: version)
@@ -23,15 +33,10 @@ module MasterDataTool
23
33
  def import_records!(records, dry_run: true)
24
34
  if dry_run
25
35
  pp records
26
- else
27
- import!(records, validate: true, on_duplicate_key_update: %w[name version], timestamps: true)
36
+ return
28
37
  end
29
- end
30
38
 
31
- # @param [MasterDataTool::MasterDataFile] master_data_file
32
- def master_data_will_change?(master_data_file)
33
- new_version = decide_version(master_data_file.path)
34
- !where(name: master_data_file.table_name, version: new_version).exists?
39
+ import!(records, validate: true, on_duplicate_key_update: %w[name version], timestamps: true)
35
40
  end
36
41
 
37
42
  def decide_version(csv_path)
@@ -7,6 +7,7 @@ module MasterDataTool
7
7
 
8
8
  def print(message)
9
9
  return if @silent
10
+ return if message.blank?
10
11
 
11
12
  MasterDataTool.config.logger.info message
12
13
  puts message
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MasterDataTool
4
- VERSION = "0.18.0"
4
+ VERSION = "0.19.0"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'csv'
4
+ require 'socket'
4
5
  require_relative "master_data_tool/version"
5
6
  require_relative "master_data_tool/config"
6
7
  require_relative "master_data_tool/master_data_status"
@@ -15,9 +16,13 @@ require_relative "master_data_tool/import"
15
16
  module MasterDataTool
16
17
  class Error < StandardError; end
17
18
  class DryRunError < StandardError; end
18
- class VerifyFailed < StandardError; end
19
19
  class NotLoadedError < StandardError; end
20
20
 
21
+ class VerifyFailed < StandardError
22
+ attr_accessor :errors
23
+ delegate :full_messages, to: :errors
24
+ end
25
+
21
26
  class << self
22
27
  def config
23
28
  @config ||= Config.new
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ CURRENT=$(cd $(dirname $0);pwd)
5
+
6
+ mysql \
7
+ -u ${DB_USERNAME} \
8
+ -h ${DB_HOST} \
9
+ -p${DB_PASSWORD} \
10
+ --port ${DB_PORT} \
11
+ -e "DROP DATABASE ${DB_NAME}"
@@ -1,4 +1,230 @@
1
+ # TypeProf 0.21.3
2
+
3
+ # Classes
1
4
  module MasterDataTool
2
5
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
6
+ self.@config: Config
7
+
8
+ def self.config: -> Config
9
+ def self.configure: -> untyped
10
+ def self.resolve_table_name: (Pathname csv_path, String? override_identifier) -> String
11
+
12
+ class Config
13
+ def initialize: -> void
14
+ end
15
+
16
+ class MasterDataStatus
17
+ def will_change?: (MasterDataFile master_data_file) -> bool
18
+ def self.fetch_all: -> Hash[String,MasterDataStatus]
19
+ def self.build: (MasterDataFile master_data_file) -> MasterDataStatus
20
+ def self.import_records!: (Array[MasterDataStatus] records, dry_run: bool) -> Array[MasterDataStatus]
21
+ def self.master_data_will_change?: (MasterDataFile master_data_file) -> bool
22
+ def self.decide_version: (Pathname csv_path) -> String
23
+ end
24
+
25
+ class MasterDataFile
26
+ attr_reader table_name: String
27
+ attr_reader path: Pathname
28
+ attr_reader override_identifier: String?
29
+ def initialize: (String table_name, Pathname path, String? override_identifier) -> void
30
+ def self.build: (Pathname path, String? override_identifier) -> MasterDataFile
31
+ def basename: -> Pathname
32
+ def ==: (untyped other) -> bool
33
+ alias eql? ==
34
+ def hash: -> Integer
35
+ end
36
+
37
+ class MasterDataFileCollection
38
+ @override_identifier: String?
39
+ @collection: Array[MasterDataFile]
40
+
41
+ def initialize: (override_identifier: String?) -> void
42
+ def each: ?{ -> Array[MasterDataFile] } -> Enumerator[bot, untyped]
43
+ def to_a: -> Array[MasterDataFile]
44
+
45
+ private
46
+ def build: -> Array[MasterDataFile]
47
+ def extract_master_data_csv_paths: -> Array[MasterDataFile]
48
+ def overridden_master_data_csv_paths: -> Array[MasterDataFile]
49
+ end
50
+
51
+ class MasterData
52
+ @loaded: bool
53
+ @affected: bool
54
+ @preload_associations: Array[untyped]
55
+ @eager_load_associations: Array[untyped]
56
+
57
+ attr_reader master_data_file: MasterDataFile
58
+ attr_reader model_klass: untyped
59
+ attr_reader columns: Array[String]
60
+ attr_reader new_records: Array[untyped]
61
+ def new_records: -> Array[untyped]
62
+ attr_reader updated_records: Array[untyped]
63
+ def updated_records: -> Array[untyped]
64
+ attr_reader no_change_records: Array[untyped]
65
+ def no_change_records: -> Array[untyped]
66
+ attr_reader deleted_records: Array[untyped]
67
+ def deleted_records: -> Array[untyped]
68
+ attr_reader before_count: Integer
69
+ def before_count: -> Integer
70
+ attr_reader after_count: Integer
71
+ def after_count: -> Integer
72
+ def initialize: (MasterDataFile master_data_file, untyped model_klass) -> void
73
+ def self.build: (MasterDataFile master_data_file, ?load: bool) -> MasterData
74
+ def basename: -> Pathname
75
+ def load: -> true
76
+ def import_records: -> Array[untyped]
77
+ def affected_records: -> Array[untyped]
78
+ def loaded?: -> bool
79
+ def affected?: -> bool?
80
+ def table_name: -> String
81
+ def import!: (?dry_run: true, ?delete_all_ignore_foreign_key: false) -> Report::ImportReport
82
+ def verify!: (?ignore_fail: bool) -> Report::VerifyReport
83
+ def print_affected_table: -> Report::PrintAffectedTableReport?
84
+
85
+ private
86
+ def preload_associations: -> Array[untyped]
87
+ def eager_load_associations: -> Array[untyped]
88
+ def build_records_from_csv: (Array[Array[String?]] csv, Hash[Integer, untyped] old_records_by_id) -> Hash[Integer, untyped]
89
+ def enable_foreign_key_checks: -> untyped
90
+ def disable_foreign_key_checks: -> untyped
91
+ end
92
+
93
+ class MasterDataCollection
94
+ @collection: Array[MasterData]
95
+
96
+ def initialize: -> void
97
+ def append: (MasterData master_data) -> Array[MasterData]
98
+ def each: ?{ (MasterData) -> (Array[MasterDataStatus | {operation: :verify, table_name: untyped, valid: untyped, id: untyped}]?) } -> (Array[MasterData] | Enumerator[MasterData, untyped] | Enumerator[untyped, untyped])
99
+ def to_a: -> Array[MasterData]
100
+ end
101
+
102
+ module Report
103
+ module Printer
104
+ attr_accessor silent: false
105
+ def initialize: (?silent: false) -> void
106
+ def print: (String message) -> nil
107
+ end
108
+
109
+ class DefaultPrinter
110
+ include Printer
111
+
112
+ def print: (String message) -> nil
113
+ end
114
+
115
+ module Core
116
+ def initialize: (MasterData master_data) -> void
117
+ def print: (Printer printer) -> untyped
118
+
119
+ private
120
+ def convert_to_ltsv: ({operation: :affected_table | :verify, table_name: untyped, valid: untyped, id: untyped} items) -> String
121
+ end
122
+
123
+ class ImportReport
124
+ include Core
125
+ @master_data: MasterData
126
+
127
+ attr_reader reports: Array[untyped]
128
+ def reports: -> Array[untyped]
129
+ def print: (Printer printer) -> untyped
130
+
131
+ private
132
+ def count_report: -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
133
+ def new_records_report: -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
134
+ def updated_records_report: -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
135
+ def no_change_records_report: -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
136
+ def deleted_records_report: -> Hash[Symbol, Array[Hash[Symbol, untyped]]]
137
+ end
138
+
139
+ class VerifyReport
140
+ include Core
141
+ @master_data: MasterData
142
+
143
+ attr_reader reports: Array[{operation: :verify, table_name: untyped, valid: untyped, id: untyped}]
144
+ def initialize: (MasterData master_data) -> void
145
+ def append: ({operation: :verify, table_name: untyped, valid: untyped, id: untyped} verify_record_report) -> Array[{operation: :verify, table_name: untyped, valid: untyped, id: untyped}]
146
+ def print: (Printer printer) -> Array[{operation: :verify, table_name: untyped, valid: untyped, id: untyped}]
147
+ def self.build_verify_record_report: (MasterData master_data, untyped record, untyped valid) -> {operation: :verify, table_name: untyped, valid: untyped, id: untyped}
148
+ end
149
+
150
+ class PrintAffectedTableReport
151
+ include Core
152
+ @master_data: MasterData
153
+
154
+ def print: (Printer printer) -> nil
155
+ end
156
+ end
157
+
158
+ module Dump
159
+ class Executor
160
+ DEFAULT_IGNORE_TABLES: [String, String, String]
161
+ DEFAULT_IGNORE_COLUMNS: [String, String]
162
+ @ignore_empty_table: bool
163
+ @ignore_tables: Array[String]
164
+ @ignore_column_names: Array[String]
165
+ @only_tables: Array[String]
166
+ @verbose: bool
167
+
168
+ def initialize: (ignore_empty_table: bool, ignore_tables: Array[String], ignore_column_names: Array[String], only_tables: Array[String], verbose: bool) -> void
169
+ def execute: -> Array[untyped]
170
+
171
+ private
172
+ def print_message: (String message) -> nil
173
+ def dump_to_csv: (untyped table) -> nil
174
+ def ignore?: (untyped model_klass) -> false
175
+
176
+ class Error < Struct[untyped]
177
+ attr_accessor table(): untyped
178
+ attr_accessor exception(): nil
179
+ end
180
+ end
181
+ end
182
+
183
+ module Import
184
+ class Executor
185
+ @dry_run: bool
186
+ @verify: bool
187
+ @only_import_tables: Array[String]
188
+ @except_import_tables: Array[String]
189
+ @only_verify_tables: Array[String]
190
+ @except_verify_tables: Array[String]
191
+ @skip_no_change: bool
192
+ @silent: bool
193
+ @delete_all_ignore_foreign_key: bool
194
+ @override_identifier: String?
195
+ @report_printer: Report::DefaultPrinter
196
+ @master_data_statuses: [MasterDataStatus]
197
+
198
+ def initialize: (dry_run: bool, verify: bool, only_import_tables: Array[String], except_import_tables: Array[String], only_verify_tables: Array[String], except_verify_tables: Array[String], skip_no_change: bool, silent: bool, delete_all_ignore_foreign_key: bool, override_identifier: String?, report_printer: Report::Printer) -> void
199
+ def execute: -> nil
200
+
201
+ private
202
+ def print_execute_options: -> nil
203
+ def build_master_data_collection: -> MasterDataCollection
204
+ def import_all!: (MasterDataCollection master_data_collection) -> (Array[MasterData] | Enumerator[MasterData, untyped] | Enumerator[untyped, untyped])
205
+ def verify_all!: (MasterDataCollection master_data_collection) -> (Array[MasterData] | Enumerator[MasterData, untyped] | Enumerator[untyped, untyped])
206
+ def save_master_data_statuses!: (MasterDataCollection master_data_collection) -> Array[MasterDataStatus]
207
+ def print_affected_tables: (MasterDataCollection master_data_collection) -> (Array[MasterData] | Enumerator[MasterData, untyped] | Enumerator[untyped, untyped])
208
+ def load_skip_table?: (untyped master_data_file) -> bool
209
+ def import_skip_table?: (untyped table_name) -> bool
210
+ def verify_skip_table?: (untyped table_name) -> bool
211
+ def need_skip_table?: (untyped table_name, Array[untyped] only, Array[untyped] except) -> bool
212
+ def extract_master_data_csv_paths: -> Array[Pathname]
213
+ def overridden_master_data_csv_paths: -> Array[Pathname]
214
+ def master_data_statuses: -> untyped
215
+ end
216
+ end
217
+
218
+ class Error < StandardError
219
+ end
220
+
221
+ class DryRunError < StandardError
222
+ end
223
+
224
+ class NotLoadedError < StandardError
225
+ end
226
+
227
+ class VerifyFailed < StandardError
228
+ attr_accessor errors: untyped
229
+ end
4
230
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: master_data_tool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takahiro Ooishi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-29 00:00:00.000000000 Z
11
+ date: 2022-07-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -209,6 +209,7 @@ files:
209
209
  - lib/master_data_tool/version.rb
210
210
  - log/test.log
211
211
  - master_data_tool.gemspec
212
+ - scripts/drop_db.sh
212
213
  - scripts/setup.sh
213
214
  - sig/master_data_tool.rbs
214
215
  homepage: https://github.com/taka0125/master_data_tool
@@ -231,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
232
  - !ruby/object:Gem::Version
232
233
  version: '0'
233
234
  requirements: []
234
- rubygems_version: 3.2.33
235
+ rubygems_version: 3.3.7
235
236
  signing_key:
236
237
  specification_version: 4
237
238
  summary: マスタデータの管理ツール