sequel-sequence 0.3.0 → 0.4.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/.github/workflows/ci.yml +41 -8
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +110 -13
- data/README.md +28 -9
- data/Rakefile +9 -1
- data/lib/sequel/sequence/database/postgresql.rb +3 -2
- data/lib/sequel/sequence/database/server/mariadb.rb +71 -0
- data/lib/sequel/sequence/database/server/mysql.rb +178 -0
- data/lib/sequel/sequence/database/sqlite.rb +11 -4
- data/lib/sequel/sequence/database.rb +2 -2
- data/lib/sequel/sequence/database_ext_connection.rb +25 -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/mysql_test_helper.rb +11 -9
- data/test/sequel/mariadb_sequence_test.rb +182 -0
- data/test/sequel/mysql_sequence_test.rb +214 -41
- data/test/sequel/sqlite_sequence_test.rb +77 -5
- data/test/sqlite_test_helper.rb +2 -1
- metadata +11 -6
- data/lib/sequel/sequence/database/mysql.rb +0 -10
- data/lib/sequel/sequence/database/mysql2.rb +0 -81
@@ -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)
|
@@ -85,6 +88,10 @@ module Sequel
|
|
85
88
|
)
|
86
89
|
end
|
87
90
|
|
91
|
+
def insert_into_sequence_table_init_values(name, start_id, num_label)
|
92
|
+
"INSERT INTO #{name} (id, fiction) VALUES (#{start_id}, #{num_label});"
|
93
|
+
end
|
94
|
+
|
88
95
|
def insert_into_sequence_table(name, num_label)
|
89
96
|
"INSERT INTO #{name} (fiction) VALUES (#{num_label});"
|
90
97
|
end
|
@@ -119,7 +126,7 @@ module Sequel
|
|
119
126
|
CREATE TRIGGER IF NOT EXISTS #{table}_#{sequence} AFTER INSERT
|
120
127
|
ON #{table}
|
121
128
|
BEGIN
|
122
|
-
INSERT INTO #{sequence}(fiction) VALUES (0);
|
129
|
+
INSERT INTO #{sequence} (fiction) VALUES (0);
|
123
130
|
UPDATE #{table}
|
124
131
|
SET #{column} = (SELECT MAX(seq) FROM sqlite_sequence WHERE name = '#{sequence}')
|
125
132
|
WHERE rowid = NEW.rowid;
|
@@ -53,12 +53,12 @@ module Sequel
|
|
53
53
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
54
54
|
end
|
55
55
|
|
56
|
-
# for
|
56
|
+
# for Postgres
|
57
57
|
def currval(_name)
|
58
58
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::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)
|
@@ -0,0 +1,25 @@
|
|
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 = db.mariadb? ? Mariadb : Mysql
|
18
|
+
puts "Sequel::Database.REconnect mariadb? = #{db.mariadb?.inspect}"
|
19
|
+
puts "Sequel::Database.REconnect server_version = #{db.server_version.inspect}"
|
20
|
+
Sequel::Mysql2::Database.include(@dbms)
|
21
|
+
end
|
22
|
+
db
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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
|
|
@@ -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
|