sequel-sequence 0.3.0 → 0.4.1
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/.github/workflows/ci.yml +44 -8
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +14 -0
- data/CONTRIBUTING.md +111 -13
- data/README.md +33 -10
- data/Rakefile +34 -1
- data/lib/sequel/error.rb +6 -6
- data/lib/sequel/sequence/database/postgresql.rb +3 -2
- data/lib/sequel/sequence/database/server/mariadb.rb +79 -0
- data/lib/sequel/sequence/database/server/mysql.rb +185 -0
- data/lib/sequel/sequence/database/sqlite.rb +18 -24
- data/lib/sequel/sequence/database.rb +12 -12
- data/lib/sequel/sequence/database_ext_connection.rb +29 -0
- data/lib/sequel/sequence/version.rb +1 -1
- data/lib/sequel/sequence.rb +1 -9
- data/sequel-sequence.gemspec +3 -2
- data/test/mariadb_test_helper.rb +32 -0
- data/test/mock_test_helper.rb +5 -0
- data/test/mysql_test_helper.rb +16 -9
- data/test/sequel/mariadb_sequence_test.rb +182 -0
- data/test/sequel/mock_sequence_test.rb +100 -0
- data/test/sequel/mysql_sequence_test.rb +230 -41
- data/test/sequel/sqlite_sequence_test.rb +86 -12
- data/test/sqlite_test_helper.rb +10 -2
- data/test/test_helper.rb +1 -0
- metadata +13 -6
- data/lib/sequel/sequence/database/mysql.rb +0 -10
- data/lib/sequel/sequence/database/mysql2.rb +0 -81
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module Sequence
|
5
|
+
module Database
|
6
|
+
module Server
|
7
|
+
module Mysql
|
8
|
+
def check_sequences
|
9
|
+
fetch('SELECT * FROM mysql_sequence;').all.to_a
|
10
|
+
end
|
11
|
+
|
12
|
+
def custom_sequence?(sequence_name)
|
13
|
+
table_matcher do
|
14
|
+
out = nil
|
15
|
+
fetch(select_from_mysql_sequence_where(stringify(sequence_name))) do |row|
|
16
|
+
out = row[:name]
|
17
|
+
end
|
18
|
+
!out.nil?
|
19
|
+
end || false
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_sequence(name, options = {})
|
23
|
+
check_options(options)
|
24
|
+
if_exists = build_exists_condition(options[:if_exists])
|
25
|
+
start_option = options[:start] || 1
|
26
|
+
num_label = options[:numeric_label] || 0
|
27
|
+
return if (current = lastval(name)) && (current >= start_option)
|
28
|
+
|
29
|
+
run create_sequence_table(stringify(name), if_exists)
|
30
|
+
run insert_into_sequence_table_init_values(stringify(name), start_option, num_label)
|
31
|
+
run create_mysql_sequence
|
32
|
+
table_matcher { run delete_from_mysql_sequence(stringify(name)) }
|
33
|
+
run insert_into_mysql_sequence(stringify(name), start_option)
|
34
|
+
end
|
35
|
+
|
36
|
+
def drop_sequence(name, options = {})
|
37
|
+
if_exists = build_exists_condition(options[:if_exists])
|
38
|
+
run drop_sequence_table(stringify(name), if_exists)
|
39
|
+
table_matcher { run delete_from_mysql_sequence(stringify(name)) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def nextval(name)
|
43
|
+
run insert_into_sequence_table(stringify(name), 0)
|
44
|
+
table_matcher { run delete_from_mysql_sequence(stringify(name)) }
|
45
|
+
run insert_last_insert_id_into_mysql_sequence(stringify(name))
|
46
|
+
take_seq(stringify(name))
|
47
|
+
end
|
48
|
+
|
49
|
+
def nextval_with_label(name, num_label = 0)
|
50
|
+
run insert_into_sequence_table(stringify(name), num_label)
|
51
|
+
table_matcher { run delete_from_mysql_sequence(stringify(name)) }
|
52
|
+
run insert_last_insert_id_into_mysql_sequence(stringify(name))
|
53
|
+
take_seq(stringify(name))
|
54
|
+
end
|
55
|
+
|
56
|
+
def lastval(name)
|
57
|
+
take_seq(stringify(name))
|
58
|
+
end
|
59
|
+
|
60
|
+
alias currval lastval
|
61
|
+
|
62
|
+
def setval(name, value)
|
63
|
+
current = lastval(stringify(name))
|
64
|
+
if current.nil?
|
65
|
+
create_sequence(stringify(name), { start: value })
|
66
|
+
elsif value < current
|
67
|
+
log_info Sequel::Database::DANGER_OPT_ID
|
68
|
+
value = current
|
69
|
+
elsif value > current
|
70
|
+
run insert_into_sequence_table_init_values(stringify(name), value, 0)
|
71
|
+
table_matcher { run delete_from_mysql_sequence(stringify(name)) }
|
72
|
+
run insert_into_mysql_sequence(stringify(name), value)
|
73
|
+
end
|
74
|
+
value
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_column_default_nextval(table, column, sequence)
|
78
|
+
run create_sequenced_column(stringify(table),
|
79
|
+
stringify(column),
|
80
|
+
stringify(sequence))
|
81
|
+
run update_sequenced_column(stringify(table),
|
82
|
+
stringify(column),
|
83
|
+
stringify(sequence))
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def stringify(name)
|
89
|
+
@name ||= {}
|
90
|
+
@name.fetch(name, nil) || (@name[name] = name.to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
def select_from_mysql_sequence_where(name)
|
94
|
+
"SELECT * FROM mysql_sequence where name = '#{name}';"
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_sequence_table(name, if_exists = nil)
|
98
|
+
%(
|
99
|
+
CREATE TABLE #{if_exists || Sequel::Database::IF_NOT_EXISTS} #{name}
|
100
|
+
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
101
|
+
fiction INT);
|
102
|
+
).strip
|
103
|
+
end
|
104
|
+
|
105
|
+
def insert_into_sequence_table_init_values(name, start_id, num_label)
|
106
|
+
"INSERT INTO #{name} (id, fiction) VALUES (#{start_id}, #{num_label});"
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_mysql_sequence
|
110
|
+
%(
|
111
|
+
CREATE TABLE #{Sequel::Database::IF_NOT_EXISTS} mysql_sequence
|
112
|
+
(name VARCHAR(40), seq INT);
|
113
|
+
).strip
|
114
|
+
end
|
115
|
+
|
116
|
+
def select_max_seq(name)
|
117
|
+
"SELECT MAX(seq) AS id FROM mysql_sequence WHERE name = '#{name}';"
|
118
|
+
end
|
119
|
+
|
120
|
+
def take_seq(name)
|
121
|
+
table_matcher do
|
122
|
+
out = nil
|
123
|
+
fetch(select_max_seq(name)) do |row|
|
124
|
+
out = row[:id]
|
125
|
+
end
|
126
|
+
out
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def delete_from_mysql_sequence(name)
|
131
|
+
"DELETE QUICK IGNORE FROM mysql_sequence WHERE name = '#{name}';"
|
132
|
+
end
|
133
|
+
|
134
|
+
def insert_into_mysql_sequence(name, value)
|
135
|
+
"INSERT INTO mysql_sequence (name, seq) VALUES ('#{name}', #{value});"
|
136
|
+
end
|
137
|
+
|
138
|
+
def drop_sequence_table(name, if_exists = nil)
|
139
|
+
"DROP TABLE #{if_exists || Sequel::Database::IF_EXISTS} #{name};"
|
140
|
+
end
|
141
|
+
|
142
|
+
def insert_into_sequence_table(name, num_label)
|
143
|
+
"INSERT INTO #{name} (fiction) VALUES (#{num_label});"
|
144
|
+
end
|
145
|
+
|
146
|
+
def insert_last_insert_id_into_mysql_sequence(name)
|
147
|
+
"INSERT INTO mysql_sequence (name, seq) VALUES ('#{name}', LAST_INSERT_ID());"
|
148
|
+
end
|
149
|
+
|
150
|
+
def create_sequenced_column(table, _column, sequence)
|
151
|
+
%(
|
152
|
+
CREATE TRIGGER IF NOT EXISTS #{table}_#{sequence} BEFORE INSERT
|
153
|
+
ON #{table}
|
154
|
+
FOR EACH ROW BEGIN
|
155
|
+
DELETE QUICK IGNORE FROM mysql_sequence WHERE name = '#{sequence}';
|
156
|
+
INSERT INTO #{sequence} SET fiction = 0;
|
157
|
+
INSERT INTO mysql_sequence SET name = '#{sequence}', seq = LAST_INSERT_ID();
|
158
|
+
|
159
|
+
END;
|
160
|
+
).strip
|
161
|
+
end
|
162
|
+
|
163
|
+
def update_sequenced_column(table, column, sequence)
|
164
|
+
%(
|
165
|
+
CREATE TRIGGER IF NOT EXISTS #{table}_#{column} BEFORE INSERT
|
166
|
+
ON #{table}
|
167
|
+
FOR EACH ROW FOLLOWS #{table}_#{sequence}
|
168
|
+
SET NEW.#{column} = ( SELECT MAX(seq) FROM mysql_sequence WHERE name = '#{sequence}' );
|
169
|
+
).strip
|
170
|
+
end
|
171
|
+
|
172
|
+
def table_matcher(&block)
|
173
|
+
block.call
|
174
|
+
rescue Sequel::DatabaseError => e
|
175
|
+
return if e.message =~ /\AMysql2::Error: Table(.)*doesn't exist\z/
|
176
|
+
|
177
|
+
# :nocov:
|
178
|
+
raise e
|
179
|
+
# :nocov:
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -14,8 +14,11 @@ module Sequel
|
|
14
14
|
check_options(options)
|
15
15
|
if_exists = build_exists_condition(options[:if_exists])
|
16
16
|
start_option = options[:start] || 1
|
17
|
+
num_label = options[:numeric_label] || 0
|
18
|
+
return if (current = lastval(name)) && (current >= start_option)
|
19
|
+
|
17
20
|
sql = [create_sequence_table(stringify(name), if_exists)]
|
18
|
-
sql <<
|
21
|
+
sql << insert_into_sequence_table_init_values(stringify(name), start_option, num_label)
|
19
22
|
run(sql.join("\n"))
|
20
23
|
end
|
21
24
|
|
@@ -26,12 +29,12 @@ module Sequel
|
|
26
29
|
|
27
30
|
def nextval(name)
|
28
31
|
run(insert_into_sequence_table(stringify(name), 0))
|
29
|
-
take_seq(name)
|
32
|
+
take_seq(stringify(name))
|
30
33
|
end
|
31
34
|
|
32
35
|
def nextval_with_label(name, num_label = 0)
|
33
36
|
run(insert_into_sequence_table(stringify(name), num_label))
|
34
|
-
take_seq(name)
|
37
|
+
take_seq(stringify(name))
|
35
38
|
end
|
36
39
|
|
37
40
|
def lastval(name)
|
@@ -45,14 +48,10 @@ module Sequel
|
|
45
48
|
if current.nil?
|
46
49
|
create_sequence(stringify(name), { start: value })
|
47
50
|
elsif value < current
|
48
|
-
# sql = [delete_from_sqlite_sequence(name)]
|
49
|
-
# sql << drop_sequence_table(name)
|
50
|
-
# sql << insert_into_sqlite_sequence(name, value)
|
51
|
-
# run(sql.join("\n"))
|
52
51
|
log_info DANGER_OPT_ID
|
53
52
|
value = current
|
54
53
|
else
|
55
|
-
run(
|
54
|
+
run(update_sqlite_sequence(stringify(name), value))
|
56
55
|
end
|
57
56
|
value
|
58
57
|
end
|
@@ -85,25 +84,20 @@ module Sequel
|
|
85
84
|
)
|
86
85
|
end
|
87
86
|
|
88
|
-
def
|
89
|
-
"INSERT INTO #{name} (fiction) VALUES (#{num_label});"
|
87
|
+
def insert_into_sequence_table_init_values(name, start_id, num_label)
|
88
|
+
"INSERT INTO #{name} (id, fiction) VALUES (#{start_id}, #{num_label});"
|
90
89
|
end
|
91
90
|
|
92
|
-
def
|
93
|
-
|
94
|
-
if current.nil?
|
95
|
-
"INSERT INTO sqlite_sequence (name, seq) VALUES ('#{name}', #{value});"
|
96
|
-
else
|
97
|
-
%(
|
98
|
-
UPDATE sqlite_sequence
|
99
|
-
SET seq = #{[current, value].max}
|
100
|
-
WHERE name = '#{name}';
|
101
|
-
)
|
102
|
-
end
|
91
|
+
def insert_into_sequence_table(name, num_label)
|
92
|
+
"INSERT INTO #{name} (fiction) VALUES (#{num_label});"
|
103
93
|
end
|
104
94
|
|
105
|
-
def
|
106
|
-
|
95
|
+
def update_sqlite_sequence(name, value)
|
96
|
+
%(
|
97
|
+
UPDATE sqlite_sequence
|
98
|
+
SET seq = #{value}
|
99
|
+
WHERE name = '#{name}';
|
100
|
+
)
|
107
101
|
end
|
108
102
|
|
109
103
|
def drop_sequence_table(name, if_exists = nil)
|
@@ -119,7 +113,7 @@ module Sequel
|
|
119
113
|
CREATE TRIGGER IF NOT EXISTS #{table}_#{sequence} AFTER INSERT
|
120
114
|
ON #{table}
|
121
115
|
BEGIN
|
122
|
-
INSERT INTO #{sequence}(fiction) VALUES (0);
|
116
|
+
INSERT INTO #{sequence} (fiction) VALUES (0);
|
123
117
|
UPDATE #{table}
|
124
118
|
SET #{column} = (SELECT MAX(seq) FROM sqlite_sequence WHERE name = '#{sequence}')
|
125
119
|
WHERE rowid = NEW.rowid;
|
@@ -14,24 +14,24 @@ module Sequel
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def custom_sequence?(_sequence_name)
|
17
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
17
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
18
18
|
end
|
19
19
|
|
20
20
|
def check_sequences
|
21
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
21
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
22
22
|
end
|
23
23
|
|
24
24
|
def create_sequence(_name, _options = {})
|
25
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
25
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
26
26
|
end
|
27
27
|
|
28
28
|
def drop_sequence(_name, _options = {})
|
29
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
29
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
30
30
|
end
|
31
31
|
|
32
32
|
def quote_name(name)
|
33
33
|
unless respond_to?(:quote_column_name, false)
|
34
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
34
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
35
35
|
end
|
36
36
|
|
37
37
|
name.to_s.split('.', 2).map { |part| quote_column_name(part) }.join('.')
|
@@ -39,30 +39,30 @@ module Sequel
|
|
39
39
|
|
40
40
|
def quote(name)
|
41
41
|
unless respond_to?(:quote_sequence_name, false)
|
42
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
42
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
43
43
|
end
|
44
44
|
|
45
45
|
name.to_s.split('.', 2).map { |part| quote_sequence_name(part) }.join('.')
|
46
46
|
end
|
47
47
|
|
48
48
|
def nextval_with_label(_name, _num_label = 0)
|
49
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
49
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
50
50
|
end
|
51
51
|
|
52
52
|
def nextval(_name)
|
53
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
53
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
54
54
|
end
|
55
55
|
|
56
|
-
# for
|
56
|
+
# for Postgres
|
57
57
|
def currval(_name)
|
58
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
58
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
59
59
|
end
|
60
60
|
|
61
|
-
# for
|
61
|
+
# for MariaDB
|
62
62
|
alias lastval currval
|
63
63
|
|
64
64
|
def setval(_name, _value)
|
65
|
-
raise Sequel::MethodNotAllowed, Sequel::
|
65
|
+
raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
|
66
66
|
end
|
67
67
|
|
68
68
|
def build_exists_condition(option)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'database/server/mysql'
|
4
|
+
require_relative 'database/server/mariadb'
|
5
|
+
|
6
|
+
module Sequel
|
7
|
+
class Database
|
8
|
+
class << self
|
9
|
+
attr_reader :dbms
|
10
|
+
end
|
11
|
+
|
12
|
+
old_connect = singleton_method(:connect)
|
13
|
+
|
14
|
+
define_singleton_method(:connect) do |*args|
|
15
|
+
db = old_connect.call(*args)
|
16
|
+
if db.adapter_scheme == :mysql2
|
17
|
+
@dbms = if db.mariadb?
|
18
|
+
Sequel::Sequence::Database::Server::Mariadb
|
19
|
+
else
|
20
|
+
Sequel::Sequence::Database::Server::Mysql
|
21
|
+
end
|
22
|
+
db.log_info "Sequel::Database.connect (mariadb? = #{db.mariadb?.inspect})"
|
23
|
+
db.log_info "Sequel::Database.connect (server_version = #{db.server_version.inspect})"
|
24
|
+
Sequel::Mysql2::Database.include(@dbms)
|
25
|
+
end
|
26
|
+
db
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/sequel/sequence.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'sequel/database'
|
4
4
|
require 'sequel/adapters/postgres'
|
5
|
-
# require 'sequel/adapters/mysql'
|
6
5
|
require 'sequel/adapters/mysql2'
|
7
6
|
require 'sequel/adapters/sqlite'
|
8
7
|
require 'sequel/error'
|
8
|
+
require 'sequel/sequence/database_ext_connection'
|
9
9
|
|
10
10
|
module Sequel
|
11
11
|
module Sequence
|
@@ -13,8 +13,6 @@ module Sequel
|
|
13
13
|
|
14
14
|
module Database
|
15
15
|
require 'sequel/sequence/database/postgresql'
|
16
|
-
# require "sequel/sequence/database/mysql"
|
17
|
-
require 'sequel/sequence/database/mysql2'
|
18
16
|
require 'sequel/sequence/database/sqlite'
|
19
17
|
end
|
20
18
|
end
|
@@ -26,12 +24,6 @@ Sequel::Database.include(
|
|
26
24
|
Sequel::Postgres::Database.include(
|
27
25
|
Sequel::Sequence::Database::PostgreSQL
|
28
26
|
)
|
29
|
-
Sequel::Mysql2::Database.include(
|
30
|
-
Sequel::Sequence::Database::Mysql2
|
31
|
-
)
|
32
|
-
# Sequel::Mysql::Database.include(
|
33
|
-
# Sequel::Sequence::Database::Mysql
|
34
|
-
# )
|
35
27
|
Sequel::SQLite::Database.include(
|
36
28
|
Sequel::Sequence::Database::SQLite
|
37
29
|
)
|
data/sequel-sequence.gemspec
CHANGED
@@ -7,10 +7,11 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.version = Sequel::Sequence::VERSION
|
8
8
|
spec.licenses = ['MIT']
|
9
9
|
spec.summary = \
|
10
|
-
|
10
|
+
'Adds SEQUENCE support to Sequel for migrations to PostgreSQL, MariaDB, MySQL and SQLite.'
|
11
11
|
spec.description = <<-DES
|
12
12
|
This gem provides a single interface for SEQUENCE functionality
|
13
|
-
in Postgresql and
|
13
|
+
in Postgresql and MariaDB DBMS within the Sequel ORM.
|
14
|
+
It also models the Sequences to meet the needs of SQLite and MySQL users.
|
14
15
|
DES
|
15
16
|
spec.authors = ['Nikolai Bocharov']
|
16
17
|
spec.email = ['it.architect@yahoo.com']
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
MariaDB = Sequel.connect(
|
6
|
+
adapter: 'mysql2',
|
7
|
+
user: ENV['TEST_MARIA_USERNAME'] || 'root',
|
8
|
+
password: ENV['TEST_MARIA_PASSWORD'] || 'root',
|
9
|
+
host: ENV['TEST_MARIA_HOST'] || '127.0.0.1',
|
10
|
+
port: ENV['TEST_MARIA_PORT'] || 3306,
|
11
|
+
database: ENV['TEST_MARIA_DATABASE'] || 'test'
|
12
|
+
)
|
13
|
+
|
14
|
+
module MariadbTestHelper
|
15
|
+
def recreate_table
|
16
|
+
MariaDB.run 'DROP SEQUENCE IF EXISTS position'
|
17
|
+
MariaDB.run 'DROP TABLE IF EXISTS wares'
|
18
|
+
MariaDB.run 'DROP SEQUENCE IF EXISTS a'
|
19
|
+
MariaDB.run 'DROP SEQUENCE IF EXISTS b'
|
20
|
+
MariaDB.run 'DROP SEQUENCE IF EXISTS c'
|
21
|
+
sql = 'CREATE TABLE wares (id INT AUTO_INCREMENT, slug VARCHAR(255), quantity INT DEFAULT(0), PRIMARY KEY(id));'
|
22
|
+
MariaDB.run sql
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_migration(&block)
|
26
|
+
migration_class = Sequel::Migration
|
27
|
+
|
28
|
+
Sequel::Model.db = MariaDB
|
29
|
+
|
30
|
+
Class.new(migration_class, &block).new(MariaDB)
|
31
|
+
end
|
32
|
+
end
|
data/test/mysql_test_helper.rb
CHANGED
@@ -5,20 +5,22 @@ require 'test_helper'
|
|
5
5
|
MysqlDB = Sequel.connect(
|
6
6
|
adapter: 'mysql2',
|
7
7
|
user: ENV['TEST_MYSQL_USERNAME'] || 'root',
|
8
|
-
password: ENV['TEST_MYSQL_PASSWORD'] || '
|
9
|
-
host: ENV['TEST_MYSQL_HOST'] || '
|
10
|
-
port: ENV['TEST_MYSQL_PORT'] ||
|
8
|
+
password: ENV['TEST_MYSQL_PASSWORD'] || 'rootroot',
|
9
|
+
host: ENV['TEST_MYSQL_HOST'] || '0.0.0.0',
|
10
|
+
port: ENV['TEST_MYSQL_PORT'] || 3360,
|
11
11
|
database: ENV['TEST_MYSQL_DATABASE'] || 'test'
|
12
12
|
)
|
13
13
|
|
14
14
|
module MysqlTestHelper
|
15
15
|
def recreate_table
|
16
|
-
MysqlDB.
|
17
|
-
MysqlDB.
|
18
|
-
MysqlDB.
|
19
|
-
MysqlDB.
|
20
|
-
MysqlDB.
|
21
|
-
|
16
|
+
MysqlDB.drop_table :creators, if_exists: true
|
17
|
+
MysqlDB.drop_sequence :position_id, if_exists: true
|
18
|
+
MysqlDB.drop_sequence :position
|
19
|
+
MysqlDB.drop_table :stuffs, if_exists: true
|
20
|
+
MysqlDB.drop_sequence 'a'
|
21
|
+
MysqlDB.drop_sequence 'b'
|
22
|
+
MysqlDB.drop_sequence 'c'
|
23
|
+
sql = 'CREATE TABLE stuffs (id INT AUTO_INCREMENT PRIMARY KEY, slug VARCHAR(255), quantity INT DEFAULT(0));'
|
22
24
|
MysqlDB.run sql
|
23
25
|
end
|
24
26
|
|
@@ -29,4 +31,9 @@ module MysqlTestHelper
|
|
29
31
|
|
30
32
|
Class.new(migration_class, &block).new(MysqlDB)
|
31
33
|
end
|
34
|
+
|
35
|
+
def sequence_table_exists?(name)
|
36
|
+
table_list = MysqlDB.fetch('SHOW TABLES;').all.map { |_key, value| value }
|
37
|
+
table_list.include?(name)
|
38
|
+
end
|
32
39
|
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mariadb_test_helper'
|
4
|
+
|
5
|
+
class MariadbSequenceTest < Minitest::Test
|
6
|
+
include MariadbTestHelper
|
7
|
+
|
8
|
+
setup do
|
9
|
+
recreate_table
|
10
|
+
end
|
11
|
+
|
12
|
+
test 'adds sequence with default values' do
|
13
|
+
with_migration do
|
14
|
+
def up
|
15
|
+
# create_sequence :position, {start: 1, increment: 1} - default values
|
16
|
+
create_sequence :position
|
17
|
+
end
|
18
|
+
end.up
|
19
|
+
|
20
|
+
assert_equal 1, MariaDB.nextval(:position)
|
21
|
+
assert_equal 2, MariaDB.nextval(:position)
|
22
|
+
end
|
23
|
+
|
24
|
+
test 'adds sequence reader within model and its inherited class' do
|
25
|
+
with_migration do
|
26
|
+
def up
|
27
|
+
create_sequence :position
|
28
|
+
end
|
29
|
+
end.up
|
30
|
+
|
31
|
+
class Ware < Sequel::Model; end
|
32
|
+
|
33
|
+
assert_equal 1, Ware.db.nextval('position')
|
34
|
+
assert_equal 2, Ware.db.nextval('position')
|
35
|
+
|
36
|
+
class InheritedWare < Ware; end
|
37
|
+
|
38
|
+
assert_equal 3, InheritedWare.db.nextval(:position)
|
39
|
+
assert_equal 4, InheritedWare.db.nextval(:position)
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'adds sequence starting at 100' do
|
43
|
+
with_migration do
|
44
|
+
def up
|
45
|
+
create_sequence :position, start: 100
|
46
|
+
end
|
47
|
+
end.up
|
48
|
+
|
49
|
+
assert_equal 100, MariaDB.nextval(:position)
|
50
|
+
assert_equal 101, MariaDB.nextval(:position)
|
51
|
+
end
|
52
|
+
|
53
|
+
test 'adds sequence incremented by 2' do
|
54
|
+
with_migration do
|
55
|
+
def up
|
56
|
+
create_sequence :position, increment: 2
|
57
|
+
end
|
58
|
+
end.up
|
59
|
+
|
60
|
+
assert_equal 1, MariaDB.nextval(:position)
|
61
|
+
assert_equal 3, MariaDB.nextval(:position)
|
62
|
+
end
|
63
|
+
|
64
|
+
test 'adds sequence incremented by 2 (using :step alias)' do
|
65
|
+
with_migration do
|
66
|
+
def up
|
67
|
+
create_sequence :position, step: 2
|
68
|
+
end
|
69
|
+
end.up
|
70
|
+
|
71
|
+
assert_equal 1, MariaDB.nextval(:position)
|
72
|
+
assert_equal 3, MariaDB.nextval(:position)
|
73
|
+
end
|
74
|
+
|
75
|
+
test "returns current/last sequence value, which doesn't increase by itself" do
|
76
|
+
with_migration do
|
77
|
+
def up
|
78
|
+
create_sequence :position
|
79
|
+
end
|
80
|
+
end.up
|
81
|
+
|
82
|
+
MariaDB.nextval(:position)
|
83
|
+
|
84
|
+
assert_equal 1, MariaDB.currval(:position)
|
85
|
+
assert_equal 1, MariaDB.lastval(:position)
|
86
|
+
assert_equal 1, MariaDB.currval(:position)
|
87
|
+
assert_equal 1, MariaDB.lastval(:position)
|
88
|
+
end
|
89
|
+
|
90
|
+
test 'sets sequence value' do
|
91
|
+
with_migration do
|
92
|
+
def up
|
93
|
+
create_sequence :position
|
94
|
+
end
|
95
|
+
end.up
|
96
|
+
|
97
|
+
MariaDB.nextval(:position)
|
98
|
+
assert_equal MariaDB.currval(:position), 1
|
99
|
+
|
100
|
+
MariaDB.setval(:position, 101)
|
101
|
+
# in MariaDB, 'lastval' only works after 'nextval' rather than 'setval'
|
102
|
+
assert_equal 1, MariaDB.lastval(:position)
|
103
|
+
|
104
|
+
MariaDB.nextval(:position)
|
105
|
+
# now the value is correct
|
106
|
+
assert_equal 102, MariaDB.lastval(:position)
|
107
|
+
end
|
108
|
+
|
109
|
+
test 'drops sequence and check_sequences' do
|
110
|
+
with_migration do
|
111
|
+
def up
|
112
|
+
create_sequence :position
|
113
|
+
end
|
114
|
+
end.up
|
115
|
+
|
116
|
+
sequence = MariaDB.check_sequences.find_all do |seq|
|
117
|
+
seq[:Tables_in_test] == 'position'
|
118
|
+
end
|
119
|
+
|
120
|
+
assert_equal 1, sequence.size
|
121
|
+
|
122
|
+
with_migration do
|
123
|
+
def down
|
124
|
+
drop_sequence :position
|
125
|
+
end
|
126
|
+
end.down
|
127
|
+
|
128
|
+
sequence = MariaDB.check_sequences.find do |seq|
|
129
|
+
seq[:Tables_in_test] == 'position'
|
130
|
+
end
|
131
|
+
|
132
|
+
assert_nil sequence
|
133
|
+
end
|
134
|
+
|
135
|
+
test 'orders sequences' do
|
136
|
+
list = MariaDB.check_sequences.map { |s| s[:Tables_in_test] }
|
137
|
+
assert !list.include?('a')
|
138
|
+
assert !list.include?('b')
|
139
|
+
assert !list.include?('c')
|
140
|
+
|
141
|
+
with_migration do
|
142
|
+
def up
|
143
|
+
drop_table :things, if_exists: true
|
144
|
+
create_sequence :c
|
145
|
+
create_sequence :a
|
146
|
+
create_sequence :b
|
147
|
+
end
|
148
|
+
end.up
|
149
|
+
|
150
|
+
list = MariaDB.check_sequences.map { |s| s[:Tables_in_test] }
|
151
|
+
assert list.include?('a')
|
152
|
+
assert list.include?('b')
|
153
|
+
assert list.include?('c')
|
154
|
+
end
|
155
|
+
|
156
|
+
test 'creates table that references sequence' do
|
157
|
+
with_migration do
|
158
|
+
def up
|
159
|
+
drop_table :builders, if_exists: true
|
160
|
+
create_sequence :position_id, if_exists: false, start: 1
|
161
|
+
create_table :builders do
|
162
|
+
primary_key :id
|
163
|
+
String :name, text: true
|
164
|
+
Bignum :position, null: false
|
165
|
+
end
|
166
|
+
set_column_default_nextval :builders, :position, :position_id
|
167
|
+
end
|
168
|
+
end.up
|
169
|
+
|
170
|
+
class Builder < Sequel::Model; end
|
171
|
+
|
172
|
+
builder1 = Builder.create(name: 'Builder 1')
|
173
|
+
pos1 = MariaDB.currval(:position_id)
|
174
|
+
assert_equal pos1, builder1.reload.position
|
175
|
+
|
176
|
+
builder2 = Builder.create(name: 'Builder 2')
|
177
|
+
pos2 = MariaDB.currval(:position_id)
|
178
|
+
assert_equal pos2, builder2.reload.position
|
179
|
+
|
180
|
+
assert_equal pos2 - pos1, 1
|
181
|
+
end
|
182
|
+
end
|