mysql_rewinder 0.1.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 +7 -0
- data/.rspec +3 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +102 -0
- data/LICENSE.txt +21 -0
- data/README.md +115 -0
- data/Rakefile +8 -0
- data/Steepfile +20 -0
- data/lib/mysql_rewinder/cleaner/adapter.rb +32 -0
- data/lib/mysql_rewinder/cleaner/mysql2_adapter.rb +44 -0
- data/lib/mysql_rewinder/cleaner/trilogy_adapter.rb +44 -0
- data/lib/mysql_rewinder/cleaner.rb +34 -0
- data/lib/mysql_rewinder/ext/mysql2_client.rb +14 -0
- data/lib/mysql_rewinder/ext/trilogy.rb +14 -0
- data/lib/mysql_rewinder/version.rb +5 -0
- data/lib/mysql_rewinder.rb +79 -0
- data/mysql_rewinder.gemspec +22 -0
- data/sig/mysql_rewinder/cleaner/adapter.rbs +10 -0
- data/sig/mysql_rewinder/cleaner/mysql2_adapter.rbs +13 -0
- data/sig/mysql_rewinder/cleaner/trilogy_adapter.rbs +13 -0
- data/sig/mysql_rewinder/cleaner.rbs +15 -0
- data/sig/mysql_rewinder/ext/mysql2_client.rbs +7 -0
- data/sig/mysql_rewinder/ext/trilogy.rbs +7 -0
- data/sig/mysql_rewinder/mysql2.rbs +16 -0
- data/sig/mysql_rewinder/trilogy.rbs +12 -0
- data/sig/mysql_rewinder/version.rbs +3 -0
- data/sig/mysql_rewinder.rbs +20 -0
- metadata +69 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 312985891d45112d6c806ae4bdd2f2b741f1150bdfe6e5884e4cc0f327ebfbcf
|
4
|
+
data.tar.gz: 853345a9fba1a84b22b3f051ff1cc30f7495153ac2eb47fd559c72bf9c677ce7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8afda05e048b531c39b89dc9136e5d7e32407c01c5c672433e30a10498bdf8820fa0fa08a581b22ecf25afe0ebcf11ae6a8590977af3e4418790f7abe54837b3
|
7
|
+
data.tar.gz: ae8539d8a9e068f2a451794ff967efaf86d93b5d09450172fbe4b03b09d5e2bdd6b04b82b38f043c9ce1f8e7cd3d587e405fcd30b112a661489bbe3255123883
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
mysql_rewinder (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activesupport (7.1.1)
|
10
|
+
base64
|
11
|
+
bigdecimal
|
12
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
|
+
connection_pool (>= 2.2.5)
|
14
|
+
drb
|
15
|
+
i18n (>= 1.6, < 2)
|
16
|
+
minitest (>= 5.1)
|
17
|
+
mutex_m
|
18
|
+
tzinfo (~> 2.0)
|
19
|
+
ast (2.4.2)
|
20
|
+
base64 (0.2.0)
|
21
|
+
bigdecimal (3.1.4)
|
22
|
+
concurrent-ruby (1.2.2)
|
23
|
+
connection_pool (2.4.1)
|
24
|
+
csv (3.2.7)
|
25
|
+
diff-lcs (1.5.0)
|
26
|
+
drb (2.2.0)
|
27
|
+
ruby2_keywords
|
28
|
+
ffi (1.16.3)
|
29
|
+
fileutils (1.7.2)
|
30
|
+
i18n (1.14.1)
|
31
|
+
concurrent-ruby (~> 1.0)
|
32
|
+
json (2.6.3)
|
33
|
+
language_server-protocol (3.17.0.3)
|
34
|
+
listen (3.8.0)
|
35
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
36
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
37
|
+
logger (1.6.0)
|
38
|
+
minitest (5.20.0)
|
39
|
+
mutex_m (0.2.0)
|
40
|
+
mysql2 (0.5.5)
|
41
|
+
parser (3.2.2.4)
|
42
|
+
ast (~> 2.4.1)
|
43
|
+
racc
|
44
|
+
racc (1.7.3)
|
45
|
+
rainbow (3.1.1)
|
46
|
+
rake (13.1.0)
|
47
|
+
rb-fsevent (0.11.2)
|
48
|
+
rb-inotify (0.10.1)
|
49
|
+
ffi (~> 1.0)
|
50
|
+
rbs (3.2.2)
|
51
|
+
rspec (3.12.0)
|
52
|
+
rspec-core (~> 3.12.0)
|
53
|
+
rspec-expectations (~> 3.12.0)
|
54
|
+
rspec-mocks (~> 3.12.0)
|
55
|
+
rspec-core (3.12.2)
|
56
|
+
rspec-support (~> 3.12.0)
|
57
|
+
rspec-expectations (3.12.3)
|
58
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
59
|
+
rspec-support (~> 3.12.0)
|
60
|
+
rspec-mocks (3.12.6)
|
61
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
62
|
+
rspec-support (~> 3.12.0)
|
63
|
+
rspec-support (3.12.1)
|
64
|
+
ruby2_keywords (0.0.5)
|
65
|
+
securerandom (0.3.0)
|
66
|
+
steep (1.5.3)
|
67
|
+
activesupport (>= 5.1)
|
68
|
+
concurrent-ruby (>= 1.1.10)
|
69
|
+
csv (>= 3.0.9)
|
70
|
+
fileutils (>= 1.1.0)
|
71
|
+
json (>= 2.1.0)
|
72
|
+
language_server-protocol (>= 3.15, < 4.0)
|
73
|
+
listen (~> 3.0)
|
74
|
+
logger (>= 1.3.0)
|
75
|
+
parser (>= 3.1)
|
76
|
+
rainbow (>= 2.2.2, < 4.0)
|
77
|
+
rbs (>= 3.1.0)
|
78
|
+
securerandom (>= 0.1)
|
79
|
+
strscan (>= 1.0.0)
|
80
|
+
terminal-table (>= 2, < 4)
|
81
|
+
strscan (3.0.7)
|
82
|
+
terminal-table (3.0.2)
|
83
|
+
unicode-display_width (>= 1.1.1, < 3)
|
84
|
+
trilogy (2.6.0)
|
85
|
+
tzinfo (2.0.6)
|
86
|
+
concurrent-ruby (~> 1.0)
|
87
|
+
unicode-display_width (2.5.0)
|
88
|
+
|
89
|
+
PLATFORMS
|
90
|
+
arm64-darwin
|
91
|
+
x86_64-linux
|
92
|
+
|
93
|
+
DEPENDENCIES
|
94
|
+
mysql2
|
95
|
+
mysql_rewinder!
|
96
|
+
rake (~> 13.0)
|
97
|
+
rspec (~> 3.0)
|
98
|
+
steep
|
99
|
+
trilogy
|
100
|
+
|
101
|
+
BUNDLED WITH
|
102
|
+
2.3.15
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Yusuke Sangenya
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# MysqlRewinder
|
2
|
+
|
3
|
+
MysqlRewinder is a simple, stable, and fast database cleaner for mysql.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
* Fast cleanup using `DELETE` query
|
8
|
+
* Supports multi-database
|
9
|
+
* Supports both `mysql2` and `trilogy` as a client library
|
10
|
+
* Works without ActiveRecord
|
11
|
+
* Works with `fork`
|
12
|
+
|
13
|
+
## How does it work?
|
14
|
+
|
15
|
+
1. Capture SQL statements during test execution and extract `INSERT`ed table names, and record them into temporary files
|
16
|
+
2. Aggregate tmp files and execute DELETE query for `INSERT`ed tables
|
17
|
+
|
18
|
+
## What does `stable` mean?
|
19
|
+
|
20
|
+
MysqlRewinder is stable because it does not depend on ActiveRecord's internal implementation.
|
21
|
+
It only depends on `Mysql2::Client#query` and `Trilogy#query`.
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
Add this line to your Gemfile's `:test` group:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'trilogy'
|
29
|
+
# gem 'mysql2' # described later
|
30
|
+
gem 'mysql_rewinder'
|
31
|
+
```
|
32
|
+
|
33
|
+
And then execute:
|
34
|
+
|
35
|
+
```shell
|
36
|
+
$ bundle
|
37
|
+
```
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
### Basic configuration
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
RSpec.configure do |config|
|
45
|
+
config.before(:suite) do
|
46
|
+
db_config = {
|
47
|
+
host: '127.0.0.1',
|
48
|
+
port: '3306',
|
49
|
+
username: 'user1',
|
50
|
+
password: 'my_secure_password',
|
51
|
+
database: 'myapp-test'
|
52
|
+
}
|
53
|
+
MysqlRewinder.setup([db_config])
|
54
|
+
MysqlRewinder.clean_all
|
55
|
+
end
|
56
|
+
|
57
|
+
config.after(:each) do
|
58
|
+
MysqlRewinder.clean
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
### Multi-database
|
64
|
+
|
65
|
+
Pass all configurations to `MysqlRewinder.setup`.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
MysqlRewinder.setup(
|
69
|
+
[
|
70
|
+
{ host: '127.0.0.1', port: '3306', username: 'user1', password: 'my_secure_password', database: 'myapp-test-shard1' },
|
71
|
+
{ host: '127.0.0.1', port: '3306', username: 'user1', password: 'my_secure_password', database: 'myapp-test-shard2' },
|
72
|
+
]
|
73
|
+
)
|
74
|
+
```
|
75
|
+
|
76
|
+
### mysql2
|
77
|
+
|
78
|
+
If you want to use `mysql2` as a client library, do the following:
|
79
|
+
|
80
|
+
* Write `gem 'mysql2'` in your `Gemfile`
|
81
|
+
* Pass `adapter: :mysql2` to `MysqlRewinder.setup`.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
MysqlRewinder.setup(db_configs, adapter: :mysql2)
|
85
|
+
```
|
86
|
+
|
87
|
+
### ActiveRecord
|
88
|
+
|
89
|
+
If you want to use MysqlRewinder with ActiveRecord, do the following:
|
90
|
+
|
91
|
+
* Generate db_configs from `ActiveRecord::Base.configurations`
|
92
|
+
* Pass `ActiveRecord::SchemaMigration.new(nil).table_name` and `ActiveRecord::Base.internal_metadata_table_name` to `DatabaseRewinder.setup` as `except_tables`
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
db_configs = ActiveRecord::Base.configurations.configs_for(env_name: 'test').map(&:configuration_hash)
|
96
|
+
except_tables = [
|
97
|
+
ActiveRecord::Base.internal_metadata_table_name,
|
98
|
+
|
99
|
+
# for AR >= 7.1
|
100
|
+
ActiveRecord::SchemaMigration.new(nil).table_name,
|
101
|
+
# for AR < 7.1
|
102
|
+
# ActiveRecord::SchemaMigration.table_name,
|
103
|
+
]
|
104
|
+
|
105
|
+
MysqlRewinder.setup(db_configs, except_tables: except_tables)
|
106
|
+
```
|
107
|
+
|
108
|
+
## License
|
109
|
+
|
110
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
111
|
+
|
112
|
+
## Special Thanks
|
113
|
+
|
114
|
+
* Thank you [@aeroastro](https://github.com/aeroastro) for the idea of using temporary files
|
115
|
+
* This gem is heavily inspired by [amatsuda/database_rewinder](https://github.com/amatsuda/database_rewinder).
|
data/Rakefile
ADDED
data/Steepfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
D = Steep::Diagnostic
|
2
|
+
|
3
|
+
target :lib do
|
4
|
+
signature "sig"
|
5
|
+
|
6
|
+
check "lib"
|
7
|
+
|
8
|
+
library "pathname"
|
9
|
+
library "fileutils"
|
10
|
+
library "tmpdir"
|
11
|
+
library "forwardable"
|
12
|
+
|
13
|
+
configure_code_diagnostics(D::Ruby.lenient)
|
14
|
+
end
|
15
|
+
|
16
|
+
target :test do
|
17
|
+
signature "sig", "sig-private"
|
18
|
+
|
19
|
+
check "test"
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class MysqlRewinder
|
2
|
+
class Cleaner
|
3
|
+
class Adapter
|
4
|
+
def self.generate(adapter, config)
|
5
|
+
case adapter
|
6
|
+
when :trilogy
|
7
|
+
require 'trilogy'
|
8
|
+
require_relative '../ext/trilogy'
|
9
|
+
|
10
|
+
TrilogyAdapter.new(config)
|
11
|
+
when :mysql2
|
12
|
+
require 'mysql2'
|
13
|
+
require_relative '../ext/mysql2_client'
|
14
|
+
|
15
|
+
Mysql2Adapter.new(config)
|
16
|
+
else
|
17
|
+
raise 'adapter must be either :trilogy or :mysql2'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(_config); end
|
22
|
+
|
23
|
+
def query(sql)
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute(sql)
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class MysqlRewinder
|
2
|
+
class Cleaner
|
3
|
+
class Mysql2Adapter < Adapter
|
4
|
+
def initialize(db_config)
|
5
|
+
super
|
6
|
+
@db_config = db_config
|
7
|
+
connect
|
8
|
+
end
|
9
|
+
|
10
|
+
def query(sql)
|
11
|
+
with_reconnect do
|
12
|
+
@client.query(sql, as: :array).to_a
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(sql)
|
17
|
+
with_reconnect do
|
18
|
+
@client.query(sql)
|
19
|
+
@client.store_result while @client.next_result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def with_reconnect(&block)
|
25
|
+
retry_count = 0
|
26
|
+
begin
|
27
|
+
block.call
|
28
|
+
rescue Mysql2::Error => e
|
29
|
+
raise e if retry_count > 3
|
30
|
+
|
31
|
+
connect
|
32
|
+
retry_count += 1
|
33
|
+
|
34
|
+
retry
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def connect
|
39
|
+
@client&.close
|
40
|
+
@client = Mysql2::Client.new(@db_config.merge(connect_flags: Mysql2::Client::MULTI_STATEMENTS))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class MysqlRewinder
|
2
|
+
class Cleaner
|
3
|
+
class TrilogyAdapter < Adapter
|
4
|
+
def initialize(db_config)
|
5
|
+
super
|
6
|
+
@db_config = db_config
|
7
|
+
connect
|
8
|
+
end
|
9
|
+
|
10
|
+
def query(sql)
|
11
|
+
with_reconnect do
|
12
|
+
@client.query(sql).to_a
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(sql)
|
17
|
+
with_reconnect do
|
18
|
+
@client.query(sql)
|
19
|
+
@client.next_result while @client.more_results_exist?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def with_reconnect(&block)
|
25
|
+
retry_count = 0
|
26
|
+
begin
|
27
|
+
block.call
|
28
|
+
rescue Trilogy::Error => e
|
29
|
+
raise e if retry_count > 3
|
30
|
+
|
31
|
+
connect
|
32
|
+
retry_count += 1
|
33
|
+
|
34
|
+
retry
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def connect
|
39
|
+
@client&.close
|
40
|
+
@client = Trilogy.new(@db_config.merge(multi_statement: true))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'cleaner/adapter'
|
2
|
+
require_relative 'cleaner/mysql2_adapter'
|
3
|
+
require_relative 'cleaner/trilogy_adapter'
|
4
|
+
|
5
|
+
class MysqlRewinder
|
6
|
+
class Cleaner
|
7
|
+
attr_reader :db_config
|
8
|
+
|
9
|
+
def initialize(db_config, except_tables:, adapter:)
|
10
|
+
@db_config = db_config
|
11
|
+
@client = Adapter.generate(adapter, db_config.transform_keys(&:to_sym))
|
12
|
+
@except_tables = except_tables
|
13
|
+
end
|
14
|
+
|
15
|
+
def clean_all
|
16
|
+
clean(tables: all_tables)
|
17
|
+
end
|
18
|
+
|
19
|
+
def clean(tables:)
|
20
|
+
target_tables = (tables - @except_tables) & all_tables
|
21
|
+
return if target_tables.empty?
|
22
|
+
|
23
|
+
@client.execute(target_tables.map { |table| "DELETE FROM #{table}" }.join(';'))
|
24
|
+
end
|
25
|
+
|
26
|
+
def all_tables
|
27
|
+
@all_tables ||= @client.query(<<~SQL).flatten
|
28
|
+
SELECT TABLE_NAME
|
29
|
+
FROM INFORMATION_SCHEMA.TABLES
|
30
|
+
WHERE TABLE_SCHEMA = DATABASE()
|
31
|
+
SQL
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "mysql_rewinder/version"
|
4
|
+
require_relative "mysql_rewinder/cleaner"
|
5
|
+
require 'set'
|
6
|
+
require 'tmpdir'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'forwardable'
|
9
|
+
|
10
|
+
class MysqlRewinder
|
11
|
+
class << self
|
12
|
+
extend Forwardable
|
13
|
+
delegate %i[clean clean_all record_inserted_table] => :@instance
|
14
|
+
|
15
|
+
def setup(db_configs, except_tables: [], adapter: :trilogy)
|
16
|
+
@instance = new(db_configs: db_configs, except_tables: except_tables, adapter: adapter)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(db_configs:, except_tables:, adapter:)
|
21
|
+
@initialized_pid = Process.pid
|
22
|
+
@inserted_table_record_dir = Pathname(Dir.tmpdir)
|
23
|
+
@cleaners = db_configs.map do |db_config|
|
24
|
+
Cleaner.new(
|
25
|
+
db_config.transform_keys(&:to_sym),
|
26
|
+
except_tables: except_tables,
|
27
|
+
adapter: adapter
|
28
|
+
)
|
29
|
+
end
|
30
|
+
reset_inserted_tables
|
31
|
+
end
|
32
|
+
|
33
|
+
def record_inserted_table(sql)
|
34
|
+
return unless @initialized_pid
|
35
|
+
|
36
|
+
@inserted_tables ||= Set.new
|
37
|
+
sql.split(';').each do |statement|
|
38
|
+
match = statement.match(/\A\s*INSERT(?:\s+IGNORE)?(?:\s+INTO)?\s+(?:\.*[`"]?([^.\s`"(]+)[`"]?)*/i)
|
39
|
+
next unless match
|
40
|
+
|
41
|
+
table = match[1]
|
42
|
+
@inserted_tables << table if table
|
43
|
+
end
|
44
|
+
File.write(
|
45
|
+
@inserted_table_record_dir.join("#{@initialized_pid}.#{Process.pid}.inserted_tables").to_s,
|
46
|
+
@inserted_tables.to_a.join(',')
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset_inserted_tables
|
51
|
+
unless @initialized_pid == Process.pid
|
52
|
+
raise "MysqlRewinder is initialize in process #{@initialized_pid}, but reset_inserted_tables is called in process #{Process.pid}"
|
53
|
+
end
|
54
|
+
|
55
|
+
@inserted_tables = Set.new
|
56
|
+
FileUtils.rm(Dir.glob(@inserted_table_record_dir.join("#{@initialized_pid}.*.inserted_tables").to_s))
|
57
|
+
end
|
58
|
+
|
59
|
+
def calculate_inserted_tables
|
60
|
+
unless @initialized_pid == Process.pid
|
61
|
+
raise "MysqlRewinder is initialize in process #{@initialized_pid}, but calculate_inserted_tables is called in process #{Process.pid}"
|
62
|
+
end
|
63
|
+
|
64
|
+
Dir.glob(@inserted_table_record_dir.join("#{@initialized_pid}.*.inserted_tables").to_s).flat_map do |fname|
|
65
|
+
File.read(fname).strip.split(',')
|
66
|
+
end.uniq
|
67
|
+
end
|
68
|
+
|
69
|
+
def clean_all
|
70
|
+
@cleaners.each(&:clean_all)
|
71
|
+
reset_inserted_tables
|
72
|
+
end
|
73
|
+
|
74
|
+
def clean
|
75
|
+
aggregated_inserted_tables = calculate_inserted_tables
|
76
|
+
@cleaners.each { |c| c.clean(tables: aggregated_inserted_tables) }
|
77
|
+
reset_inserted_tables
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/mysql_rewinder/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "mysql_rewinder"
|
7
|
+
spec.version = MysqlRewinder::VERSION
|
8
|
+
spec.authors = ["Yusuke Sangenya"]
|
9
|
+
spec.email = ["longinus.eva@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Simple, stable, and fast database cleaner for mysql"
|
12
|
+
spec.homepage = "https://github.com/genya0407/mysql_rewinder"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = ">= 3.0.0"
|
15
|
+
|
16
|
+
spec.files = Dir.chdir(__dir__) do
|
17
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class MysqlRewinder
|
2
|
+
class Cleaner
|
3
|
+
class Adapter
|
4
|
+
def self.generate: (Symbol adapter, Hash[Symbol,String] db_config) -> Adapter
|
5
|
+
def initialize: (Hash[Symbol,String] db_config) -> untyped
|
6
|
+
def query: (String sql) -> Array[Array[Object]]
|
7
|
+
def execute: (String sql) -> void
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class MysqlRewinder
|
2
|
+
class Cleaner
|
3
|
+
@db_config: Hash[Symbol,String]
|
4
|
+
@client: Adapter
|
5
|
+
@except_tables: Array[String]
|
6
|
+
@all_tables: Array[String]
|
7
|
+
|
8
|
+
attr_reader db_config: Hash[Symbol,String]
|
9
|
+
|
10
|
+
def initialize: (Hash[Symbol,String] db_config, except_tables: Array[String], adapter: Symbol) -> untyped
|
11
|
+
def clean_all: () -> void
|
12
|
+
def clean: (tables: untyped) -> void
|
13
|
+
def all_tables: () -> void
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Mysql2
|
2
|
+
class Result < Enumerator[Array[Object], void]
|
3
|
+
end
|
4
|
+
class Error < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
class Client
|
8
|
+
MULTI_STATEMENTS: Integer
|
9
|
+
|
10
|
+
def initialize: (Hash[Symbol, Object] config) -> untyped
|
11
|
+
def close: () -> void
|
12
|
+
def next_result: () -> bool
|
13
|
+
def store_result: () -> Array[Object]
|
14
|
+
def query: (String sql, ?Hash[Symbol, Object] _options) -> Array[Array[Object]]
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Trilogy
|
2
|
+
class Result < Enumerator[Array[Object], void]
|
3
|
+
end
|
4
|
+
class Error < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize: (Hash[Symbol,Object] config) -> untyped
|
8
|
+
def close: () -> void
|
9
|
+
def more_results_exist?: () -> bool
|
10
|
+
def next_result: () -> Array[Object]
|
11
|
+
def query: (String sql) -> Array[Array[Object]]
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class MysqlRewinder
|
2
|
+
self.@instance: MysqlRewinder
|
3
|
+
@initialized_pid: Integer
|
4
|
+
@inserted_table_record_dir: Object
|
5
|
+
# @inserted_table_record_dir: Pathname
|
6
|
+
@cleaners: Array[Cleaner]
|
7
|
+
@inserted_tables: Set[String]
|
8
|
+
|
9
|
+
def self.setup: (Array[Hash[Symbol,String]] db_configs, ?except_tables: Array[String], ?adapter: ::Symbol) -> void
|
10
|
+
def self.clean_all: () -> void
|
11
|
+
def self.clean: () -> void
|
12
|
+
def self.record_inserted_table: (String sql) -> void
|
13
|
+
|
14
|
+
def initialize: (db_configs: Array[Hash[Symbol,String]], except_tables: Array[String], adapter: ::Symbol) -> untyped
|
15
|
+
def record_inserted_table: (String sql) -> void
|
16
|
+
def reset_inserted_tables: () -> void
|
17
|
+
def calculate_inserted_tables: () -> void
|
18
|
+
def clean_all: () -> void
|
19
|
+
def clean: () -> void
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mysql_rewinder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yusuke Sangenya
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-11-12 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email:
|
15
|
+
- longinus.eva@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rspec"
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- Steepfile
|
27
|
+
- lib/mysql_rewinder.rb
|
28
|
+
- lib/mysql_rewinder/cleaner.rb
|
29
|
+
- lib/mysql_rewinder/cleaner/adapter.rb
|
30
|
+
- lib/mysql_rewinder/cleaner/mysql2_adapter.rb
|
31
|
+
- lib/mysql_rewinder/cleaner/trilogy_adapter.rb
|
32
|
+
- lib/mysql_rewinder/ext/mysql2_client.rb
|
33
|
+
- lib/mysql_rewinder/ext/trilogy.rb
|
34
|
+
- lib/mysql_rewinder/version.rb
|
35
|
+
- mysql_rewinder.gemspec
|
36
|
+
- sig/mysql_rewinder.rbs
|
37
|
+
- sig/mysql_rewinder/cleaner.rbs
|
38
|
+
- sig/mysql_rewinder/cleaner/adapter.rbs
|
39
|
+
- sig/mysql_rewinder/cleaner/mysql2_adapter.rbs
|
40
|
+
- sig/mysql_rewinder/cleaner/trilogy_adapter.rbs
|
41
|
+
- sig/mysql_rewinder/ext/mysql2_client.rbs
|
42
|
+
- sig/mysql_rewinder/ext/trilogy.rbs
|
43
|
+
- sig/mysql_rewinder/mysql2.rbs
|
44
|
+
- sig/mysql_rewinder/trilogy.rbs
|
45
|
+
- sig/mysql_rewinder/version.rbs
|
46
|
+
homepage: https://github.com/genya0407/mysql_rewinder
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
metadata: {}
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 3.0.0
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubygems_version: 3.4.10
|
66
|
+
signing_key:
|
67
|
+
specification_version: 4
|
68
|
+
summary: Simple, stable, and fast database cleaner for mysql
|
69
|
+
test_files: []
|