sequel-sequence 0.2.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.
@@ -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