masking 1.0.0 → 1.0.1

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.
@@ -1,51 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'masking/data_mask_processor/cache'
3
4
  require 'masking/config/target_columns'
4
5
  require 'masking/insert_statement'
5
6
 
6
7
  module Masking
7
- # TODO: find better naming/modeling of DataMaskProcessor
8
8
  class DataMaskProcessor
9
- class << self
10
- def process(insert_statement_line, target_columns: ::Masking.config.target_columns)
11
- new(insert_statement_line, target_columns: target_columns).send(:process)
12
- end
13
- end
14
-
15
- private
16
-
17
- attr_reader :raw_line, :target_columns, :insert_statement
18
-
19
- def initialize(insert_statement_line, target_columns:)
9
+ def initialize(
10
+ insert_statement_line,
11
+ target_columns: ::Masking.config.target_columns,
12
+ insert_statement: InsertStatement.new(insert_statement_line),
13
+ cache_store: Cache
14
+ )
20
15
  @raw_line = insert_statement_line
21
16
  @target_columns = target_columns
22
- @insert_statement = InsertStatement.new(insert_statement_line)
17
+ @insert_statement = insert_statement
18
+ @cache_store = cache_store
23
19
  end
24
20
 
25
- # TODO: define insert_statement.mask_values(column, mask_method) method & refactoring
26
- # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
27
21
  def process
28
22
  return raw_line unless target_table?
29
23
 
30
- columns = target_columns.columns(table_name: insert_statement.table)
31
- if columns.first.index.nil?
32
- columns.each do |target_column|
33
- target_column.index = insert_statement.columns.index(target_column.name)
34
- end
35
- end
24
+ column_indexes_mask_methods.each do |column_index, mask_method|
25
+ next if column_index.nil?
36
26
 
37
- insert_statement.values.each do |values|
38
- columns.each do |target_column|
39
- values[target_column.index] = target_column.masked_value unless target_column.index.nil?
40
- end
27
+ insert_statement.mask_value(
28
+ column_index: column_index,
29
+ mask_method: mask_method
30
+ )
41
31
  end
42
32
 
43
33
  insert_statement.sql
44
34
  end
45
- # rubocop:enable Metrics/AbcSize,Metrics/MethodLength
35
+
36
+ private
37
+
38
+ attr_reader :raw_line, :target_columns, :insert_statement, :cache_store
46
39
 
47
40
  def target_table?
48
- target_columns.contains?(table_name: insert_statement.table)
41
+ target_columns.contains?(table_name: table_name)
42
+ end
43
+
44
+ def column_indexes_mask_methods
45
+ cache_store.fetch_or_store_if_no_cache(
46
+ table: table_name,
47
+ proc: proc {
48
+ target_columns.columns(table_name: table_name).map do |column|
49
+ [insert_statement.column_index(column.name), column.method]
50
+ end
51
+ }
52
+ )
53
+ end
54
+
55
+ def table_name
56
+ @table_name = insert_statement.table
49
57
  end
50
58
  end
51
59
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Masking
4
+ class DataMaskProcessor
5
+ class Cache
6
+ def self.fetch_or_store_if_no_cache(table:, proc:)
7
+ @cache ||= {}
8
+
9
+ if @cache.key?(table)
10
+ @cache[table]
11
+ else
12
+ @cache[table] = proc.call
13
+ end
14
+ end
15
+
16
+ # onlu for test
17
+ def self.clear
18
+ @cache = {}
19
+ end
20
+ end
21
+ end
22
+ end
@@ -7,8 +7,9 @@ module Masking
7
7
  class InsertStatement
8
8
  attr_reader :raw_statement, :table
9
9
 
10
- def initialize(raw_statement)
10
+ def initialize(raw_statement, sql_builder: SQLBuilder)
11
11
  @raw_statement = raw_statement
12
+ @sql_builder = sql_builder
12
13
 
13
14
  PARSE_REGEXP.match(raw_statement).tap do |match_data|
14
15
  raise Error::InsertStatementParseError if match_data.nil?
@@ -20,24 +21,32 @@ module Masking
20
21
  end
21
22
 
22
23
  def columns
23
- # NOTE: define and extract to ColumnSet class?
24
24
  @columns ||= columns_section.scan(COLUMNS_REGEXP).flatten.map(&:to_sym)
25
25
  end
26
26
 
27
+ def column_index(column_name)
28
+ columns.index(column_name)
29
+ end
30
+
27
31
  def values
28
- # NOTE: define and extract to ValueSet class?
29
32
  @values ||= values_section.split(VALUE_ROW_SPLITTER)
30
33
  .tap { |rows| rows.each_with_index { |_, i| recursive_pattern_value_concat(rows, i) } }
31
34
  .flat_map { |row| row.scan(values_regexp) }
32
35
  end
33
36
 
37
+ def mask_value(column_index:, mask_method:)
38
+ values.each do |value|
39
+ value[column_index] = mask_method.call
40
+ end
41
+ end
42
+
34
43
  def sql
35
- SQLBuilder.build(table: table, columns: columns, values: values)
44
+ sql_builder.new(table: table, columns: columns, values: values).sql
36
45
  end
37
46
 
38
47
  private
39
48
 
40
- attr_reader :columns_section, :values_section
49
+ attr_reader :columns_section, :values_section, :sql_builder
41
50
 
42
51
  VALUE_ROW_SPLITTER = '),('
43
52
  PARSE_REGEXP = /INSERT INTO `(?<table>.+)` \((?<columns_section>.+)\) VALUES (?<values_section>.+);/.freeze
@@ -3,25 +3,20 @@
3
3
  module Masking
4
4
  class InsertStatement
5
5
  class SQLBuilder
6
- class << self
7
- def build(table:, columns:, values:)
8
- new(table: table, columns: columns, values: values).send(:build)
9
- end
10
- end
11
-
12
- private
13
-
14
- attr_reader :table, :columns, :values
15
6
  def initialize(table:, columns:, values:)
16
7
  @table = table
17
8
  @columns = columns
18
9
  @values = values
19
10
  end
20
11
 
21
- def build
12
+ def sql
22
13
  %(INSERT INTO `#{table}` #{columns_section} VALUES #{values_section};\n)
23
14
  end
24
15
 
16
+ private
17
+
18
+ attr_reader :table, :columns, :values
19
+
25
20
  def columns_section
26
21
  '(' + columns.map { |column| "`#{column}`" }.join(', ') + ')'
27
22
  end
@@ -4,21 +4,36 @@ require 'masking/data_mask_processor'
4
4
 
5
5
  module Masking
6
6
  class SQLDumpLine
7
- def initialize(line)
7
+ def initialize(line, mask_processor: DataMaskProcessor)
8
8
  @line = line
9
+ @mask_processor = mask_processor
9
10
  end
10
11
 
11
- def output
12
- insert_statement? ? DataMaskProcessor.process(line) : line
12
+ def mask
13
+ processor.new(line).process
14
+ end
15
+
16
+ def insert_statement?
17
+ line.match?(INSERT_STATEMENT_REGEXP)
13
18
  end
14
19
 
15
20
  private
16
21
 
17
- attr_reader :line
22
+ attr_reader :line, :mask_processor
18
23
  INSERT_STATEMENT_REGEXP = /^INSERT/.freeze
19
24
 
20
- def insert_statement?
21
- line.match?(INSERT_STATEMENT_REGEXP)
25
+ def processor
26
+ insert_statement? ? mask_processor : NoMaskProcessor
27
+ end
28
+
29
+ class NoMaskProcessor
30
+ def initialize(line)
31
+ @line = line
32
+ end
33
+
34
+ def process
35
+ @line # do nothing
36
+ end
22
37
  end
23
38
  end
24
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Masking
4
- VERSION = '1.0.0'
4
+ VERSION = '1.0.1'
5
5
  end
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.required_ruby_version = '>= 2.5'
27
27
 
28
- spec.add_development_dependency 'bundler', '~> 2.0'
29
- spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'rake'
30
30
  spec.add_development_dependency 'rake-notes'
31
31
  spec.add_development_dependency 'ruby-prof'
32
32
 
@@ -35,8 +35,8 @@ Gem::Specification.new do |spec|
35
35
  spec.add_development_dependency 'rubocop'
36
36
 
37
37
  # test
38
- spec.add_development_dependency 'coveralls'
39
- spec.add_development_dependency 'rspec', '~> 3.0'
38
+ spec.add_development_dependency 'codecov'
39
+ spec.add_development_dependency 'rspec'
40
40
  spec.add_development_dependency 'simplecov'
41
41
 
42
42
  # debug
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: masking
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chikahiro Tokoro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-10 00:00:00.000000000 Z
11
+ date: 2019-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake-notes
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: coveralls
98
+ name: codecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -112,16 +112,16 @@ dependencies:
112
112
  name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '3.0'
117
+ version: '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: '3.0'
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: simplecov
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -210,7 +210,9 @@ files:
210
210
  - acceptance/masking.yml
211
211
  - acceptance/run_test.sh
212
212
  - acceptance/tmp/.keep
213
- - bin/benchmark.rb
213
+ - benchmark/masking.yml
214
+ - benchmark/run.rb
215
+ - benchmark/users.sql
214
216
  - bin/console
215
217
  - bin/masking_profile
216
218
  - bin/setup
@@ -250,6 +252,7 @@ files:
250
252
  - lib/masking/config/target_columns/method/time.rb
251
253
  - lib/masking/config/target_columns/table.rb
252
254
  - lib/masking/data_mask_processor.rb
255
+ - lib/masking/data_mask_processor/cache.rb
253
256
  - lib/masking/errors.rb
254
257
  - lib/masking/insert_statement.rb
255
258
  - lib/masking/insert_statement/sql_builder.rb
@@ -278,7 +281,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
281
  - !ruby/object:Gem::Version
279
282
  version: '0'
280
283
  requirements: []
281
- rubygems_version: 3.0.3
284
+ rubygems_version: 3.1.2
282
285
  signing_key:
283
286
  specification_version: 4
284
287
  summary: Command line tool for anonymizing databese records