masking 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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