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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ad173cdbfab54d867f0116350b372fc06224abb5c3166da8d59dcbe59125d5e
4
- data.tar.gz: 03a849590718d9d94f9d59730d51f001050c00ad09d54ba7dcd9470625627dd1
3
+ metadata.gz: 5f82e1eb06fb93971e146fafade1c45e2e3c5909e3968f32a719c9581efb55f3
4
+ data.tar.gz: 5a0bc0100489a41230115924cbff3f52e1ef2206441724116135ed01ccdd28da
5
5
  SHA512:
6
- metadata.gz: 86b8d677d14434d8db2c688caf99946bbc8357d729abcdea9c707330f792cd190cebdfd47b7e9305154ed41399fdaf0315b9f5d718217c922c92faecbcaf80d0
7
- data.tar.gz: 563c533e208b02539137b94f5b0e4f6939114dacec5a04524e31744bd8267ead0db261d4e04e02c997b3a2d9646959d56c095aa7be72974cbfa67b91f20a9d9c
6
+ metadata.gz: 0b059eabd253b3e7e0ead32528ac380d874dd9ab42ff942ec86ff3ddec86257b00aa5aea3c44912f95d3c0c8ba2dc7e8ba0a33abff668f6100f929fc2ed45f61
7
+ data.tar.gz: 216b0b9917670ca40cd30d3c243493e88aaf2279d946b68eaa927b0a65d78226e075279f12c8839f32a4d9be8b3edb7c348ba2038cd25bfa2845dc62aa9d4944
data/.gitignore CHANGED
@@ -6,3 +6,8 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /sqlnet.log
10
+ /test/config.yml
11
+ /test/db/
12
+ /test/fixtures/*.sqlite*
13
+ /debug.log
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
- PATH
2
- remote: .
3
- specs:
4
- activerecord-tidb-adapter (0.2.0)
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.18.4)
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.8.0, < 2.0)
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.8.0)
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/[USERNAME]/activerecord-tidb-adapter.
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
- Rake::TestTask.new(:test) do |t|
7
- t.libs << 'test'
8
- t.libs << 'lib'
9
- t.test_files = FileList['test/**/*_test.rb']
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 default: :test
57
+ task build_mysql_databases: 'db:mysql:build'
data/config.toml ADDED
@@ -0,0 +1 @@
1
+ new_collations_enabled_on_first_bootstrap = true
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Type
3
5
  class << self
@@ -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 #:nodoc:
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) #:nodoc:
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
- if tidb_version >= '5.1.0'
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\.]+)/, 1]
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
- !!ActiveRecord::Base.tidb_connection(config)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- TIDB_ADAPTER_VERSION = '0.2.0'
4
+ TIDB_ADAPTER_VERSION = '6.1.0'
5
5
  end
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: 0.2.0
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-08 00:00:00.000000000 Z
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
@@ -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