sequel-sequence 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 << insert_into_sqlite_sequence(stringify(name), start_option)
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 connection.adapter_name = "PostgreSQL"
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 connection.adapter_name = "Mysql2"
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sequel
4
4
  module Sequence
5
- VERSION = '0.3.0'
5
+ VERSION = '0.4.0'
6
6
  end
7
7
  end
@@ -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
  )
@@ -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
- "Add support for PostgreSQL's and MySQL's SEQUENCE on Sequel migrations."
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 Mysql databases within the Sequel ORM.
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
@@ -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'] || 'root',
9
- host: ENV['TEST_MYSQL_HOST'] || '127.0.0.1',
10
- port: ENV['TEST_MYSQL_PORT'] || 3306,
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.run 'DROP SEQUENCE IF EXISTS position'
17
- MysqlDB.run 'DROP TABLE IF EXISTS wares'
18
- MysqlDB.run 'DROP SEQUENCE IF EXISTS a'
19
- MysqlDB.run 'DROP SEQUENCE IF EXISTS b'
20
- MysqlDB.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));'
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