masking 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +3 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile.lock +1 -1
- data/README.md +93 -58
- data/bin/benchmark.rb +23 -0
- data/bin/masking_profile +5 -5
- data/lib/masking/config/target_columns.rb +3 -5
- data/lib/masking/config/target_columns/column.rb +1 -0
- data/lib/masking/config/target_columns/method/date.rb +2 -2
- data/lib/masking/config/target_columns/method/float.rb +2 -2
- data/lib/masking/config/target_columns/method/integer.rb +2 -2
- data/lib/masking/config/target_columns/method/string.rb +2 -2
- data/lib/masking/config/target_columns/method/time.rb +2 -2
- data/lib/masking/data_mask_processor.rb +12 -5
- data/lib/masking/insert_statement.rb +2 -4
- data/lib/masking/insert_statement/sql_builder.rb +1 -1
- data/lib/masking/version.rb +1 -1
- metadata +4 -3
- data/lib/masking/insert_statement/value.rb +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a65d39a6c96c94bf473883d1ef9877f1abdd16cfcae97da27e99f8c7afa9963
|
4
|
+
data.tar.gz: 109965dbb6e2ee880f9fd955e4f0d05f6a3dfbc8cbecd153315f9bcad275bf86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03010bd6d5fb1c90ed1c6dca9dff8f7d84bfe934d65bf48fab28feb3aa6c67381c0c1c6d85ba055b21334919ad1b075a166e23ab3d01fc76f09575f08c1ccac0
|
7
|
+
data.tar.gz: ff9ddd10f8f30c72427815177bb37d68e46fedd7d104d1141d5655449c7ae3811e4d2d0135113b2145b4b809d5774752b9c0100337927d6a59949a9c4fe35580
|
data/.codeclimate.yml
CHANGED
@@ -5,10 +5,12 @@ plugins:
|
|
5
5
|
markdownlint:
|
6
6
|
enabled: true
|
7
7
|
checks:
|
8
|
-
# below 3 checks are disabled because Codeclimate's Markdownlint is not latest version
|
8
|
+
# below 3 checks are disabled because Codeclimate's Markdownlint is not latest version (0.5.0)
|
9
9
|
MD023:
|
10
10
|
enabled: false
|
11
11
|
MD034:
|
12
12
|
enabled: false
|
13
13
|
MD036:
|
14
14
|
enabled: false
|
15
|
+
exclude_patterns:
|
16
|
+
- ".chglog/*.tpl.md"
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [v0.0.3] - 2019-07-07
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- Update Document [#25](https://github.com/kibitan/masking/pull/25)
|
15
|
+
- Performance Tuning [#28](https://github.com/kibitan/masking/pull/28) special thanks [@isaiah](https://github.com/isaiah)
|
16
|
+
|
17
|
+
```
|
18
|
+
$ bin/benchmark.rb
|
19
|
+
(v0.0.2)
|
20
|
+
user system total real
|
21
|
+
2.197755 0.239222 2.436977 ( 2.460922)
|
22
|
+
|
23
|
+
(v0.0.3)
|
24
|
+
user system total real
|
25
|
+
1.136621 0.198741 1.335362 ( 1.355499)
|
26
|
+
```
|
27
|
+
|
28
|
+
## [v0.0.2] - 2019-01-06
|
29
|
+
|
30
|
+
### Fix
|
31
|
+
|
32
|
+
- fix bug about NoMethodError on some environment
|
33
|
+
|
34
|
+
## [v0.0.1] - 2019-01-05
|
35
|
+
|
36
|
+
Initial release version. 🎉
|
37
|
+
|
38
|
+
[Unreleased]: https://github.com/kibitan/masking/compare/v0.0.3...HEAD
|
39
|
+
[v0.0.3]: https://github.com/kibitan/masking/compare/v0.0.2...v0.0.3
|
40
|
+
[v0.0.2]: https://github.com/kibitan/masking/compare/v0.0.1...v0.0.2
|
41
|
+
[v0.0.1]: https://github.com/kibitan/masking/tree/v0.0.1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -3,18 +3,12 @@
|
|
3
3
|
[![Build Status](https://travis-ci.org/kibitan/masking.svg?branch=master)](https://travis-ci.org/kibitan/masking)
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/github/kibitan/masking/badge.svg?branch=master)](https://coveralls.io/github/kibitan/masking?branch=master)
|
5
5
|
[![Maintainability](https://api.codeclimate.com/v1/badges/290b3005ecc193a3d138/maintainability)](https://codeclimate.com/github/kibitan/masking/maintainability)
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/masking.svg)](https://badge.fury.io/rb/masking)
|
6
7
|
|
7
8
|
The command line tool for anonymizing database records by parsing a SQL dump file and build new SQL dump file with masking sensitive/credential data.
|
8
9
|
|
9
10
|
## Installation
|
10
11
|
|
11
|
-
```bash
|
12
|
-
git clone git@github.com:kibitan/masking.git
|
13
|
-
bin/setup
|
14
|
-
```
|
15
|
-
|
16
|
-
or install it yourself as:
|
17
|
-
|
18
12
|
```bash
|
19
13
|
gem install masking
|
20
14
|
```
|
@@ -29,51 +23,57 @@ gem install masking
|
|
29
23
|
|
30
24
|
## Usage
|
31
25
|
|
32
|
-
1.
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
A value will be implicitly converted to compatible type. If you prefer to explicitly convert, you could use a tag as defined in [YAML Version 1.1](http://yaml.org/spec/current.html#id2503753)
|
55
|
-
|
56
|
-
```yaml
|
57
|
-
not-date: !!str 2002-04-28
|
58
|
-
```
|
26
|
+
1. Setup configuration for anonymizing target tables/columns to `masking.yml`
|
27
|
+
|
28
|
+
```yaml
|
29
|
+
# table_name:
|
30
|
+
# column_name: masked_value
|
31
|
+
|
32
|
+
users:
|
33
|
+
string: anonymized string
|
34
|
+
email: anonymized+%{n}@example.com # %{n} will be replaced with sequential number
|
35
|
+
integer: 12345
|
36
|
+
float: 123.45
|
37
|
+
boolean: true
|
38
|
+
null: null
|
39
|
+
date: 2018-08-24
|
40
|
+
time: 2018-08-24 15:54:06
|
41
|
+
binary_or_blob: !binary | # Binary Data Language-Independent Type for YAML™ Version 1.1: http://yaml.org/type/binary.html
|
42
|
+
R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
|
43
|
+
OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
|
44
|
+
+f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
|
45
|
+
AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=
|
46
|
+
```
|
47
|
+
|
48
|
+
A value will be implicitly converted to compatible type. If you prefer to explicitly convert, you could use a tag as defined in [YAML Version 1.1](http://yaml.org/spec/current.html#id2503753)
|
49
|
+
|
50
|
+
```yaml
|
51
|
+
not-date: !!str 2002-04-28
|
52
|
+
```
|
53
|
+
|
54
|
+
String should be matched with [MySQL String Type]( https://dev.mysql.com/doc/refman/8.0/en/string-type-overview.html). Integer/Float should be matched with [MySQL Numeric Type](https://dev.mysql.com/doc/refman/8.0/en/numeric-type-overview.html). Date/Time should be matched with [MySQL Date and Time Type](https://dev.mysql.com/doc/refman/8.0/en/date-and-time-type-overview.html).
|
59
55
|
|
60
|
-
|
56
|
+
*NOTE: MasKING doesn't check actual schema's type from dump. If you put uncomaptible value it will cause error during restoring to database.*
|
61
57
|
|
62
|
-
|
58
|
+
1. Dump database with anonymizing
|
63
59
|
|
64
|
-
|
60
|
+
MasKING works with `mysqldump --complete-insert`
|
65
61
|
|
66
|
-
|
62
|
+
```bash
|
63
|
+
mysqldump --complete-insert -u USERNAME DATABASE_NAME | masking > anonymized_dump.sql
|
64
|
+
```
|
67
65
|
|
68
|
-
|
69
|
-
mysqldump --complete-insert -u USERNAME DATABASE_NAME | masking > masked_dump.sql
|
70
|
-
```
|
66
|
+
1. Restore from anonymized dump file
|
71
67
|
|
72
|
-
|
68
|
+
```bash
|
69
|
+
mysql -u USERNAME ANONYMIZED_DATABASE_NAME < anonymized_dump.sql
|
70
|
+
```
|
73
71
|
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
Tip: If you don't need to have anonymized dump file, you can directly insert from stream. It can be faster because it has less IO interaction.
|
73
|
+
|
74
|
+
```bash
|
75
|
+
mysqldump --complete-insert -u USERNAME DATABASE_NAME | masking | mysql -u USERNAME ANONYMIZED_DATABASE_NAME
|
76
|
+
```
|
77
77
|
|
78
78
|
### options
|
79
79
|
|
@@ -83,13 +83,48 @@ Usage: masking [options]
|
|
83
83
|
-c, --config=FILE_PATH specify config file. default: masking.yml
|
84
84
|
```
|
85
85
|
|
86
|
-
##
|
86
|
+
## Use case of annonymized (production) database
|
87
|
+
|
88
|
+
* Simulate for database migration and find a problem before release
|
89
|
+
|
90
|
+
Some schema changing statement will lock table and it will cause trouble during the migration. But, without having a large number of record such as production, a migration will finish at the moment and easy to overlook.
|
91
|
+
|
92
|
+
* Performance optimization of database queries
|
93
|
+
|
94
|
+
Some database query can be slow, but some query isn't reproducible until you have similar amount of records/cardinality.
|
95
|
+
|
96
|
+
* Finding bug before release on production
|
97
|
+
|
98
|
+
Some bugs are related to unexpected data in production (for instance so long text, invalid/not-well formatted data) and it might be noticed after releasing in production.
|
99
|
+
|
100
|
+
* Better development/demo of a feature
|
101
|
+
|
102
|
+
Using similar data with real one will be good to make a good view of how feature looks like. It makes easy to find out the things to be changed/fixed before release/check the feature in production.
|
103
|
+
|
104
|
+
* Analyze metrics on our production data with respecting GDPR
|
105
|
+
|
106
|
+
We can use this database for BI and some trouble shooting.
|
107
|
+
|
108
|
+
* And… your idea here!
|
109
|
+
|
110
|
+
## Development
|
111
|
+
|
112
|
+
```bash
|
113
|
+
git clone git@github.com:kibitan/masking.git
|
114
|
+
bin/setup
|
115
|
+
```
|
116
|
+
|
117
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
118
|
+
|
119
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
120
|
+
|
121
|
+
### Run test & rubocop & notes
|
87
122
|
|
88
123
|
```bash
|
89
124
|
bundle exec rake
|
90
125
|
```
|
91
126
|
|
92
|
-
|
127
|
+
#### Protip
|
93
128
|
|
94
129
|
It's useful that set `rake` on [Git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks).
|
95
130
|
|
@@ -100,18 +135,12 @@ bundle exec rake
|
|
100
135
|
EOF
|
101
136
|
```
|
102
137
|
|
103
|
-
|
138
|
+
#### [Markdown lint](https://github.com/markdownlint/markdownlint)
|
104
139
|
|
105
140
|
```bash
|
106
141
|
bundle exec mdl *.md
|
107
142
|
```
|
108
143
|
|
109
|
-
## Development
|
110
|
-
|
111
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
112
|
-
|
113
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
114
|
-
|
115
144
|
### Profiling
|
116
145
|
|
117
146
|
use `bin/masking_profile`
|
@@ -127,6 +156,16 @@ graph html is saved at /your/repo/profile/graph.html
|
|
127
156
|
|
128
157
|
see also: [ruby-prof/ruby-prof: ruby-prof: a code profiler for MRI rubies](https://github.com/ruby-prof/ruby-prof)
|
129
158
|
|
159
|
+
### Benchmark
|
160
|
+
|
161
|
+
use `bin/benchmark.rb`
|
162
|
+
|
163
|
+
```bash
|
164
|
+
$ bin/benchmark.rb
|
165
|
+
user system total real
|
166
|
+
1.152776 0.207064 1.359840 ( 1.375090)
|
167
|
+
```
|
168
|
+
|
130
169
|
## Design Concept
|
131
170
|
|
132
171
|
### KISS ~ keep it simple, stupid ~
|
@@ -137,10 +176,6 @@ No connection to database, No handling file, Only dealing with stdin/stdout. ~ D
|
|
137
176
|
|
138
177
|
Depend on only pure language standard libraries, no external libraries. (except development/test environment)
|
139
178
|
|
140
|
-
### High Code Quality
|
141
|
-
|
142
|
-
100% of code coverage [![Coverage Status](https://coveralls.io/repos/github/kibitan/masking/badge.svg?branch=master)](https://coveralls.io/github/kibitan/masking?branch=master) and low complexity [![Maintainability](https://api.codeclimate.com/v1/badges/290b3005ecc193a3d138/maintainability)](https://codeclimate.com/github/kibitan/masking/maintainability)
|
143
|
-
|
144
179
|
## Future Todo
|
145
180
|
|
146
181
|
* Pluguable/customizable for a mask way e.g. integrate with [Faker](https://github.com/stympy/faker)
|
data/bin/benchmark.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift('./lib')
|
5
|
+
require 'benchmark'
|
6
|
+
require 'masking'
|
7
|
+
|
8
|
+
n = 10_000
|
9
|
+
|
10
|
+
Masking.configure do |config|
|
11
|
+
config.target_columns_file_path = 'spec/fixtures/config/masking.yml'
|
12
|
+
end
|
13
|
+
|
14
|
+
fixture = File.open('spec/fixtures/insert_statement/sample.sql')
|
15
|
+
|
16
|
+
Benchmark.bm do |x|
|
17
|
+
x.report do
|
18
|
+
n.times do
|
19
|
+
Masking::Main.new(input: fixture, output: File.open(File::NULL, 'w')).run
|
20
|
+
fixture.rewind
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/bin/masking_profile
CHANGED
@@ -37,11 +37,11 @@ RubyProf::GraphHtmlPrinter.new(result).tap do |graph_html_printer|
|
|
37
37
|
end
|
38
38
|
|
39
39
|
# # this is quite slow so commented out. but it's useful
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
call_stack_html_file = Pathname(__dir__).join('../profile/call_stack.html')
|
41
|
+
RubyProf::CallStackPrinter.new(result).tap do |call_stack_html_printer|
|
42
|
+
call_stack_html_printer.print(File.new(call_stack_html_file, 'w'))
|
43
|
+
puts "call stack html is saved at #{call_stack_html_file}"
|
44
|
+
end
|
45
45
|
|
46
46
|
# # I'm not sure how to read this
|
47
47
|
# call_graph_dot_file = Pathname(__dir__).join('../profile/call_graph.dot')
|
@@ -24,7 +24,7 @@ module Masking
|
|
24
24
|
|
25
25
|
# TODO: refactoring
|
26
26
|
def columns(table_name:)
|
27
|
-
tables
|
27
|
+
tables[table_name.to_sym]&.columns
|
28
28
|
end
|
29
29
|
|
30
30
|
def ==(other)
|
@@ -41,10 +41,8 @@ module Masking
|
|
41
41
|
|
42
42
|
# TODO: extract to other class
|
43
43
|
def tables
|
44
|
-
@tables ||=
|
45
|
-
|
46
|
-
arr << Table.new(table_name, columns: columns)
|
47
|
-
end
|
44
|
+
@tables ||= data.each_with_object({}) do |kv, r|
|
45
|
+
r[kv[0].to_sym] = Table.new(kv[0], columns: kv[1])
|
48
46
|
end
|
49
47
|
end
|
50
48
|
end
|
@@ -8,7 +8,7 @@ module Masking
|
|
8
8
|
class Method
|
9
9
|
class Date
|
10
10
|
def initialize(value)
|
11
|
-
@date = value
|
11
|
+
@date = value.strftime(FORMAT)
|
12
12
|
end
|
13
13
|
|
14
14
|
def call
|
@@ -21,7 +21,7 @@ module Masking
|
|
21
21
|
FORMAT = '%Y-%m-%d'
|
22
22
|
|
23
23
|
def date_format
|
24
|
-
date
|
24
|
+
date
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -11,13 +11,13 @@ module Masking
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def call
|
14
|
-
"'
|
14
|
+
("'" + output + "'").b
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
+
SEQUENTIAL_NUMBER_PLACEHOLDER = '%{n}' # rubocop:disable Style/FormatStringToken
|
19
20
|
attr_reader :string
|
20
|
-
SEQUENTIAL_NUMBER_PLACEHOLDER = /%{n}/.freeze
|
21
21
|
|
22
22
|
def output
|
23
23
|
string.sub(SEQUENTIAL_NUMBER_PLACEHOLDER, sequence.to_s)
|
@@ -6,7 +6,7 @@ module Masking
|
|
6
6
|
class Method
|
7
7
|
class Time
|
8
8
|
def initialize(value)
|
9
|
-
@time = value
|
9
|
+
@time = value.strftime(FORMAT)
|
10
10
|
end
|
11
11
|
|
12
12
|
def call
|
@@ -19,7 +19,7 @@ module Masking
|
|
19
19
|
FORMAT = '%Y-%m-%d %H:%M:%S'
|
20
20
|
|
21
21
|
def time_format
|
22
|
-
time
|
22
|
+
time
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -23,19 +23,26 @@ module Masking
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# TODO: define insert_statement.mask_values(column, mask_method) method & refactoring
|
26
|
-
# rubocop:disable Metrics/AbcSize
|
26
|
+
# rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
27
27
|
def process
|
28
28
|
return raw_line unless target_table?
|
29
29
|
|
30
|
-
target_columns.columns(table_name: insert_statement.table)
|
31
|
-
|
32
|
-
|
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
|
36
|
+
|
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?
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
36
43
|
insert_statement.sql
|
37
44
|
end
|
38
|
-
# rubocop:enable Metrics/AbcSize
|
45
|
+
# rubocop:enable Metrics/AbcSize,Metrics/MethodLength
|
39
46
|
|
40
47
|
def target_table?
|
41
48
|
target_columns.contains?(table_name: insert_statement.table)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'masking/insert_statement/value'
|
4
3
|
require 'masking/insert_statement/sql_builder'
|
5
4
|
|
6
5
|
module Masking
|
@@ -26,8 +25,7 @@ module Masking
|
|
26
25
|
# NOTE: define and extract to ValueSet class?
|
27
26
|
@values ||= values_section.split(VALUE_ROW_SPLITTER)
|
28
27
|
.tap { |rows| rows.each_with_index { |_, i| recursive_pattern_value_concat(rows, i) } }
|
29
|
-
.
|
30
|
-
.map { |data| Value.new(columns: columns, data: data) }
|
28
|
+
.flat_map { |row| row.scan(values_regexp) }
|
31
29
|
end
|
32
30
|
|
33
31
|
def sql
|
@@ -65,7 +63,7 @@ module Masking
|
|
65
63
|
# e.g. INSERT ... VALUES (123,'string ),( abc'),(456,'ab');
|
66
64
|
# refs: implementation of parsing CSV on ruby standard library FasterCSV (ja): https://www.clear-code.com/blog/2018/12/25.html
|
67
65
|
def recursive_pattern_value_concat(value_rows, index)
|
68
|
-
return if value_rows[index].gsub(/\\\\/, '').gsub(/\\'/, '').
|
66
|
+
return if value_rows[index].gsub(/\\\\/, '').gsub(/\\'/, '').count(?').even?
|
69
67
|
|
70
68
|
value_rows[index] += VALUE_ROW_SPLITTER + value_rows.delete_at(index + 1)
|
71
69
|
recursive_pattern_value_concat(value_rows, index)
|
data/lib/masking/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: masking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
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
|
+
date: 2019-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -193,12 +193,14 @@ files:
|
|
193
193
|
- ".rubocop.yml"
|
194
194
|
- ".ruby-version"
|
195
195
|
- ".travis.yml"
|
196
|
+
- CHANGELOG.md
|
196
197
|
- CODE_OF_CONDUCT.md
|
197
198
|
- Gemfile
|
198
199
|
- Gemfile.lock
|
199
200
|
- LICENSE.txt
|
200
201
|
- README.md
|
201
202
|
- Rakefile
|
203
|
+
- bin/benchmark.rb
|
202
204
|
- bin/console
|
203
205
|
- bin/masking_profile
|
204
206
|
- bin/setup
|
@@ -226,7 +228,6 @@ files:
|
|
226
228
|
- lib/masking/errors.rb
|
227
229
|
- lib/masking/insert_statement.rb
|
228
230
|
- lib/masking/insert_statement/sql_builder.rb
|
229
|
-
- lib/masking/insert_statement/value.rb
|
230
231
|
- lib/masking/sql_dump_line.rb
|
231
232
|
- lib/masking/version.rb
|
232
233
|
- masking.gemspec
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'delegate'
|
4
|
-
|
5
|
-
module Masking
|
6
|
-
class InsertStatement
|
7
|
-
class Value < ::SimpleDelegator
|
8
|
-
def initialize(columns:, data:)
|
9
|
-
@columns = columns
|
10
|
-
@data = Struct.new(*columns).new(*data)
|
11
|
-
# NOTE: is it better to get rid of SimpleDelegator, store data in instance variable and define accesor for it?
|
12
|
-
super(@data)
|
13
|
-
end
|
14
|
-
|
15
|
-
def phrase
|
16
|
-
'(' + to_a.join(?,) + ')'
|
17
|
-
end
|
18
|
-
|
19
|
-
# override for make comparable
|
20
|
-
# NOTE: original #== method comapares struct subclass
|
21
|
-
def ==(other)
|
22
|
-
to_h == other.to_h
|
23
|
-
end
|
24
|
-
|
25
|
-
def column?(column_name)
|
26
|
-
@columns.include?(column_name.to_sym)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|