activerecord-tidb-adapter 0.2.0 → 6.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 +4 -4
- data/.gitignore +5 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +134 -12
- data/README.md +107 -4
- data/Rakefile +50 -5
- data/config.toml +1 -0
- data/lib/active_record/connection_adapters/tidb/type.rb +2 -0
- data/lib/active_record/connection_adapters/tidb_adapter.rb +52 -9
- data/lib/active_record/sequence.rb +21 -0
- data/lib/active_record/sequence/adapter.rb +50 -0
- data/lib/active_record/sequence/command_recorder.rb +20 -0
- data/lib/active_record/sequence/model_methods.rb +22 -0
- data/lib/active_record/sequence/schema_dumper.rb +54 -0
- data/lib/version.rb +1 -1
- metadata +8 -3
- data/.github/workflows/main.yml +0 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f82e1eb06fb93971e146fafade1c45e2e3c5909e3968f32a719c9581efb55f3
|
|
4
|
+
data.tar.gz: 5a0bc0100489a41230115924cbff3f52e1ef2206441724116135ed01ccdd28da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b059eabd253b3e7e0ead32528ac380d874dd9ab42ff942ec86ff3ddec86257b00aa5aea3c44912f95d3c0c8ba2dc7e8ba0a33abff668f6100f929fc2ed45f61
|
|
7
|
+
data.tar.gz: 216b0b9917670ca40cd30d3c243493e88aaf2279d946b68eaa927b0a65d78226e075279f12c8839f32a4d9be8b3edb7c348ba2038cd25bfa2845dc62aa9d4944
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
|
@@ -8,7 +8,16 @@ gemspec
|
|
|
8
8
|
gem 'rake', '~> 13.0'
|
|
9
9
|
|
|
10
10
|
gem 'minitest', '~> 5.0'
|
|
11
|
+
gem 'minitest-excludes', '~> 2.0'
|
|
11
12
|
|
|
12
13
|
gem 'pry'
|
|
13
14
|
|
|
14
15
|
gem 'rubocop', '~> 1.18'
|
|
16
|
+
|
|
17
|
+
gem 'rails', git: 'https://github.com/pingcap/rails.git', branch: '6-1-stable'
|
|
18
|
+
|
|
19
|
+
gem 'byebug', '~> 11.1'
|
|
20
|
+
|
|
21
|
+
gem 'sqlite3', '~> 1.4'
|
|
22
|
+
|
|
23
|
+
gem 'pg', '~> 1.2'
|
data/Gemfile.lock
CHANGED
|
@@ -1,57 +1,174 @@
|
|
|
1
|
-
|
|
2
|
-
remote: .
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
activerecord (~> 6.1)
|
|
6
|
-
mysql2
|
|
7
|
-
|
|
8
|
-
GEM
|
|
9
|
-
remote: https://rubygems.org/
|
|
1
|
+
GIT
|
|
2
|
+
remote: https://github.com/pingcap/rails.git
|
|
3
|
+
revision: e2a3d3fb2ee24c709b9f32221fbcb66cfda5acfc
|
|
4
|
+
branch: 6-1-stable
|
|
10
5
|
specs:
|
|
6
|
+
actioncable (6.1.4)
|
|
7
|
+
actionpack (= 6.1.4)
|
|
8
|
+
activesupport (= 6.1.4)
|
|
9
|
+
nio4r (~> 2.0)
|
|
10
|
+
websocket-driver (>= 0.6.1)
|
|
11
|
+
actionmailbox (6.1.4)
|
|
12
|
+
actionpack (= 6.1.4)
|
|
13
|
+
activejob (= 6.1.4)
|
|
14
|
+
activerecord (= 6.1.4)
|
|
15
|
+
activestorage (= 6.1.4)
|
|
16
|
+
activesupport (= 6.1.4)
|
|
17
|
+
mail (>= 2.7.1)
|
|
18
|
+
actionmailer (6.1.4)
|
|
19
|
+
actionpack (= 6.1.4)
|
|
20
|
+
actionview (= 6.1.4)
|
|
21
|
+
activejob (= 6.1.4)
|
|
22
|
+
activesupport (= 6.1.4)
|
|
23
|
+
mail (~> 2.5, >= 2.5.4)
|
|
24
|
+
rails-dom-testing (~> 2.0)
|
|
25
|
+
actionpack (6.1.4)
|
|
26
|
+
actionview (= 6.1.4)
|
|
27
|
+
activesupport (= 6.1.4)
|
|
28
|
+
rack (~> 2.0, >= 2.0.9)
|
|
29
|
+
rack-test (>= 0.6.3)
|
|
30
|
+
rails-dom-testing (~> 2.0)
|
|
31
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
32
|
+
actiontext (6.1.4)
|
|
33
|
+
actionpack (= 6.1.4)
|
|
34
|
+
activerecord (= 6.1.4)
|
|
35
|
+
activestorage (= 6.1.4)
|
|
36
|
+
activesupport (= 6.1.4)
|
|
37
|
+
nokogiri (>= 1.8.5)
|
|
38
|
+
actionview (6.1.4)
|
|
39
|
+
activesupport (= 6.1.4)
|
|
40
|
+
builder (~> 3.1)
|
|
41
|
+
erubi (~> 1.4)
|
|
42
|
+
rails-dom-testing (~> 2.0)
|
|
43
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
44
|
+
activejob (6.1.4)
|
|
45
|
+
activesupport (= 6.1.4)
|
|
46
|
+
globalid (>= 0.3.6)
|
|
11
47
|
activemodel (6.1.4)
|
|
12
48
|
activesupport (= 6.1.4)
|
|
13
49
|
activerecord (6.1.4)
|
|
14
50
|
activemodel (= 6.1.4)
|
|
15
51
|
activesupport (= 6.1.4)
|
|
52
|
+
activestorage (6.1.4)
|
|
53
|
+
actionpack (= 6.1.4)
|
|
54
|
+
activejob (= 6.1.4)
|
|
55
|
+
activerecord (= 6.1.4)
|
|
56
|
+
activesupport (= 6.1.4)
|
|
57
|
+
marcel (~> 1.0.0)
|
|
58
|
+
mini_mime (>= 1.1.0)
|
|
16
59
|
activesupport (6.1.4)
|
|
17
60
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
18
61
|
i18n (>= 1.6, < 2)
|
|
19
62
|
minitest (>= 5.1)
|
|
20
63
|
tzinfo (~> 2.0)
|
|
21
64
|
zeitwerk (~> 2.3)
|
|
65
|
+
rails (6.1.4)
|
|
66
|
+
actioncable (= 6.1.4)
|
|
67
|
+
actionmailbox (= 6.1.4)
|
|
68
|
+
actionmailer (= 6.1.4)
|
|
69
|
+
actionpack (= 6.1.4)
|
|
70
|
+
actiontext (= 6.1.4)
|
|
71
|
+
actionview (= 6.1.4)
|
|
72
|
+
activejob (= 6.1.4)
|
|
73
|
+
activemodel (= 6.1.4)
|
|
74
|
+
activerecord (= 6.1.4)
|
|
75
|
+
activestorage (= 6.1.4)
|
|
76
|
+
activesupport (= 6.1.4)
|
|
77
|
+
bundler (>= 1.15.0)
|
|
78
|
+
railties (= 6.1.4)
|
|
79
|
+
sprockets-rails (>= 2.0.0)
|
|
80
|
+
railties (6.1.4)
|
|
81
|
+
actionpack (= 6.1.4)
|
|
82
|
+
activesupport (= 6.1.4)
|
|
83
|
+
method_source
|
|
84
|
+
rake (>= 0.13)
|
|
85
|
+
thor (~> 1.0)
|
|
86
|
+
|
|
87
|
+
PATH
|
|
88
|
+
remote: .
|
|
89
|
+
specs:
|
|
90
|
+
activerecord-tidb-adapter (6.1.0)
|
|
91
|
+
activerecord (~> 6.1)
|
|
92
|
+
mysql2
|
|
93
|
+
|
|
94
|
+
GEM
|
|
95
|
+
remote: https://rubygems.org/
|
|
96
|
+
specs:
|
|
22
97
|
ast (2.4.2)
|
|
98
|
+
builder (3.2.4)
|
|
99
|
+
byebug (11.1.3)
|
|
23
100
|
coderay (1.1.3)
|
|
24
101
|
concurrent-ruby (1.1.9)
|
|
102
|
+
crass (1.0.6)
|
|
103
|
+
erubi (1.10.0)
|
|
104
|
+
globalid (0.5.2)
|
|
105
|
+
activesupport (>= 5.0)
|
|
25
106
|
i18n (1.8.10)
|
|
26
107
|
concurrent-ruby (~> 1.0)
|
|
108
|
+
loofah (2.12.0)
|
|
109
|
+
crass (~> 1.0.2)
|
|
110
|
+
nokogiri (>= 1.5.9)
|
|
111
|
+
mail (2.7.1)
|
|
112
|
+
mini_mime (>= 0.1.1)
|
|
113
|
+
marcel (1.0.1)
|
|
27
114
|
method_source (1.0.0)
|
|
115
|
+
mini_mime (1.1.0)
|
|
28
116
|
minitest (5.14.4)
|
|
117
|
+
minitest-excludes (2.0.1)
|
|
118
|
+
minitest (~> 5.0)
|
|
29
119
|
mysql2 (0.5.3)
|
|
120
|
+
nio4r (2.5.8)
|
|
121
|
+
nokogiri (1.12.3-x86_64-darwin)
|
|
122
|
+
racc (~> 1.4)
|
|
123
|
+
nokogiri (1.12.3-x86_64-linux)
|
|
124
|
+
racc (~> 1.4)
|
|
30
125
|
parallel (1.20.1)
|
|
31
126
|
parser (3.0.2.0)
|
|
32
127
|
ast (~> 2.4.1)
|
|
128
|
+
pg (1.2.3)
|
|
33
129
|
pry (0.14.1)
|
|
34
130
|
coderay (~> 1.1)
|
|
35
131
|
method_source (~> 1.0)
|
|
132
|
+
racc (1.5.2)
|
|
133
|
+
rack (2.2.3)
|
|
134
|
+
rack-test (1.1.0)
|
|
135
|
+
rack (>= 1.0, < 3)
|
|
136
|
+
rails-dom-testing (2.0.3)
|
|
137
|
+
activesupport (>= 4.2.0)
|
|
138
|
+
nokogiri (>= 1.6)
|
|
139
|
+
rails-html-sanitizer (1.4.1)
|
|
140
|
+
loofah (~> 2.3)
|
|
36
141
|
rainbow (3.0.0)
|
|
37
142
|
rake (13.0.6)
|
|
38
143
|
regexp_parser (2.1.1)
|
|
39
144
|
rexml (3.2.5)
|
|
40
|
-
rubocop (1.
|
|
145
|
+
rubocop (1.19.0)
|
|
41
146
|
parallel (~> 1.10)
|
|
42
147
|
parser (>= 3.0.0.0)
|
|
43
148
|
rainbow (>= 2.2.2, < 4.0)
|
|
44
149
|
regexp_parser (>= 1.8, < 3.0)
|
|
45
150
|
rexml
|
|
46
|
-
rubocop-ast (>= 1.
|
|
151
|
+
rubocop-ast (>= 1.9.1, < 2.0)
|
|
47
152
|
ruby-progressbar (~> 1.7)
|
|
48
153
|
unicode-display_width (>= 1.4.0, < 3.0)
|
|
49
|
-
rubocop-ast (1.
|
|
154
|
+
rubocop-ast (1.10.0)
|
|
50
155
|
parser (>= 3.0.1.1)
|
|
51
156
|
ruby-progressbar (1.11.0)
|
|
157
|
+
sprockets (4.0.2)
|
|
158
|
+
concurrent-ruby (~> 1.0)
|
|
159
|
+
rack (> 1, < 3)
|
|
160
|
+
sprockets-rails (3.2.2)
|
|
161
|
+
actionpack (>= 4.0)
|
|
162
|
+
activesupport (>= 4.0)
|
|
163
|
+
sprockets (>= 3.0.0)
|
|
164
|
+
sqlite3 (1.4.2)
|
|
165
|
+
thor (1.1.0)
|
|
52
166
|
tzinfo (2.0.4)
|
|
53
167
|
concurrent-ruby (~> 1.0)
|
|
54
168
|
unicode-display_width (2.0.0)
|
|
169
|
+
websocket-driver (0.7.5)
|
|
170
|
+
websocket-extensions (>= 0.1.0)
|
|
171
|
+
websocket-extensions (0.1.5)
|
|
55
172
|
zeitwerk (2.4.2)
|
|
56
173
|
|
|
57
174
|
PLATFORMS
|
|
@@ -60,10 +177,15 @@ PLATFORMS
|
|
|
60
177
|
|
|
61
178
|
DEPENDENCIES
|
|
62
179
|
activerecord-tidb-adapter!
|
|
180
|
+
byebug (~> 11.1)
|
|
63
181
|
minitest (~> 5.0)
|
|
182
|
+
minitest-excludes (~> 2.0)
|
|
183
|
+
pg (~> 1.2)
|
|
64
184
|
pry
|
|
185
|
+
rails!
|
|
65
186
|
rake (~> 13.0)
|
|
66
187
|
rubocop (~> 1.18)
|
|
188
|
+
sqlite3 (~> 1.4)
|
|
67
189
|
|
|
68
190
|
BUNDLED WITH
|
|
69
191
|
2.2.25
|
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@ TiDB adapter for ActiveRecord 5 and 6. This is a lightweight extension of the my
|
|
|
8
8
|
Add this line to your application's Gemfile:
|
|
9
9
|
|
|
10
10
|
```ruby
|
|
11
|
-
gem 'activerecord-tidb-adapter'
|
|
11
|
+
gem 'activerecord-tidb-adapter', "~> 6.1.0"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
And then execute:
|
|
@@ -21,7 +21,7 @@ Or install it yourself as:
|
|
|
21
21
|
|
|
22
22
|
## Usage
|
|
23
23
|
|
|
24
|
-
database.yml
|
|
24
|
+
config/database.yml
|
|
25
25
|
|
|
26
26
|
```yml
|
|
27
27
|
default: &default
|
|
@@ -44,16 +44,119 @@ development:
|
|
|
44
44
|
|
|
45
45
|
* demo repo with rails 6.1.4: https://github.com/hooopo/activerecord-tidb-adapter-demo
|
|
46
46
|
|
|
47
|
+
## TiDB features
|
|
48
|
+
|
|
49
|
+
**[Sequence](https://docs.pingcap.com/tidb/stable/sql-statement-create-sequence)**
|
|
50
|
+
|
|
51
|
+
Sequence as primary key
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
class TestSeq < ActiveRecord::Migration[6.1]
|
|
55
|
+
def up
|
|
56
|
+
# more options: increment, min_value, cycle, cache
|
|
57
|
+
create_sequence :orders_seq, start: 1024
|
|
58
|
+
create_table :orders, id: false do |t|
|
|
59
|
+
t.primary_key :id, default: -> { "nextval(orders_seq)" }
|
|
60
|
+
t.string :name
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def down
|
|
65
|
+
drop_table :orders
|
|
66
|
+
drop_sequence :orders_seq
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Generated DDL
|
|
72
|
+
```sql
|
|
73
|
+
mysql> show create table orders_seq\G;
|
|
74
|
+
*************************** 1. row ***************************
|
|
75
|
+
Sequence: orders_seq
|
|
76
|
+
Create Sequence: CREATE SEQUENCE `orders_seq` start with 1024 minvalue 1 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=InnoDB
|
|
77
|
+
|
|
78
|
+
mysql> show create table orders\G;
|
|
79
|
+
*************************** 1. row ***************************
|
|
80
|
+
Table: orders
|
|
81
|
+
Create Table: CREATE TABLE `orders` (
|
|
82
|
+
`id` bigint(20) NOT NULL DEFAULT nextval(`activerecord_tidb_adapter_demo_development`.`orders_seq`),
|
|
83
|
+
`name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
|
84
|
+
PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */
|
|
85
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This gem also adds a few helpers to interact with `SEQUENCE`
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# Advance sequence and return new value
|
|
93
|
+
ActiveRecord::Base.nextval("numbers")
|
|
94
|
+
|
|
95
|
+
# Return value most recently obtained with nextval for specified sequence.
|
|
96
|
+
ActiveRecord::Base.lastval("numbers")
|
|
97
|
+
|
|
98
|
+
# Set sequence's current value
|
|
99
|
+
ActiveRecord::Base.setval("numbers", 1234)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## Setting up local TiDB server
|
|
104
|
+
|
|
105
|
+
Install [tiup](https://github.com/pingcap/tiup)
|
|
106
|
+
|
|
107
|
+
```shell
|
|
108
|
+
$ curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
|
|
109
|
+
```
|
|
110
|
+
Starting TiDB playground
|
|
111
|
+
|
|
112
|
+
```shell
|
|
113
|
+
$ tiup playground nightly
|
|
114
|
+
```
|
|
115
|
+
|
|
47
116
|
## Development
|
|
48
117
|
|
|
49
118
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
50
119
|
|
|
51
120
|
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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
52
121
|
|
|
122
|
+
## Testing
|
|
123
|
+
|
|
124
|
+
install gems
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
bundle install
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
start tidb server
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
tiup playground nightly
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
create database for testing
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake db:tidb:rebuild
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
run tidb adapter tests and activerecord buildin tests
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake test:tidb
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
run **ONLY** tidb adapter tests using `ONLY_TEST_TIDB` env:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
ONLY_TEST_TIDB=1 MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake test:tidb
|
|
154
|
+
```
|
|
155
|
+
|
|
53
156
|
## Contributing
|
|
54
157
|
|
|
55
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
|
158
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pingcap/activerecord-tidb-adapter.
|
|
56
159
|
|
|
57
160
|
## License
|
|
58
161
|
|
|
59
|
-
Apache 2.0
|
|
162
|
+
Apache 2.0
|
data/Rakefile
CHANGED
|
@@ -2,11 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
require 'bundler/gem_tasks'
|
|
4
4
|
require 'rake/testtask'
|
|
5
|
+
require 'pry'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
require_relative 'test/support/paths_tidb'
|
|
8
|
+
require_relative 'test/support/rake_helpers'
|
|
9
|
+
require_relative 'test/support/config'
|
|
10
|
+
|
|
11
|
+
task test: ['test:tidb']
|
|
12
|
+
task default: [:test]
|
|
13
|
+
|
|
14
|
+
namespace :test do
|
|
15
|
+
Rake::TestTask.new('tidb') do |t|
|
|
16
|
+
t.libs = ARTest::TiDB.test_load_paths
|
|
17
|
+
t.test_files = test_files
|
|
18
|
+
t.warning = !ENV['WARNING'].nil?
|
|
19
|
+
t.verbose = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
task 'tidb:env' do
|
|
23
|
+
ENV['ARCONN'] = 'tidb'
|
|
24
|
+
ENV['tidb'] = '1'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
task 'test:tidb' => 'test:tidb:env'
|
|
29
|
+
|
|
30
|
+
namespace :db do
|
|
31
|
+
namespace :tidb do
|
|
32
|
+
connection_arguments = lambda do |connection_name|
|
|
33
|
+
config = ARTest.config['connections']['tidb'][connection_name]
|
|
34
|
+
["--user=#{config['username']}", "--password=#{config['password']}", "--port=#{config['port']}",
|
|
35
|
+
("--host=#{config['host']}" if config['host'])].join(' ')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc 'Build the TiDB test databases'
|
|
39
|
+
task :build do
|
|
40
|
+
config = ARTest.config['connections']['tidb']
|
|
41
|
+
`mysql #{connection_arguments['arunit']} -e "create DATABASE #{config['arunit']['database']} DEFAULT CHARACTER SET utf8mb4 COLLATE #{config['arunit']['collation']}"`
|
|
42
|
+
`mysql #{connection_arguments['arunit2']} -e "create DATABASE #{config['arunit2']['database']} DEFAULT CHARACTER SET utf8mb4 COLLATE #{config['arunit2']['collation']}"`
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc 'Drop the TiDB test databases'
|
|
46
|
+
task :drop do
|
|
47
|
+
config = ARTest.config['connections']['tidb']
|
|
48
|
+
`mysqladmin #{connection_arguments['arunit']} -f drop #{config['arunit']['database']}`
|
|
49
|
+
`mysqladmin #{connection_arguments['arunit2']} -f drop #{config['arunit2']['database']}`
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
desc 'Rebuild the TiDB test databases'
|
|
53
|
+
task rebuild: %i[drop build]
|
|
54
|
+
end
|
|
10
55
|
end
|
|
11
56
|
|
|
12
|
-
task
|
|
57
|
+
task build_mysql_databases: 'db:mysql:build'
|
data/config.toml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
new_collations_enabled_on_first_bootstrap = true
|
|
@@ -4,13 +4,14 @@ require 'active_record/connection_adapters'
|
|
|
4
4
|
require 'active_record/connection_adapters/mysql2_adapter'
|
|
5
5
|
require 'active_record/connection_adapters/tidb/setup'
|
|
6
6
|
require_relative '../../version'
|
|
7
|
+
require_relative '../sequence'
|
|
7
8
|
|
|
8
9
|
ActiveRecord::ConnectionAdapters::Tidb.initial_setup
|
|
9
10
|
|
|
10
11
|
module ActiveRecord
|
|
11
|
-
module ConnectionHandling
|
|
12
|
+
module ConnectionHandling # :nodoc:
|
|
12
13
|
# Establishes a connection to the database that's used by all Active Record objects.
|
|
13
|
-
def tidb_connection(config)
|
|
14
|
+
def tidb_connection(config) # :nodoc:
|
|
14
15
|
config = config.symbolize_keys
|
|
15
16
|
config[:flags] ||= 0
|
|
16
17
|
|
|
@@ -31,6 +32,7 @@ module ActiveRecord
|
|
|
31
32
|
|
|
32
33
|
module ConnectionAdapters
|
|
33
34
|
class TidbAdapter < Mysql2Adapter
|
|
35
|
+
include ActiveRecord::Sequence::Adapter
|
|
34
36
|
ADAPTER_NAME = 'Tidb'
|
|
35
37
|
|
|
36
38
|
def supports_savepoints?
|
|
@@ -67,11 +69,7 @@ module ActiveRecord
|
|
|
67
69
|
end
|
|
68
70
|
|
|
69
71
|
def supports_common_table_expressions?
|
|
70
|
-
|
|
71
|
-
true
|
|
72
|
-
else
|
|
73
|
-
false
|
|
74
|
-
end
|
|
72
|
+
tidb_version >= '5.1.0'
|
|
75
73
|
end
|
|
76
74
|
|
|
77
75
|
def transaction_isolation_levels
|
|
@@ -85,7 +83,7 @@ module ActiveRecord
|
|
|
85
83
|
super(connection, logger, conn_params, config)
|
|
86
84
|
|
|
87
85
|
tidb_version_string = query_value('select version()')
|
|
88
|
-
@tidb_version = tidb_version_string[/TiDB-v([0-9
|
|
86
|
+
@tidb_version = tidb_version_string[/TiDB-v([0-9.]+)/, 1]
|
|
89
87
|
end
|
|
90
88
|
|
|
91
89
|
def tidb_version_string
|
|
@@ -97,10 +95,55 @@ module ActiveRecord
|
|
|
97
95
|
end
|
|
98
96
|
|
|
99
97
|
def self.database_exists?(config)
|
|
100
|
-
|
|
98
|
+
!ActiveRecord::Base.tidb_connection(config).nil?
|
|
101
99
|
rescue ActiveRecord::NoDatabaseError
|
|
102
100
|
false
|
|
103
101
|
end
|
|
102
|
+
|
|
103
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
|
104
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
|
105
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
|
106
|
+
return id_value if id_value.present?
|
|
107
|
+
|
|
108
|
+
model = arel.ast.relation.instance_variable_get(:@klass)
|
|
109
|
+
pk_def = schema_cache.columns_hash(model.table_name)[pk]
|
|
110
|
+
if pk_def&.default_function && pk_def.default_function =~ /nextval/
|
|
111
|
+
query_value("SELECT #{pk_def.default_function.sub('nextval', 'lastval')}")
|
|
112
|
+
elsif model.sequence_name
|
|
113
|
+
ActiveRecord::Base.lastval(model.sequence_name)
|
|
114
|
+
else
|
|
115
|
+
last_inserted_id(value)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
alias create insert
|
|
119
|
+
|
|
120
|
+
def new_column_from_field(_table_name, field)
|
|
121
|
+
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
|
122
|
+
default = field[:Default]
|
|
123
|
+
default_function = nil
|
|
124
|
+
|
|
125
|
+
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(default)
|
|
126
|
+
default_function = default
|
|
127
|
+
default = nil
|
|
128
|
+
elsif type_metadata.extra == 'DEFAULT_GENERATED'
|
|
129
|
+
default = +"(#{default})" unless default.start_with?('(')
|
|
130
|
+
default_function = default
|
|
131
|
+
default = nil
|
|
132
|
+
elsif default.to_s =~ /nextval/i
|
|
133
|
+
default_function = default
|
|
134
|
+
default = nil
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
MySQL::Column.new(
|
|
138
|
+
field[:Field],
|
|
139
|
+
default,
|
|
140
|
+
type_metadata,
|
|
141
|
+
field[:Null] == 'YES',
|
|
142
|
+
default_function,
|
|
143
|
+
collation: field[:Collation],
|
|
144
|
+
comment: field[:Comment].presence
|
|
145
|
+
)
|
|
146
|
+
end
|
|
104
147
|
end
|
|
105
148
|
end
|
|
106
149
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/all'
|
|
4
|
+
require 'active_record'
|
|
5
|
+
require 'active_record/connection_adapters/mysql/schema_dumper'
|
|
6
|
+
require 'active_record/migration/command_recorder'
|
|
7
|
+
require 'active_record/schema_dumper'
|
|
8
|
+
|
|
9
|
+
module ActiveRecord
|
|
10
|
+
module Sequence
|
|
11
|
+
require 'active_record/sequence/command_recorder'
|
|
12
|
+
require 'active_record/sequence/adapter'
|
|
13
|
+
require 'active_record/sequence/schema_dumper'
|
|
14
|
+
require 'active_record/sequence/model_methods'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
ActiveRecord::Migration::CommandRecorder.include(ActiveRecord::Sequence::CommandRecorder)
|
|
19
|
+
|
|
20
|
+
ActiveRecord::SchemaDumper.prepend(ActiveRecord::Sequence::SchemaDumper)
|
|
21
|
+
ActiveRecord::Base.extend(ActiveRecord::Sequence::ModelMethods)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Sequence
|
|
5
|
+
module Adapter
|
|
6
|
+
def check_sequences
|
|
7
|
+
select_all(
|
|
8
|
+
'SELECT * FROM information_schema.sequences ORDER BY sequence_name'
|
|
9
|
+
).to_a
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create_sequence(name, options = {})
|
|
13
|
+
increment = options[:increment] || options[:step]
|
|
14
|
+
name = quote_column_name(name)
|
|
15
|
+
|
|
16
|
+
sql = ["CREATE SEQUENCE IF NOT EXISTS #{name}"]
|
|
17
|
+
sql << "INCREMENT BY #{increment}" if increment
|
|
18
|
+
sql << "START WITH #{options[:start]}" if options[:start]
|
|
19
|
+
sql << if options[:cache]
|
|
20
|
+
"CACHE #{options[:cache]}"
|
|
21
|
+
else
|
|
22
|
+
'NOCACHE'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
sql << if options[:cycle]
|
|
26
|
+
'CYCLE'
|
|
27
|
+
else
|
|
28
|
+
'NOCYCLE'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
sql << "MIN_VALUE #{options[:min_value]}" if options[:min_value]
|
|
32
|
+
|
|
33
|
+
sql << "COMMENT #{quote(options[:comment].to_s)}" if options[:comment]
|
|
34
|
+
|
|
35
|
+
execute(sql.join("\n"))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def drop_sequence(name)
|
|
39
|
+
name = quote_column_name(name)
|
|
40
|
+
sql = "DROP SEQUENCE IF EXISTS #{name}"
|
|
41
|
+
execute(sql)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def recreate_sequence(name, options = {})
|
|
45
|
+
drop_sequence(name)
|
|
46
|
+
create_sequence(name, options)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Sequence
|
|
5
|
+
module CommandRecorder
|
|
6
|
+
def create_sequence(name, options = {})
|
|
7
|
+
record(__method__, [name, options])
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def drop_sequence(name)
|
|
11
|
+
record(__method__, [name])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def invert_create_sequence(args)
|
|
15
|
+
name, = args
|
|
16
|
+
[:drop_sequence, [name]]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Sequence
|
|
5
|
+
module ModelMethods
|
|
6
|
+
def nextval(name)
|
|
7
|
+
name = connection.quote_column_name(name)
|
|
8
|
+
connection.query_value("SELECT nextval(#{name})")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def lastval(name)
|
|
12
|
+
name = connection.quote_column_name(name)
|
|
13
|
+
connection.query_value("SELECT lastval(#{name})")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def setval(name, value)
|
|
17
|
+
name = connection.quote_column_name(name)
|
|
18
|
+
connection.query_value("SELECT setval(#{name}, #{value})")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module Sequence
|
|
5
|
+
module SchemaDumper
|
|
6
|
+
def header(stream)
|
|
7
|
+
super
|
|
8
|
+
sequences(stream)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def sequences(stream)
|
|
12
|
+
sequences = @connection.check_sequences
|
|
13
|
+
return if sequences.empty?
|
|
14
|
+
|
|
15
|
+
sequences.each do |seq|
|
|
16
|
+
start_value = seq['START']
|
|
17
|
+
increment = seq['INCREMENT']
|
|
18
|
+
cache = seq['CACHE']
|
|
19
|
+
cache_value = seq['CACHE_VALUE']
|
|
20
|
+
min_value = seq['MIN_VALUE']
|
|
21
|
+
cycle = seq['CYCLE']
|
|
22
|
+
comment = seq['COMMENT']
|
|
23
|
+
|
|
24
|
+
options = []
|
|
25
|
+
|
|
26
|
+
options << "start: #{start_value}" if start_value && Integer(start_value) != 1
|
|
27
|
+
|
|
28
|
+
options << "increment: #{increment}" if increment && Integer(increment) != 1
|
|
29
|
+
|
|
30
|
+
options << "cache: #{cache_value}" if cache_value && Integer(cache_value) != 0
|
|
31
|
+
|
|
32
|
+
options << "min_value: #{min_value}" if min_value
|
|
33
|
+
|
|
34
|
+
options << 'cycle: true' if cycle.to_i != 0
|
|
35
|
+
|
|
36
|
+
options << "comment: #{comment.inspect}" if comment.present?
|
|
37
|
+
|
|
38
|
+
statement = [
|
|
39
|
+
'create_sequence',
|
|
40
|
+
seq['SEQUENCE_NAME'].inspect
|
|
41
|
+
].join(' ')
|
|
42
|
+
|
|
43
|
+
if options.any?
|
|
44
|
+
statement << (options.any? ? ", #{options.join(', ')}" : '')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
stream.puts " #{statement}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
stream.puts
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-tidb-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hooopo Wang
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-08-
|
|
11
|
+
date: 2021-08-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -45,7 +45,6 @@ executables: []
|
|
|
45
45
|
extensions: []
|
|
46
46
|
extra_rdoc_files: []
|
|
47
47
|
files:
|
|
48
|
-
- ".github/workflows/main.yml"
|
|
49
48
|
- ".gitignore"
|
|
50
49
|
- Gemfile
|
|
51
50
|
- Gemfile.lock
|
|
@@ -55,10 +54,16 @@ files:
|
|
|
55
54
|
- activerecord-tidb-adapter.gemspec
|
|
56
55
|
- bin/console
|
|
57
56
|
- bin/setup
|
|
57
|
+
- config.toml
|
|
58
58
|
- lib/active_record/connection_adapters/tidb/database_tasks.rb
|
|
59
59
|
- lib/active_record/connection_adapters/tidb/setup.rb
|
|
60
60
|
- lib/active_record/connection_adapters/tidb/type.rb
|
|
61
61
|
- lib/active_record/connection_adapters/tidb_adapter.rb
|
|
62
|
+
- lib/active_record/sequence.rb
|
|
63
|
+
- lib/active_record/sequence/adapter.rb
|
|
64
|
+
- lib/active_record/sequence/command_recorder.rb
|
|
65
|
+
- lib/active_record/sequence/model_methods.rb
|
|
66
|
+
- lib/active_record/sequence/schema_dumper.rb
|
|
62
67
|
- lib/activerecord-tidb-adapter.rb
|
|
63
68
|
- lib/version.rb
|
|
64
69
|
homepage: https://github.com/pingcap/activerecord-tidb-adapter
|
data/.github/workflows/main.yml
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name: Ruby
|
|
2
|
-
|
|
3
|
-
on: [push,pull_request]
|
|
4
|
-
|
|
5
|
-
jobs:
|
|
6
|
-
build:
|
|
7
|
-
runs-on: ubuntu-latest
|
|
8
|
-
steps:
|
|
9
|
-
- uses: actions/checkout@v2
|
|
10
|
-
- name: Set up Ruby
|
|
11
|
-
uses: ruby/setup-ruby@v1
|
|
12
|
-
with:
|
|
13
|
-
ruby-version: 2.7.0
|
|
14
|
-
bundler-cache: true
|
|
15
|
-
- name: Run the default task
|
|
16
|
-
run: bundle exec rake
|