sequel-sequence 0.4.0 → 0.4.1

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: ba4270613514ab8a88b24fa9034314333feba102dff7719a8e238ca1c84e67d1
4
- data.tar.gz: 950c6494e0c9f55f6465beee78209649c784508c9c9c0dab1b9817576cbf3a7c
3
+ metadata.gz: 749ea113ce41f1f7f70f620d5aa70deac470a76491cdb36b4bd8e5c739487a07
4
+ data.tar.gz: 9628bc8f57ad5a1ead78d82eaa8348963876c93a6be40df0d8c9dabfab928f76
5
5
  SHA512:
6
- metadata.gz: ed1505fd942d5247ea8ad64b47e1caa9cc420826ace83e4f8c075db257090576772219aa9f48007a0c9d84793f127ec82604a310688717b18ece0ceec8824d66
7
- data.tar.gz: c781c917e87029eec161ae656bb331552e6e0f531ceb8c6f3df8b836686f9f1bc7a4f277f81c15a9c515f2861624ed73f978a7be7b7db35d29a32c09aef277f5
6
+ metadata.gz: d0dbf107132dad0bcd23bcf5da23cb9fb121119dafb109865978a6bf26fe8465985875fd6d33b72422cd57e1d5b74b54fce065ba7a2fdf21b0d76f032b7c149e
7
+ data.tar.gz: bd1bbeaf56ddcd37b4bc86b6b83ad06e85212c7f09bb32db03004bfc9599dd240b141ea6c6130d64fe8b85471c3e6bb7cd8537714b7b6f34f744142b117ce606
@@ -126,5 +126,8 @@ jobs:
126
126
  env:
127
127
  TEST_SQLITE_DATABASE: "db/test.sqlite3"
128
128
 
129
+ - name: Run Mock Tests
130
+ run: bundle exec rake TEST=test/sequel/mock_sequence_test.rb
131
+
129
132
  - name: Run Rubocop
130
133
  run: bundle exec rake rubocop
data/CHANGELOG.md CHANGED
@@ -11,6 +11,13 @@ Prefix your message with one of the following:
11
11
  - [Security] in case of vulnerabilities.
12
12
  -->
13
13
 
14
+ ## v0.4.1 - 2023-09-28
15
+
16
+ - [Added] Important notice to README.md.
17
+ - [Added] MySQL tests cover 100%.
18
+ - [Added] SQLite tests cover 100%.
19
+ - [Added] Mock connection to check for additional ORM exceptions.
20
+
14
21
  ## v0.4.0 - 2023-09-26
15
22
 
16
23
  - [Fixed] Differences between MySQL and MariaDB.
data/CONTRIBUTING.md CHANGED
@@ -235,4 +235,5 @@ $ bundle exec rake TEST=test/sequel/postgresql_sequence_test.rb
235
235
  $ bundle exec rake TEST=test/sequel/mariadb_sequence_test.rb
236
236
  $ bundle exec rake TEST=test/sequel/mysql_sequence_test.rb
237
237
  $ bundle exec rake TEST=test/sequel/sqlite_sequence_test.rb
238
+ $ bundle exec rake TEST=test/sequel/mock_sequence_test.rb
238
239
  ```
data/README.md CHANGED
@@ -48,7 +48,7 @@ Sequel.migration do
48
48
  end
49
49
  ```
50
50
 
51
- You can also specify the initial value and increment:
51
+ You can also specify the following optional parameters: `if_exists` – a condition of acceptability; `start` – an initial value; `increment` or `step` – step size to the next auto incrementing value:
52
52
 
53
53
  ```ruby
54
54
  create_sequence :position, increment: 2
@@ -107,7 +107,7 @@ CREATE TABLE `name_of_your_sequence_table`
107
107
  (id integer primary key autoincrement, fiction integer);
108
108
  ```
109
109
 
110
- You might utilize the last field as a numeric label to collect statistics on the operation of the end-to-end counter `"name_of_your_sequence_table".id` within the application.
110
+ You might utilize the last field `fiction` as a numeric label to collect statistics on the operation of the end-to-end counter `"name_of_your_sequence_table".id` within the application.
111
111
  ```ruby
112
112
  create_sequence :position, if_exists: false, start: 1000, numeric_label: 1
113
113
  ```
@@ -120,6 +120,10 @@ By default, `fiction` has a zero value.
120
120
 
121
121
  Otherwise, the operation of this gem for SQLite and MySQL is similar to the ways of using Sequence in more advanced RDBMS. There is only one difference here, you won't be able to change the increment value from 1 to another using the `increment` or `step` parameter.
122
122
 
123
+ ## Known issues you may encounter
124
+
125
+ This solution does not allow you to simultaneously work with MySQL and MariaDB databases from one application. If such a need arises, move the data processing functionality to different microservices.
126
+
123
127
  ## Maintainer
124
128
 
125
129
  - [Nikolai Bocharov](https://github.com/oreol-group)
data/Rakefile CHANGED
@@ -9,7 +9,8 @@ Rake::TestTask.new(:test) do |t|
9
9
  t.libs << 'lib'
10
10
  t.test_files = FileList['test/sequel/postgresql_sequence_test.rb',
11
11
  'test/sequel/mariadb_sequence_test.rb',
12
- 'test/sequel/sqlite_sequence_test.rb']
12
+ 'test/sequel/sqlite_sequence_test.rb',
13
+ 'test/sequel/mock_sequence_test.rb']
13
14
  end
14
15
 
15
16
  Rake::TestTask.new(:mysql) do |t|
@@ -18,6 +19,30 @@ Rake::TestTask.new(:mysql) do |t|
18
19
  t.test_files = FileList['test/sequel/mysql_sequence_test.rb']
19
20
  end
20
21
 
22
+ Rake::TestTask.new(:postgresql) do |t|
23
+ t.libs << 'test'
24
+ t.libs << 'lib'
25
+ t.test_files = FileList['test/sequel/postgresql_sequence_test.rb']
26
+ end
27
+
28
+ Rake::TestTask.new(:mariadb) do |t|
29
+ t.libs << 'test'
30
+ t.libs << 'lib'
31
+ t.test_files = FileList['test/sequel/mariadb_sequence_test.rb']
32
+ end
33
+
34
+ Rake::TestTask.new(:sqlite) do |t|
35
+ t.libs << 'test'
36
+ t.libs << 'lib'
37
+ t.test_files = FileList['test/sequel/sqlite_sequence_test.rb']
38
+ end
39
+
40
+ Rake::TestTask.new(:mock) do |t|
41
+ t.libs << 'test'
42
+ t.libs << 'lib'
43
+ t.test_files = FileList['test/sequel/mock_sequence_test.rb']
44
+ end
45
+
21
46
  RuboCop::RakeTask.new
22
47
 
23
48
  task default: %i[test rubocop]
data/lib/sequel/error.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sequel
4
- class MethodNotAllowed < StandardError
5
- METHOD_NOT_ALLOWED = 'Method not allowed'
4
+ (
5
+ # Error raised when attempting to utilize an invalid adapter to SEQUENCE interface.
6
+ MethodNotAllowed = Class.new(Error)
7
+ ).name
6
8
 
7
- # Initialize a new Error object
8
- def initialize(message = '')
9
- super(message)
10
- end
9
+ class Database
10
+ METHOD_NOT_ALLOWED = 'Method not allowed'
11
11
  end
12
12
  end
@@ -1,71 +1,79 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Mariadb
4
- def quote_column_name(name)
5
- "`#{name.gsub('`', '``')}`"
6
- end
3
+ module Sequel
4
+ module Sequence
5
+ module Database
6
+ module Server
7
+ module Mariadb
8
+ def quote_column_name(name)
9
+ "`#{name.gsub('`', '``')}`"
10
+ end
7
11
 
8
- def quote_sequence_name(name)
9
- "`#{name.gsub(/[`"']/, '')}`"
10
- end
12
+ def quote_sequence_name(name)
13
+ "`#{name.gsub(/[`"']/, '')}`"
14
+ end
11
15
 
12
- def check_sequences
13
- fetch("SHOW FULL TABLES WHERE Table_type = 'SEQUENCE';").all.to_a
14
- end
16
+ def check_sequences
17
+ fetch("SHOW FULL TABLES WHERE Table_type = 'SEQUENCE';").all.to_a
18
+ end
15
19
 
16
- def create_sequence(name, options = {})
17
- increment = options[:increment] || options[:step]
18
- if_exists = build_exists_condition(options[:if_exists])
19
- name = quote_name(name.to_s)
20
+ def create_sequence(name, options = {})
21
+ increment = options[:increment] || options[:step]
22
+ if_exists = build_exists_condition(options[:if_exists])
23
+ name = quote_name(name.to_s)
20
24
 
21
- sql = ["CREATE SEQUENCE #{if_exists || Sequel::Database::IF_NOT_EXISTS} #{name}"]
22
- sql << "INCREMENT BY #{increment}" if increment
23
- sql << "START WITH #{options[:start]}" if options[:start]
24
- sql << ';'
25
+ sql = ["CREATE SEQUENCE #{if_exists || Sequel::Database::IF_NOT_EXISTS} #{name}"]
26
+ sql << "INCREMENT BY #{increment}" if increment
27
+ sql << "START WITH #{options[:start]}" if options[:start]
28
+ sql << ';'
25
29
 
26
- run(sql.join("\n"))
27
- end
30
+ run(sql.join("\n"))
31
+ end
28
32
 
29
- def drop_sequence(name)
30
- name = quote_name(name.to_s)
31
- sql = "DROP SEQUENCE IF EXISTS #{name}"
32
- run(sql)
33
- end
33
+ def drop_sequence(name)
34
+ name = quote_name(name.to_s)
35
+ sql = "DROP SEQUENCE IF EXISTS #{name}"
36
+ run(sql)
37
+ end
34
38
 
35
- def nextval(name)
36
- name = quote(name.to_s)
37
- out = nil
38
- fetch("SELECT nextval(#{name});") do |row|
39
- out = row["nextval(#{name})".to_sym]
40
- end
41
- out
42
- end
39
+ def nextval(name)
40
+ name = quote(name.to_s)
41
+ out = nil
42
+ fetch("SELECT nextval(#{name});") do |row|
43
+ out = row["nextval(#{name})".to_sym]
44
+ end
45
+ out
46
+ end
43
47
 
44
- def lastval(name)
45
- name = quote(name.to_s)
46
- out = nil
47
- fetch("SELECT lastval(#{name});") do |row|
48
- out = row["lastval(#{name})".to_sym]
49
- end
50
- out
51
- end
48
+ def lastval(name)
49
+ name = quote(name.to_s)
50
+ out = nil
51
+ fetch("SELECT lastval(#{name});") do |row|
52
+ out = row["lastval(#{name})".to_sym]
53
+ end
54
+ out
55
+ end
52
56
 
53
- alias currval lastval
57
+ alias currval lastval
54
58
 
55
- def setval(name, value)
56
- name = quote(name.to_s)
57
- out = nil
58
- fetch("SELECT setval(#{name}, #{value});") do |row|
59
- out = row["setval(#{name}, #{value})".to_sym]
60
- end
61
- out
62
- end
59
+ def setval(name, value)
60
+ name = quote(name.to_s)
61
+ out = nil
62
+ fetch("SELECT setval(#{name}, #{value});") do |row|
63
+ out = row["setval(#{name}, #{value})".to_sym]
64
+ end
65
+ out
66
+ end
63
67
 
64
- def set_column_default_nextval(table, column, sequence)
65
- table = table.to_s
66
- column = column.to_s
67
- sequence = quote(sequence.to_s)
68
- run "ALTER TABLE IF EXISTS #{table} " \
69
- "ALTER COLUMN #{column} SET DEFAULT nextval(#{sequence});"
68
+ def set_column_default_nextval(table, column, sequence)
69
+ table = table.to_s
70
+ column = column.to_s
71
+ sequence = quote(sequence.to_s)
72
+ run "ALTER TABLE IF EXISTS #{table} " \
73
+ "ALTER COLUMN #{column} SET DEFAULT nextval(#{sequence});"
74
+ end
75
+ end
76
+ end
77
+ end
70
78
  end
71
79
  end
@@ -1,178 +1,185 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Mysql
4
- def check_sequences
5
- fetch('SELECT * FROM mysql_sequence;').all.to_a
6
- end
7
-
8
- def custom_sequence?(sequence_name)
9
- out = nil
10
- begin
11
- fetch(select_from_mysql_sequence_where(stringify(sequence_name))) do |row|
12
- out = row[:name]
13
- end
14
- rescue Sequel::DatabaseError
15
- return false
16
- end
17
-
18
- !out.nil?
19
- end
20
-
21
- def create_sequence(name, options = {})
22
- check_options(options)
23
- if_exists = build_exists_condition(options[:if_exists])
24
- start_option = options[:start] || 1
25
- num_label = options[:numeric_label] || 0
26
- return if (current = lastval(name)) && (current >= start_option)
27
-
28
- run create_sequence_table(stringify(name), if_exists)
29
- run insert_into_sequence_table_init_values(stringify(name), start_option, num_label)
30
- run create_mysql_sequence
31
- table_matcher { run delete_from_mysql_sequence(stringify(name)) }
32
- run insert_into_mysql_sequence(stringify(name), start_option)
33
- end
34
-
35
- def drop_sequence(name, options = {})
36
- if_exists = build_exists_condition(options[:if_exists])
37
- run drop_sequence_table(stringify(name), if_exists)
38
- table_matcher { run delete_from_mysql_sequence(stringify(name)) }
39
- end
40
-
41
- def nextval(name)
42
- run insert_into_sequence_table(stringify(name), 0)
43
- table_matcher { run delete_from_mysql_sequence(stringify(name)) }
44
- run insert_last_insert_id_into_mysql_sequence(stringify(name))
45
- take_seq(stringify(name))
46
- end
47
-
48
- def nextval_with_label(name, num_label = 0)
49
- run insert_into_sequence_table(stringify(name), num_label)
50
- table_matcher { run delete_from_mysql_sequence(stringify(name)) }
51
- run insert_last_insert_id_into_mysql_sequence(stringify(name))
52
- take_seq(stringify(name))
53
- end
54
-
55
- def lastval(name)
56
- take_seq(stringify(name))
57
- end
58
-
59
- alias currval lastval
60
-
61
- def setval(name, value)
62
- current = lastval(stringify(name))
63
- if current.nil?
64
- create_sequence(stringify(name), { start: value })
65
- elsif value < current
66
- log_info Sequel::Database::DANGER_OPT_ID
67
- value = current
68
- elsif value > current
69
- run insert_into_sequence_table_init_values(stringify(name), value, 0)
70
- table_matcher { run delete_from_mysql_sequence(stringify(name)) }
71
- run insert_into_mysql_sequence(stringify(name), value)
72
- end
73
- value
74
- end
75
-
76
- def set_column_default_nextval(table, column, sequence)
77
- run create_sequenced_column(stringify(table),
78
- stringify(column),
79
- stringify(sequence))
80
- run update_sequenced_column(stringify(table),
81
- stringify(column),
82
- stringify(sequence))
83
- end
84
-
85
- private
86
-
87
- def stringify(name)
88
- @name ||= {}
89
- @name.fetch(name, nil) || (@name[name] = name.to_s)
90
- end
91
-
92
- def select_from_mysql_sequence_where(name)
93
- "SELECT * FROM mysql_sequence where name = '#{name}';"
94
- end
95
-
96
- def create_sequence_table(name, if_exists = nil)
97
- %(
98
- CREATE TABLE #{if_exists || Sequel::Database::IF_NOT_EXISTS} #{name}
99
- (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
100
- fiction INT);
101
- ).strip
102
- end
103
-
104
- def insert_into_sequence_table_init_values(name, start_id, num_label)
105
- "INSERT INTO #{name} (id, fiction) VALUES (#{start_id}, #{num_label});"
106
- end
107
-
108
- def create_mysql_sequence
109
- %(
110
- CREATE TABLE #{Sequel::Database::IF_NOT_EXISTS} mysql_sequence
111
- (name VARCHAR(40), seq INT);
112
- ).strip
113
- end
114
-
115
- def select_max_seq(name)
116
- "SELECT MAX(seq) AS id FROM mysql_sequence WHERE name = '#{name}';"
117
- end
118
-
119
- def take_seq(name)
120
- table_matcher do
121
- out = nil
122
- fetch(select_max_seq(name)) do |row|
123
- out = row[:id]
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
124
182
  end
125
- out
126
183
  end
127
184
  end
128
-
129
- def delete_from_mysql_sequence(name)
130
- "DELETE QUICK IGNORE FROM mysql_sequence WHERE name = '#{name}';"
131
- end
132
-
133
- def insert_into_mysql_sequence(name, value)
134
- "INSERT INTO mysql_sequence (name, seq) VALUES ('#{name}', #{value});"
135
- end
136
-
137
- def drop_sequence_table(name, if_exists = nil)
138
- "DROP TABLE #{if_exists || Sequel::Database::IF_EXISTS} #{name};"
139
- end
140
-
141
- def insert_into_sequence_table(name, num_label)
142
- "INSERT INTO #{name} (fiction) VALUES (#{num_label});"
143
- end
144
-
145
- def insert_last_insert_id_into_mysql_sequence(name)
146
- "INSERT INTO mysql_sequence (name, seq) VALUES ('#{name}', LAST_INSERT_ID());"
147
- end
148
-
149
- def create_sequenced_column(table, _column, sequence)
150
- %(
151
- CREATE TRIGGER IF NOT EXISTS #{table}_#{sequence} BEFORE INSERT
152
- ON #{table}
153
- FOR EACH ROW BEGIN
154
- DELETE QUICK IGNORE FROM mysql_sequence WHERE name = '#{sequence}';
155
- INSERT INTO #{sequence} SET fiction = 0;
156
- INSERT INTO mysql_sequence SET name = '#{sequence}', seq = LAST_INSERT_ID();
157
-
158
- END;
159
- ).strip
160
- end
161
-
162
- def update_sequenced_column(table, column, sequence)
163
- %(
164
- CREATE TRIGGER IF NOT EXISTS #{table}_#{column} BEFORE INSERT
165
- ON #{table}
166
- FOR EACH ROW FOLLOWS #{table}_#{sequence}
167
- SET NEW.#{column} = ( SELECT MAX(seq) FROM mysql_sequence WHERE name = '#{sequence}' );
168
- ).strip
169
- end
170
-
171
- def table_matcher(&block)
172
- block.call
173
- rescue Sequel::DatabaseError => e
174
- return if e.message =~ /\AMysql2::Error: Table(.)*doesn't exist\z/
175
-
176
- raise e
177
- end
178
185
  end
@@ -48,14 +48,10 @@ module Sequel
48
48
  if current.nil?
49
49
  create_sequence(stringify(name), { start: value })
50
50
  elsif value < current
51
- # sql = [delete_from_sqlite_sequence(name)]
52
- # sql << drop_sequence_table(name)
53
- # sql << insert_into_sqlite_sequence(name, value)
54
- # run(sql.join("\n"))
55
51
  log_info DANGER_OPT_ID
56
52
  value = current
57
53
  else
58
- run(insert_into_sqlite_sequence(stringify(name), value))
54
+ run(update_sqlite_sequence(stringify(name), value))
59
55
  end
60
56
  value
61
57
  end
@@ -96,21 +92,12 @@ module Sequel
96
92
  "INSERT INTO #{name} (fiction) VALUES (#{num_label});"
97
93
  end
98
94
 
99
- def insert_into_sqlite_sequence(name, value)
100
- current = take_seq(name)
101
- if current.nil?
102
- "INSERT INTO sqlite_sequence (name, seq) VALUES ('#{name}', #{value});"
103
- else
104
- %(
105
- UPDATE sqlite_sequence
106
- SET seq = #{[current, value].max}
107
- WHERE name = '#{name}';
108
- )
109
- end
110
- end
111
-
112
- def delete_from_sqlite_sequence(name)
113
- "DELETE FROM sqlite_sequence WHERE name = '#{name}';"
95
+ def update_sqlite_sequence(name, value)
96
+ %(
97
+ UPDATE sqlite_sequence
98
+ SET seq = #{value}
99
+ WHERE name = '#{name}';
100
+ )
114
101
  end
115
102
 
116
103
  def drop_sequence_table(name, if_exists = nil)
@@ -14,24 +14,24 @@ module Sequel
14
14
  end
15
15
 
16
16
  def custom_sequence?(_sequence_name)
17
- raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
17
+ raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
18
18
  end
19
19
 
20
20
  def check_sequences
21
- raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
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::MethodNotAllowed::METHOD_NOT_ALLOWED
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::MethodNotAllowed::METHOD_NOT_ALLOWED
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::MethodNotAllowed::METHOD_NOT_ALLOWED
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::MethodNotAllowed::METHOD_NOT_ALLOWED
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::MethodNotAllowed::METHOD_NOT_ALLOWED
49
+ raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
50
50
  end
51
51
 
52
52
  def nextval(_name)
53
- raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
53
+ raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
54
54
  end
55
55
 
56
56
  # for Postgres
57
57
  def currval(_name)
58
- raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
58
+ raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
59
59
  end
60
60
 
61
61
  # for MariaDB
62
62
  alias lastval currval
63
63
 
64
64
  def setval(_name, _value)
65
- raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
65
+ raise Sequel::MethodNotAllowed, Sequel::Database::METHOD_NOT_ALLOWED
66
66
  end
67
67
 
68
68
  def build_exists_condition(option)
@@ -14,9 +14,13 @@ module Sequel
14
14
  define_singleton_method(:connect) do |*args|
15
15
  db = old_connect.call(*args)
16
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}"
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})"
20
24
  Sequel::Mysql2::Database.include(@dbms)
21
25
  end
22
26
  db
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sequel
4
4
  module Sequence
5
- VERSION = '0.4.0'
5
+ VERSION = '0.4.1'
6
6
  end
7
7
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ MockDB = Sequel.connect('mock://postgresql')
@@ -31,4 +31,9 @@ module MysqlTestHelper
31
31
 
32
32
  Class.new(migration_class, &block).new(MysqlDB)
33
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
34
39
  end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mock_test_helper'
4
+
5
+ class MockSequenceTest < Minitest::Test
6
+ test 'checks check_options with params' do
7
+ mocked_method = Minitest::Mock.new
8
+ some_instance = MockDB
9
+
10
+ mocked_method.expect :call, true, [Sequel::Database::DANGER_OPT_INCREMENT]
11
+ some_instance.stub :log_info, mocked_method do
12
+ some_instance.check_options({ increment: 2 })
13
+ end
14
+ mocked_method.verify
15
+
16
+ mocked_method.expect :call, true, [Sequel::Database::DANGER_OPT_INCREMENT]
17
+ some_instance.stub :log_info, mocked_method do
18
+ some_instance.check_options({ step: 2 })
19
+ end
20
+ mocked_method.verify
21
+ end
22
+
23
+ test 'checks custom_sequence?' do
24
+ assert_raises Sequel::MethodNotAllowed do
25
+ MockDB.custom_sequence?(:position)
26
+ end
27
+ end
28
+
29
+ test 'checks check_sequences' do
30
+ assert_raises Sequel::MethodNotAllowed do
31
+ MockDB.check_sequences
32
+ end
33
+ end
34
+
35
+ test 'checks create_sequence' do
36
+ assert_raises Sequel::MethodNotAllowed do
37
+ MockDB.create_sequence(:position)
38
+ end
39
+ end
40
+
41
+ test 'checks drop_sequence' do
42
+ assert_raises Sequel::MethodNotAllowed do
43
+ MockDB.drop_sequence(:position)
44
+ end
45
+ end
46
+
47
+ test 'checks quote_name' do
48
+ assert_raises Sequel::MethodNotAllowed do
49
+ MockDB.quote_name(:position)
50
+ end
51
+ end
52
+
53
+ test 'checks quote' do
54
+ assert_raises Sequel::MethodNotAllowed do
55
+ MockDB.quote(:position)
56
+ end
57
+ end
58
+
59
+ test 'checks nextval_with_label' do
60
+ assert_raises Sequel::MethodNotAllowed do
61
+ MockDB.nextval_with_label(:position, 100)
62
+ end
63
+ end
64
+
65
+ test 'checks nextval' do
66
+ assert_raises Sequel::MethodNotAllowed do
67
+ MockDB.nextval(:position)
68
+ end
69
+ end
70
+
71
+ test 'checks currval' do
72
+ assert_raises Sequel::MethodNotAllowed do
73
+ MockDB.currval(:position)
74
+ end
75
+ end
76
+
77
+ test 'checks lastval' do
78
+ assert_raises Sequel::MethodNotAllowed do
79
+ MockDB.lastval(:position)
80
+ end
81
+ end
82
+
83
+ test 'checks setval' do
84
+ assert_raises Sequel::MethodNotAllowed do
85
+ MockDB.setval(:position, 100)
86
+ end
87
+ end
88
+
89
+ test 'checks build_exists_condition for a true condition' do
90
+ assert_equal Sequel::Database::IF_EXISTS, MockDB.build_exists_condition(true)
91
+ end
92
+
93
+ test 'checks build_exists_condition for a false condition' do
94
+ assert_equal Sequel::Database::IF_NOT_EXISTS, MockDB.build_exists_condition(false)
95
+ end
96
+
97
+ test 'checks build_exists_condition for a non boolean condition' do
98
+ assert_nil MockDB.build_exists_condition('')
99
+ end
100
+ end
@@ -352,4 +352,20 @@ class MysqlSequenceTest < Minitest::Test
352
352
 
353
353
  assert_equal pos4 - pos2, 2
354
354
  end
355
+
356
+ test "catches a Mysql2::Error: «Table mysql_sequence doesn't exist»" do
357
+ assert !sequence_table_exists?('position')
358
+
359
+ MysqlDB.drop_table :mysql_sequence, if_exists: true
360
+
361
+ last_number = MysqlDB.lastval(:position)
362
+ assert_nil last_number
363
+ end
364
+
365
+ test 'creates a Sequence by calling DB.setval(position, 1) if it still does not exist' do
366
+ assert !sequence_table_exists?('position')
367
+
368
+ MysqlDB.setval(:position, 100)
369
+ assert_equal 100, MysqlDB.currval(:position)
370
+ end
355
371
  end
@@ -166,9 +166,7 @@ class SqliteSequenceTest < Minitest::Test
166
166
  end
167
167
  end.down
168
168
 
169
- sequence = SQLiteDB.check_sequences.find do |seq|
170
- seq[:name] == 'position'
171
- end
169
+ sequence = (list = SQLiteDB.check_sequences).empty? ? nil : list
172
170
 
173
171
  assert_nil sequence
174
172
  end
@@ -192,9 +190,7 @@ class SqliteSequenceTest < Minitest::Test
192
190
  end
193
191
  end.down
194
192
 
195
- sequence = SQLiteDB.check_sequences.find do |seq|
196
- seq[:name] == 'position'
197
- end
193
+ sequence = (list = SQLiteDB.check_sequences).empty? ? nil : list
198
194
 
199
195
  assert_nil sequence
200
196
  end
@@ -295,7 +291,6 @@ class SqliteSequenceTest < Minitest::Test
295
291
  test 'creates table that references sequence' do
296
292
  with_migration do
297
293
  def up
298
- drop_table :apprentices, if_exists: true
299
294
  create_sequence :position_id, if_exists: false, start: 1
300
295
  create_table :apprentices do
301
296
  primary_key :id
@@ -326,4 +321,11 @@ class SqliteSequenceTest < Minitest::Test
326
321
 
327
322
  assert_equal pos4 - pos2, 2
328
323
  end
324
+
325
+ test 'creates a Sequence by calling DB.setval(position, 1) if it still does not exist' do
326
+ assert !sequence_table_exists?('position')
327
+
328
+ SQLiteDB.setval(:position, 100)
329
+ assert_equal 100, SQLiteDB.currval(:position)
330
+ end
329
331
  end
@@ -10,9 +10,10 @@ SQLiteDB = Sequel.connect(
10
10
 
11
11
  module SqliteTestHelper
12
12
  def recreate_table
13
+ SQLiteDB.drop_table :apprentices, if_exists: true
13
14
  SQLiteDB.drop_sequence :position
14
15
  SQLiteDB.drop_sequence :position_id, if_exists: true
15
- SQLiteDB.run 'DROP TABLE IF EXISTS objects'
16
+ SQLiteDB.drop_table :objects, if_exists: true
16
17
  SQLiteDB.drop_sequence 'a'
17
18
  SQLiteDB.drop_sequence 'b'
18
19
  SQLiteDB.drop_sequence 'c'
@@ -27,4 +28,10 @@ module SqliteTestHelper
27
28
 
28
29
  Class.new(migration_class, &block).new(SQLiteDB)
29
30
  end
31
+
32
+ def sequence_table_exists?(name)
33
+ sql = "SELECT name FROM sqlite_schema WHERE type ='table' AND name NOT LIKE 'sqlite_%';"
34
+ table_list = SQLiteDB.fetch(sql).all.map { |_key, value| value }
35
+ table_list.include?(name)
36
+ end
30
37
  end
data/test/test_helper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'simplecov'
4
+
4
5
  SimpleCov.start
5
6
 
6
7
  require 'bundler/setup'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel-sequence
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nikolai Bocharov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-26 00:00:00.000000000 Z
11
+ date: 2023-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -194,9 +194,11 @@ files:
194
194
  - lib/sequel/sequence/version.rb
195
195
  - sequel-sequence.gemspec
196
196
  - test/mariadb_test_helper.rb
197
+ - test/mock_test_helper.rb
197
198
  - test/mysql_test_helper.rb
198
199
  - test/postgresql_test_helper.rb
199
200
  - test/sequel/mariadb_sequence_test.rb
201
+ - test/sequel/mock_sequence_test.rb
200
202
  - test/sequel/mysql_sequence_test.rb
201
203
  - test/sequel/postgresql_sequence_test.rb
202
204
  - test/sequel/sqlite_sequence_test.rb