masking 0.0.2 → 0.0.3
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 +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
|
[](https://travis-ci.org/kibitan/masking)
|
|
4
4
|
[](https://coveralls.io/github/kibitan/masking?branch=master)
|
|
5
5
|
[](https://codeclimate.com/github/kibitan/masking/maintainability)
|
|
6
|
+
[](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 [](https://coveralls.io/github/kibitan/masking?branch=master) and low complexity [](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
|