activerecord-tidb-adapter 0.2.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ad173cdbfab54d867f0116350b372fc06224abb5c3166da8d59dcbe59125d5e
4
- data.tar.gz: 03a849590718d9d94f9d59730d51f001050c00ad09d54ba7dcd9470625627dd1
3
+ metadata.gz: acd66282a9f0c498709a9258ca7337267c9cbd3770ce8a5d55d38be1607d4466
4
+ data.tar.gz: 8a73bc0cb0b685fa49e8247fd9d325e8800a95c6157b12c8eaa089bc85d47277
5
5
  SHA512:
6
- metadata.gz: 86b8d677d14434d8db2c688caf99946bbc8357d729abcdea9c707330f792cd190cebdfd47b7e9305154ed41399fdaf0315b9f5d718217c922c92faecbcaf80d0
7
- data.tar.gz: 563c533e208b02539137b94f5b0e4f6939114dacec5a04524e31744bd8267ead0db261d4e04e02c997b3a2d9646959d56c095aa7be72974cbfa67b91f20a9d9c
6
+ metadata.gz: 9a478110b32ee9acaeaa7570a207f5721fa91cce9547f1c83bc89ab52e7b59f8401b3ccde38b4c224e8918d16fc2d1e376dca52a0bac316c77be8011161169a8
7
+ data.tar.gz: d9a0cdc919c9e09df981b779aa5b60b63fa927fcb93420d8629c671d96562b3f45c8a6280187813caefb5f3b39dd980d66584fbddc6d35bc7d80c11b7e96722d
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,20 @@ 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: '5-2-stable'
18
+
19
+ gem 'byebug', '~> 11.1'
20
+
21
+ gem 'sqlite3', '~> 1.4'
22
+
23
+ gem 'pg', '~> 1.2'
24
+
25
+ gem "mocha", "~> 1.13"
26
+
27
+ gem "bcrypt", "~> 3.1"
data/Gemfile.lock CHANGED
@@ -1,58 +1,158 @@
1
+ GIT
2
+ remote: https://github.com/pingcap/rails.git
3
+ revision: 7a3fbc5e103be80107fabc9e626cfc32e10e6e1c
4
+ branch: 5-2-stable
5
+ specs:
6
+ actioncable (5.2.6)
7
+ actionpack (= 5.2.6)
8
+ nio4r (~> 2.0)
9
+ websocket-driver (>= 0.6.1)
10
+ actionmailer (5.2.6)
11
+ actionpack (= 5.2.6)
12
+ actionview (= 5.2.6)
13
+ activejob (= 5.2.6)
14
+ mail (~> 2.5, >= 2.5.4)
15
+ rails-dom-testing (~> 2.0)
16
+ actionpack (5.2.6)
17
+ actionview (= 5.2.6)
18
+ activesupport (= 5.2.6)
19
+ rack (~> 2.0, >= 2.0.8)
20
+ rack-test (>= 0.6.3)
21
+ rails-dom-testing (~> 2.0)
22
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
23
+ actionview (5.2.6)
24
+ activesupport (= 5.2.6)
25
+ builder (~> 3.1)
26
+ erubi (~> 1.4)
27
+ rails-dom-testing (~> 2.0)
28
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
29
+ activejob (5.2.6)
30
+ activesupport (= 5.2.6)
31
+ globalid (>= 0.3.6)
32
+ activemodel (5.2.6)
33
+ activesupport (= 5.2.6)
34
+ activerecord (5.2.6)
35
+ activemodel (= 5.2.6)
36
+ activesupport (= 5.2.6)
37
+ arel (>= 9.0)
38
+ activestorage (5.2.6)
39
+ actionpack (= 5.2.6)
40
+ activerecord (= 5.2.6)
41
+ marcel (~> 1.0.0)
42
+ activesupport (5.2.6)
43
+ concurrent-ruby (~> 1.0, >= 1.0.2)
44
+ i18n (>= 0.7, < 2)
45
+ minitest (~> 5.1)
46
+ tzinfo (~> 1.1)
47
+ rails (5.2.6)
48
+ actioncable (= 5.2.6)
49
+ actionmailer (= 5.2.6)
50
+ actionpack (= 5.2.6)
51
+ actionview (= 5.2.6)
52
+ activejob (= 5.2.6)
53
+ activemodel (= 5.2.6)
54
+ activerecord (= 5.2.6)
55
+ activestorage (= 5.2.6)
56
+ activesupport (= 5.2.6)
57
+ bundler (>= 1.3.0)
58
+ railties (= 5.2.6)
59
+ sprockets-rails (>= 2.0.0)
60
+ railties (5.2.6)
61
+ actionpack (= 5.2.6)
62
+ activesupport (= 5.2.6)
63
+ method_source
64
+ rake (>= 0.8.7)
65
+ thor (>= 0.19.0, < 2.0)
66
+
1
67
  PATH
2
68
  remote: .
3
69
  specs:
4
- activerecord-tidb-adapter (0.2.0)
5
- activerecord (~> 6.1)
70
+ activerecord-tidb-adapter (5.2.0)
71
+ activerecord (~> 5.2)
6
72
  mysql2
7
73
 
8
74
  GEM
9
75
  remote: https://rubygems.org/
10
76
  specs:
11
- activemodel (6.1.4)
12
- activesupport (= 6.1.4)
13
- activerecord (6.1.4)
14
- activemodel (= 6.1.4)
15
- activesupport (= 6.1.4)
16
- activesupport (6.1.4)
17
- concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (>= 1.6, < 2)
19
- minitest (>= 5.1)
20
- tzinfo (~> 2.0)
21
- zeitwerk (~> 2.3)
77
+ arel (9.0.0)
22
78
  ast (2.4.2)
79
+ bcrypt (3.1.16)
80
+ builder (3.2.4)
81
+ byebug (11.1.3)
23
82
  coderay (1.1.3)
24
83
  concurrent-ruby (1.1.9)
84
+ crass (1.0.6)
85
+ erubi (1.10.0)
86
+ globalid (0.5.2)
87
+ activesupport (>= 5.0)
25
88
  i18n (1.8.10)
26
89
  concurrent-ruby (~> 1.0)
90
+ loofah (2.12.0)
91
+ crass (~> 1.0.2)
92
+ nokogiri (>= 1.5.9)
93
+ mail (2.7.1)
94
+ mini_mime (>= 0.1.1)
95
+ marcel (1.0.1)
27
96
  method_source (1.0.0)
97
+ mini_mime (1.1.0)
28
98
  minitest (5.14.4)
99
+ minitest-excludes (2.0.1)
100
+ minitest (~> 5.0)
101
+ mocha (1.13.0)
29
102
  mysql2 (0.5.3)
103
+ nio4r (2.5.8)
104
+ nokogiri (1.12.3-x86_64-darwin)
105
+ racc (~> 1.4)
106
+ nokogiri (1.12.3-x86_64-linux)
107
+ racc (~> 1.4)
30
108
  parallel (1.20.1)
31
109
  parser (3.0.2.0)
32
110
  ast (~> 2.4.1)
111
+ pg (1.2.3)
33
112
  pry (0.14.1)
34
113
  coderay (~> 1.1)
35
114
  method_source (~> 1.0)
115
+ racc (1.5.2)
116
+ rack (2.2.3)
117
+ rack-test (1.1.0)
118
+ rack (>= 1.0, < 3)
119
+ rails-dom-testing (2.0.3)
120
+ activesupport (>= 4.2.0)
121
+ nokogiri (>= 1.6)
122
+ rails-html-sanitizer (1.4.1)
123
+ loofah (~> 2.3)
36
124
  rainbow (3.0.0)
37
125
  rake (13.0.6)
38
126
  regexp_parser (2.1.1)
39
127
  rexml (3.2.5)
40
- rubocop (1.18.4)
128
+ rubocop (1.19.0)
41
129
  parallel (~> 1.10)
42
130
  parser (>= 3.0.0.0)
43
131
  rainbow (>= 2.2.2, < 4.0)
44
132
  regexp_parser (>= 1.8, < 3.0)
45
133
  rexml
46
- rubocop-ast (>= 1.8.0, < 2.0)
134
+ rubocop-ast (>= 1.9.1, < 2.0)
47
135
  ruby-progressbar (~> 1.7)
48
136
  unicode-display_width (>= 1.4.0, < 3.0)
49
- rubocop-ast (1.8.0)
137
+ rubocop-ast (1.10.0)
50
138
  parser (>= 3.0.1.1)
51
139
  ruby-progressbar (1.11.0)
52
- tzinfo (2.0.4)
140
+ sprockets (4.0.2)
53
141
  concurrent-ruby (~> 1.0)
142
+ rack (> 1, < 3)
143
+ sprockets-rails (3.2.2)
144
+ actionpack (>= 4.0)
145
+ activesupport (>= 4.0)
146
+ sprockets (>= 3.0.0)
147
+ sqlite3 (1.4.2)
148
+ thor (1.1.0)
149
+ thread_safe (0.3.6)
150
+ tzinfo (1.2.9)
151
+ thread_safe (~> 0.1)
54
152
  unicode-display_width (2.0.0)
55
- zeitwerk (2.4.2)
153
+ websocket-driver (0.7.5)
154
+ websocket-extensions (>= 0.1.0)
155
+ websocket-extensions (0.1.5)
56
156
 
57
157
  PLATFORMS
58
158
  x86_64-darwin-18
@@ -60,10 +160,17 @@ PLATFORMS
60
160
 
61
161
  DEPENDENCIES
62
162
  activerecord-tidb-adapter!
163
+ bcrypt (~> 3.1)
164
+ byebug (~> 11.1)
63
165
  minitest (~> 5.0)
166
+ minitest-excludes (~> 2.0)
167
+ mocha (~> 1.13)
168
+ pg (~> 1.2)
64
169
  pry
170
+ rails!
65
171
  rake (~> 13.0)
66
172
  rubocop (~> 1.18)
173
+ sqlite3 (~> 1.4)
67
174
 
68
175
  BUNDLED WITH
69
176
  2.2.25
data/README.md CHANGED
@@ -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'
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ['lib']
31
31
 
32
- spec.add_dependency 'activerecord', '~> 6.1'
32
+ spec.add_dependency 'activerecord', '~> 5.2'
33
33
  spec.add_dependency 'mysql2'
34
34
 
35
35
  # Uncomment to register a new dependency of your gem
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
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_record/connection_adapters'
4
3
  require 'active_record/connection_adapters/mysql2_adapter'
5
4
  require 'active_record/connection_adapters/tidb/setup'
6
5
  require_relative '../../version'
6
+ require_relative '../sequence'
7
7
 
8
8
  ActiveRecord::ConnectionAdapters::Tidb.initial_setup
9
9
 
10
10
  module ActiveRecord
11
- module ConnectionHandling #:nodoc:
11
+ module ConnectionHandling # :nodoc:
12
12
  # Establishes a connection to the database that's used by all Active Record objects.
13
- def tidb_connection(config) #:nodoc:
13
+ def tidb_connection(config) # :nodoc:
14
14
  config = config.symbolize_keys
15
15
  config[:flags] ||= 0
16
16
 
@@ -29,8 +29,30 @@ module ActiveRecord
29
29
  end
30
30
  end
31
31
 
32
+
33
+
32
34
  module ConnectionAdapters
35
+ class Mysql2Adapter < AbstractMysqlAdapter
36
+ ER_BAD_DB_ERROR = 1049
37
+ ADAPTER_NAME = "Mysql2"
38
+
39
+ include MySQL::DatabaseStatements
40
+
41
+ class << self
42
+ def new_client(config)
43
+ Mysql2::Client.new(config)
44
+ rescue Mysql2::Error => error
45
+ if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
46
+ raise ActiveRecord::NoDatabaseError
47
+ else
48
+ raise ActiveRecord::ConnectionNotEstablished, error.message
49
+ end
50
+ end
51
+ end
52
+ end
53
+
33
54
  class TidbAdapter < Mysql2Adapter
55
+ include ActiveRecord::Sequence::Adapter
34
56
  ADAPTER_NAME = 'Tidb'
35
57
 
36
58
  def supports_savepoints?
@@ -67,11 +89,7 @@ module ActiveRecord
67
89
  end
68
90
 
69
91
  def supports_common_table_expressions?
70
- if tidb_version >= '5.1.0'
71
- true
72
- else
73
- false
74
- end
92
+ tidb_version >= '5.1.0'
75
93
  end
76
94
 
77
95
  def transaction_isolation_levels
@@ -85,7 +103,7 @@ module ActiveRecord
85
103
  super(connection, logger, conn_params, config)
86
104
 
87
105
  tidb_version_string = query_value('select version()')
88
- @tidb_version = tidb_version_string[/TiDB-v([0-9\.]+)/, 1]
106
+ @tidb_version = tidb_version_string[/TiDB-v([0-9.]+)/, 1]
89
107
  end
90
108
 
91
109
  def tidb_version_string
@@ -97,10 +115,48 @@ module ActiveRecord
97
115
  end
98
116
 
99
117
  def self.database_exists?(config)
100
- !!ActiveRecord::Base.tidb_connection(config)
118
+ !ActiveRecord::Base.tidb_connection(config).nil?
101
119
  rescue ActiveRecord::NoDatabaseError
102
120
  false
103
121
  end
122
+
123
+ def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
124
+ sql, binds = to_sql_and_binds(arel, binds)
125
+ value = exec_insert(sql, name, binds, pk, sequence_name)
126
+ return id_value if id_value.present?
127
+
128
+ table_name = arel.ast.relation.table_name
129
+ pk_def = schema_cache.columns_hash(table_name)[pk]
130
+ if pk_def&.default_function && pk_def.default_function =~ /nextval/
131
+ query_value("SELECT #{pk_def.default_function.sub('nextval', 'lastval')}")
132
+ else
133
+ last_inserted_id(value)
134
+ end
135
+ end
136
+ alias create insert
137
+
138
+ def new_column_from_field(table_name, field)
139
+ type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
140
+ if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
141
+ default, default_function = nil, field[:Default]
142
+ elsif default.to_s =~ /nextval/i
143
+ default_function = default
144
+ default = nil
145
+ else
146
+ default, default_function = field[:Default], nil
147
+ end
148
+
149
+ MySQL::Column.new(
150
+ field[:Field],
151
+ default,
152
+ type_metadata,
153
+ field[:Null] == "YES",
154
+ table_name,
155
+ default_function,
156
+ field[:Collation],
157
+ comment: field[:Comment].presence
158
+ )
159
+ end
104
160
  end
105
161
  end
106
162
  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 = '5.2.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: 5.2.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
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.1'
19
+ version: '5.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '6.1'
26
+ version: '5.2'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: mysql2
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -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