sequel-sequence 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,329 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sqlite_test_helper'
4
+
5
+ class SqliteSequenceTest < Minitest::Test
6
+ include SqliteTestHelper
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, numeric_label: 0} - default values
16
+ create_sequence :position
17
+ end
18
+ end.up
19
+
20
+ assert_equal 2, SQLiteDB.nextval(:position)
21
+ assert_equal 3, SQLiteDB.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 Object < Sequel::Model; end
32
+
33
+ assert_equal 2, Object.db.nextval('position')
34
+ assert_equal 3, Object.db.nextval('position')
35
+
36
+ class InheritedObject < Object; end
37
+
38
+ assert_equal 4, InheritedObject.db.nextval(:position)
39
+ assert_equal 5, InheritedObject.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 101, SQLiteDB.nextval(:position)
50
+ assert_equal 102, SQLiteDB.nextval(:position)
51
+ end
52
+
53
+ test 'adds a sequence that we are trying to increase by a value greater than 1' do
54
+ @step = 4
55
+ with_migration do
56
+ def up
57
+ create_sequence :position, increment: 4
58
+ end
59
+ end.up
60
+
61
+ assert_equal 2, SQLiteDB.nextval(:position)
62
+ assert_equal 3, SQLiteDB.nextval(:position)
63
+ assert_operator (2 + @step), :>, SQLiteDB.nextval(:position)
64
+ end
65
+
66
+ test 'adds a sequence that we are trying to increase by a value greater than 1 (using :step alias)' do
67
+ @step = 4
68
+ with_migration do
69
+ def up
70
+ create_sequence :position, step: 4
71
+ end
72
+ end.up
73
+
74
+ assert_equal 2, SQLiteDB.nextval(:position)
75
+ assert_equal 3, SQLiteDB.nextval(:position)
76
+ assert_operator (2 + @step), :>, SQLiteDB.nextval(:position)
77
+ end
78
+
79
+ test "returns current/last sequence value, which doesn't increase by itself" do
80
+ with_migration do
81
+ def up
82
+ create_sequence :position
83
+ end
84
+ end.up
85
+
86
+ SQLiteDB.nextval(:position)
87
+ # changed value (=2) after default one (=1)
88
+
89
+ assert_equal 2, SQLiteDB.currval(:position)
90
+ assert_equal 2, SQLiteDB.lastval(:position)
91
+ assert_equal 2, SQLiteDB.currval(:position)
92
+ assert_equal 2, SQLiteDB.lastval(:position)
93
+ end
94
+
95
+ test 'sets a new sequence value greater than the current one' do
96
+ with_migration do
97
+ def up
98
+ create_sequence :position
99
+ end
100
+ end.up
101
+
102
+ assert_equal SQLiteDB.currval(:position), 1
103
+
104
+ SQLiteDB.nextval(:position)
105
+ assert_equal SQLiteDB.currval(:position), 2
106
+
107
+ SQLiteDB.setval(:position, 101)
108
+ assert_equal 101, SQLiteDB.lastval(:position)
109
+
110
+ SQLiteDB.nextval(:position)
111
+ assert_equal 102, SQLiteDB.lastval(:position)
112
+ end
113
+
114
+ test 'sets a new sequence value less than the current one' do
115
+ with_migration do
116
+ def up
117
+ create_sequence :position, start: 100
118
+ end
119
+ end.up
120
+
121
+ assert_equal SQLiteDB.currval(:position), 100
122
+
123
+ SQLiteDB.nextval(:position)
124
+ assert_equal SQLiteDB.currval(:position), 101
125
+
126
+ SQLiteDB.setval(:position, 1)
127
+ assert_equal 101, SQLiteDB.lastval(:position)
128
+
129
+ assert_equal 102, SQLiteDB.nextval(:position)
130
+ end
131
+
132
+ test 'sets a new sequence value with a label' do
133
+ with_migration do
134
+ def up
135
+ create_sequence :position
136
+ end
137
+ end.up
138
+
139
+ SQLiteDB.nextval(:position)
140
+ SQLiteDB.nextval_with_label(:position, 1)
141
+ SQLiteDB.nextval_with_label(:position, 1)
142
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position where fiction = 1;').all.size
143
+ assert_equal 2, fiction_set_size
144
+
145
+ # create_sequence + nextval
146
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position where fiction = 0;').all.size
147
+ assert_equal 2, fiction_set_size
148
+ end
149
+
150
+ test 'drops the sequence and the check_sequences' do
151
+ with_migration do
152
+ def up
153
+ create_sequence :position
154
+ end
155
+ end.up
156
+
157
+ sequence = SQLiteDB.check_sequences.find_all do |seq|
158
+ seq[:name] == 'position'
159
+ end
160
+
161
+ assert_equal 1, sequence.size
162
+
163
+ with_migration do
164
+ def down
165
+ drop_sequence :position
166
+ end
167
+ end.down
168
+
169
+ sequence = SQLiteDB.check_sequences.find do |seq|
170
+ seq[:name] == 'position'
171
+ end
172
+
173
+ assert_nil sequence
174
+ end
175
+
176
+ test 'drops the sequence with the parameter if_exists' do
177
+ with_migration do
178
+ def up
179
+ create_sequence :position
180
+ end
181
+ end.up
182
+
183
+ sequence = SQLiteDB.check_sequences.find_all do |seq|
184
+ seq[:name] == 'position'
185
+ end
186
+
187
+ assert_equal 1, sequence.size
188
+
189
+ with_migration do
190
+ def down
191
+ drop_sequence :position, if_exists: true
192
+ end
193
+ end.down
194
+
195
+ sequence = SQLiteDB.check_sequences.find do |seq|
196
+ seq[:name] == 'position'
197
+ end
198
+
199
+ assert_nil sequence
200
+ end
201
+
202
+ test 'orders sequences' do
203
+ list = SQLiteDB.check_sequences.map { |s| s[:name] }
204
+ assert !list.include?('a')
205
+ assert !list.include?('b')
206
+ assert !list.include?('c')
207
+
208
+ with_migration do
209
+ def up
210
+ drop_table :things, if_exists: true
211
+ create_sequence :c, { start: 1 }
212
+ create_sequence :a, { start: 3 }
213
+ create_sequence :b
214
+ end
215
+ end.up
216
+
217
+ list = SQLiteDB.check_sequences.map { |s| s[:name] }
218
+ assert list.include?('a')
219
+ assert list.include?('b')
220
+ assert list.include?('c')
221
+ end
222
+
223
+ test 'recreates the same sequence with the same start value' do
224
+ with_migration do
225
+ def up
226
+ create_sequence :position_id, if_exists: false, start: 1
227
+ end
228
+ end.up
229
+
230
+ assert_equal 1, SQLiteDB.currval(:position_id)
231
+
232
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position_id where fiction = 0;').all.size
233
+ assert_equal 1, fiction_set_size
234
+
235
+ with_migration do
236
+ def up
237
+ create_sequence :position_id, if_exists: false, start: 1
238
+ end
239
+ end.up
240
+
241
+ assert_equal 1, SQLiteDB.currval(:position_id)
242
+
243
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position_id where fiction = 0;').all.size
244
+ assert_equal 1, fiction_set_size
245
+ end
246
+
247
+ test 'recreates the same sequence with a smaller start value' do
248
+ with_migration do
249
+ def up
250
+ create_sequence :position_id, if_exists: false, start: 100
251
+ end
252
+ end.up
253
+
254
+ assert_equal 100, SQLiteDB.currval(:position_id)
255
+
256
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position_id where fiction = 0;').all.size
257
+ assert_equal 1, fiction_set_size
258
+
259
+ with_migration do
260
+ def up
261
+ create_sequence :position_id, if_exists: false, start: 1
262
+ end
263
+ end.up
264
+
265
+ assert_equal 100, SQLiteDB.currval(:position_id)
266
+
267
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position_id where fiction = 0;').all.size
268
+ assert_equal 1, fiction_set_size
269
+ end
270
+
271
+ test 'recreates the same sequence with a greater start value' do
272
+ with_migration do
273
+ def up
274
+ create_sequence :position_id, if_exists: false, start: 1
275
+ end
276
+ end.up
277
+
278
+ assert_equal 1, SQLiteDB.currval(:position_id)
279
+
280
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position_id where fiction = 0;').all.size
281
+ assert_equal 1, fiction_set_size
282
+
283
+ with_migration do
284
+ def up
285
+ create_sequence :position_id, if_exists: false, start: 100
286
+ end
287
+ end.up
288
+
289
+ assert_equal 100, SQLiteDB.currval(:position_id)
290
+
291
+ fiction_set_size = SQLiteDB.fetch('SELECT * FROM position_id where fiction = 0;').all.size
292
+ assert_equal 2, fiction_set_size
293
+ end
294
+
295
+ test 'creates table that references sequence' do
296
+ with_migration do
297
+ def up
298
+ drop_table :apprentices, if_exists: true
299
+ create_sequence :position_id, if_exists: false, start: 1
300
+ create_table :apprentices do
301
+ primary_key :id
302
+ String :name, text: true
303
+ Bignum :position
304
+ end
305
+ set_column_default_nextval :apprentices, :position, :position_id
306
+ end
307
+ end.up
308
+
309
+ class Apprentice < Sequel::Model; end
310
+
311
+ apprentice1 = Apprentice.create(name: 'Apprentice 1')
312
+ pos1 = SQLiteDB.lastval(:position_id) - 1
313
+ assert_equal pos1, apprentice1.reload.position
314
+
315
+ apprentice2 = Apprentice.create(name: 'Apprentice 2')
316
+ pos2 = SQLiteDB.currval(:position_id) - 1
317
+ assert_equal pos2, apprentice2.reload.position
318
+
319
+ assert_equal pos2 - pos1, 1
320
+
321
+ SQLiteDB.nextval(:position_id)
322
+
323
+ apprentice4 = Apprentice.create(name: 'Apprentice 4')
324
+ pos4 = SQLiteDB.currval(:position_id) - 1
325
+ assert_equal pos4, apprentice4.reload.position
326
+
327
+ assert_equal pos4 - pos2, 2
328
+ end
329
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'logger'
5
+
6
+ SQLiteDB = Sequel.connect(
7
+ "sqlite://#{ENV.fetch('TEST_SQLITE_DATABASE', nil) || 'db/test.sqlite3'}",
8
+ loggers: [Logger.new($stdout)]
9
+ )
10
+
11
+ module SqliteTestHelper
12
+ def recreate_table
13
+ SQLiteDB.drop_sequence :position
14
+ SQLiteDB.drop_sequence :position_id, if_exists: true
15
+ SQLiteDB.run 'DROP TABLE IF EXISTS objects'
16
+ SQLiteDB.drop_sequence 'a'
17
+ SQLiteDB.drop_sequence 'b'
18
+ SQLiteDB.drop_sequence 'c'
19
+ sql = 'CREATE TABLE objects (id INTEGER PRIMARY KEY AUTOINCREMENT, quantity INTEGER DEFAULT(0), slug VARCHAR(255));'
20
+ SQLiteDB.run sql
21
+ end
22
+
23
+ def with_migration(&block)
24
+ migration_class = Sequel::Migration
25
+
26
+ Sequel::Model.db = SQLiteDB
27
+
28
+ Class.new(migration_class, &block).new(SQLiteDB)
29
+ end
30
+ end
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.2.0
4
+ version: 0.4.0
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-14 00:00:00.000000000 Z
11
+ date: 2023-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -142,9 +142,24 @@ dependencies:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
144
  version: 1.5.4
145
+ - !ruby/object:Gem::Dependency
146
+ name: sqlite3
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: 1.6.0
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - "~>"
157
+ - !ruby/object:Gem::Version
158
+ version: 1.6.0
145
159
  description: |2
146
160
  This gem provides a single interface for SEQUENCE functionality
147
- in Postgresql and Mysql databases within the Sequel ORM.
161
+ in Postgresql and MariaDB DBMS within the Sequel ORM.
162
+ It also models the Sequences to meet the needs of SQLite and MySQL users.
148
163
  email:
149
164
  - it.architect@yahoo.com
150
165
  executables: []
@@ -171,15 +186,21 @@ files:
171
186
  - lib/sequel/error.rb
172
187
  - lib/sequel/sequence.rb
173
188
  - lib/sequel/sequence/database.rb
174
- - lib/sequel/sequence/database/mysql.rb
175
- - lib/sequel/sequence/database/mysql2.rb
176
189
  - lib/sequel/sequence/database/postgresql.rb
190
+ - lib/sequel/sequence/database/server/mariadb.rb
191
+ - lib/sequel/sequence/database/server/mysql.rb
192
+ - lib/sequel/sequence/database/sqlite.rb
193
+ - lib/sequel/sequence/database_ext_connection.rb
177
194
  - lib/sequel/sequence/version.rb
178
195
  - sequel-sequence.gemspec
196
+ - test/mariadb_test_helper.rb
179
197
  - test/mysql_test_helper.rb
180
198
  - test/postgresql_test_helper.rb
199
+ - test/sequel/mariadb_sequence_test.rb
181
200
  - test/sequel/mysql_sequence_test.rb
182
201
  - test/sequel/postgresql_sequence_test.rb
202
+ - test/sequel/sqlite_sequence_test.rb
203
+ - test/sqlite_test_helper.rb
183
204
  - test/test_helper.rb
184
205
  homepage: https://rubygems.org/gems/sequel-sequence
185
206
  licenses:
@@ -206,5 +227,6 @@ requirements: []
206
227
  rubygems_version: 3.4.19
207
228
  signing_key:
208
229
  specification_version: 4
209
- summary: Add support for PostgreSQL's and MySQL's SEQUENCE on Sequel migrations.
230
+ summary: Adds SEQUENCE support to Sequel for migrations to PostgreSQL, MariaDB, MySQL
231
+ and SQLite.
210
232
  test_files: []
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Sequel
4
- module Sequence
5
- module Database
6
- module Mysql
7
- end
8
- end
9
- end
10
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # https://sequel.jeremyevans.net/rdoc/files/doc/sql_rdoc.html
4
- # https://github.com/jeremyevans/sequel/blob/master/lib/sequel/database/connecting.rb
5
- module Sequel
6
- module Sequence
7
- module Database
8
- module Mysql2
9
- def quote_column_name(name)
10
- "`#{name.gsub('`', '``')}`"
11
- end
12
-
13
- def quote_sequence_name(name)
14
- "`#{name.gsub(/[`"']/, '')}`"
15
- end
16
-
17
- def check_sequences
18
- fetch("SHOW FULL TABLES WHERE Table_type = 'SEQUENCE';").all.to_a
19
- end
20
-
21
- def create_sequence(name, options = {})
22
- increment = options[:increment] || options[:step]
23
- name = quote_name(name.to_s)
24
-
25
- sql = ["CREATE SEQUENCE IF NOT EXISTS #{name}"]
26
- sql << "INCREMENT BY #{increment}" if increment
27
- sql << "START WITH #{options[:start]}" if options[:start]
28
- sql << ';'
29
-
30
- run(sql.join("\n"))
31
- end
32
-
33
- def drop_sequence(name)
34
- name = quote_name(name.to_s)
35
- sql = "DROP SEQUENCE #{name}"
36
- run(sql)
37
- end
38
-
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
47
-
48
- # for db.database_type = :mysql2
49
- def lastval(name)
50
- name = quote(name.to_s)
51
- out = nil
52
- fetch("SELECT lastval(#{name});") do |row|
53
- out = row["lastval(#{name})".to_sym]
54
- end
55
- out
56
- end
57
-
58
- # for db.database_type = :postgres
59
- alias currval lastval
60
-
61
- def setval(name, value)
62
- name = quote(name.to_s)
63
- out = nil
64
- fetch("SELECT setval(#{name}, #{value});") do |row|
65
- out = row["setval(#{name}, #{value})".to_sym]
66
- end
67
- out
68
- end
69
-
70
- def set_column_default_nextval(table, column, sequence)
71
- table = table.to_s
72
- column = column.to_s
73
- sequence = quote(sequence.to_s)
74
- run "ALTER TABLE IF EXISTS #{table} " \
75
- "ALTER COLUMN #{column} SET DEFAULT nextval(#{sequence});"
76
- end
77
- end
78
- end
79
- end
80
- end