sequel-sequence 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sequel
4
+ module Sequence
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sequel/database'
4
+ require 'sequel/adapters/postgres'
5
+ # require 'sequel/adapters/mysql'
6
+ require 'sequel/adapters/mysql2'
7
+ require 'sequel/error'
8
+
9
+ module Sequel
10
+ module Sequence
11
+ require 'sequel/sequence/database'
12
+
13
+ module Database
14
+ require 'sequel/sequence/database/postgresql'
15
+ # require "sequel/sequence/database/mysql"
16
+ require 'sequel/sequence/database/mysql2'
17
+ end
18
+ end
19
+ end
20
+
21
+ Sequel::Database.include(
22
+ Sequel::Sequence::Database
23
+ )
24
+ Sequel::Postgres::Database.include(
25
+ Sequel::Sequence::Database::PostgreSQL
26
+ )
27
+ Sequel::Mysql2::Database.include(
28
+ Sequel::Sequence::Database::Mysql2
29
+ )
30
+ # Sequel::Mysql::Database.include(
31
+ # Sequel::Sequence::Database::Mysql
32
+ # )
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sequel/sequence'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require './lib/sequel/sequence/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'sequel-sequence'
7
+ spec.version = Sequel::Sequence::VERSION
8
+ spec.licenses = ['MIT']
9
+ spec.summary = \
10
+ "Add support for PostgreSQL's and MySQL's SEQUENCE on Sequel migrations."
11
+ spec.description = <<-DES
12
+ This gem provides a single interface for SEQUENCE functionality
13
+ in Postgresql and Mysql databases within the Sequel ORM.
14
+ DES
15
+ spec.authors = ['Nikolai Bocharov']
16
+ spec.email = ['it.architect@yahoo.com']
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.require_paths = ['lib']
19
+ spec.extra_rdoc_files = ['README.md']
20
+ spec.homepage = 'https://rubygems.org/gems/sequel-sequence'
21
+ spec.metadata = {
22
+ 'source_code_uri' => 'https://github.com/oreol-group/sequel-sequence',
23
+ 'changelog_uri' => 'https://github.com/oreol-group/sequel-sequence/blob/master/CHANGELOG.md',
24
+ 'bug_tracker_uri' => 'https://github.com/oreol-group/sequel-sequence/issues'
25
+ }
26
+ spec.platform = Gem::Platform::RUBY
27
+ spec.required_ruby_version = '>= 2.7.0'
28
+
29
+ spec.add_dependency 'sequel'
30
+ spec.add_development_dependency 'bundler'
31
+ spec.add_development_dependency 'minitest-utils'
32
+ spec.add_development_dependency 'pry-byebug'
33
+ spec.add_development_dependency 'rake'
34
+ spec.add_development_dependency 'rubocop'
35
+ spec.add_development_dependency 'simplecov'
36
+ if RUBY_ENGINE == 'jruby'
37
+ # JRuby Adapter Dependencies
38
+ spec.add_development_dependency 'jdbc-mysql'
39
+ spec.add_development_dependency 'jdbc-postgres'
40
+ else
41
+ # MRI/Rubinius Adapter Dependencies
42
+ spec.add_development_dependency 'mysql2'
43
+ spec.add_development_dependency 'pg'
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ MysqlDB = Sequel.connect('mysql2://root:root@localhost/test')
6
+
7
+ Sequel::Model.db = MysqlDB
8
+
9
+ class Ware < Sequel::Model
10
+ end
11
+
12
+ class InheritedWare < Ware
13
+ end
14
+
15
+ class Builder < Sequel::Model
16
+ end
17
+
18
+ module MysqlTestHelper
19
+ def recreate_table
20
+ MysqlDB.run 'DROP SEQUENCE IF EXISTS position'
21
+ MysqlDB.run 'DROP TABLE IF EXISTS wares'
22
+ MysqlDB.run 'DROP SEQUENCE IF EXISTS a'
23
+ MysqlDB.run 'DROP SEQUENCE IF EXISTS b'
24
+ MysqlDB.run 'DROP SEQUENCE IF EXISTS c'
25
+ sql = 'CREATE TABLE wares (id INT AUTO_INCREMENT, slug VARCHAR(255), quantity INT DEFAULT(0), PRIMARY KEY(id));'
26
+ MysqlDB.run sql
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ PostgresqlDB = Sequel.connect('postgres:///test')
6
+
7
+ Sequel::Model.db = PostgresqlDB
8
+
9
+ class Thing < Sequel::Model
10
+ end
11
+
12
+ class InheritedThing < Thing
13
+ end
14
+
15
+ class Master < Sequel::Model
16
+ end
17
+
18
+ module PostgresqlTestHelper
19
+ def recreate_table
20
+ PostgresqlDB.run 'DROP TABLE IF EXISTS things'
21
+ PostgresqlDB.run 'DROP SEQUENCE IF EXISTS position'
22
+ PostgresqlDB.run 'DROP SEQUENCE IF EXISTS a'
23
+ PostgresqlDB.run 'DROP SEQUENCE IF EXISTS b'
24
+ PostgresqlDB.run 'DROP SEQUENCE IF EXISTS c'
25
+ sql = 'CREATE TABLE things (id SERIAL PRIMARY KEY, slug VARCHAR(255), quantity INTEGER DEFAULT 0);'
26
+ PostgresqlDB.run sql
27
+ end
28
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mysql_test_helper'
4
+
5
+ class MysqlSequenceTest < Minitest::Test
6
+ include MysqlTestHelper
7
+
8
+ setup do
9
+ recreate_table
10
+ end
11
+
12
+ test 'adds sequence with default values' do
13
+ Sequel.migration do
14
+ up do
15
+ create_sequence :position
16
+ end
17
+ end.apply(MysqlDB, :up)
18
+
19
+ assert_equal 1, Ware.db.nextval(:position)
20
+ assert_equal 2, Ware.db.nextval(:position)
21
+ end
22
+
23
+ test 'adds sequence reader within inherited class' do
24
+ Sequel.migration do
25
+ up do
26
+ create_sequence :position
27
+ end
28
+ end.apply(MysqlDB, :up)
29
+
30
+ assert_equal 1, InheritedWare.db.nextval(:position)
31
+ assert_equal 2, InheritedWare.db.nextval(:position)
32
+ end
33
+
34
+ test 'adds sequence starting at 100' do
35
+ Sequel.migration do
36
+ up do
37
+ create_sequence :position, start: 100
38
+ end
39
+ end.apply(MysqlDB, :up)
40
+
41
+ assert_equal 100, Ware.db.nextval(:position)
42
+ assert_equal 101, Ware.db.nextval(:position)
43
+ end
44
+
45
+ test 'adds sequence incremented by 2' do
46
+ Sequel.migration do
47
+ up do
48
+ create_sequence :position, increment: 2
49
+ end
50
+ end.apply(MysqlDB, :up)
51
+
52
+ assert_equal 1, Ware.db.nextval(:position)
53
+ assert_equal 3, Ware.db.nextval(:position)
54
+ end
55
+
56
+ test 'adds sequence incremented by 2 (using :step alias)' do
57
+ Sequel.migration do
58
+ up do
59
+ create_sequence :position, step: 2
60
+ end
61
+ end.apply(MysqlDB, :up)
62
+
63
+ assert_equal 1, Ware.db.nextval(:position)
64
+ assert_equal 3, Ware.db.nextval(:position)
65
+ end
66
+
67
+ test 'returns current/last sequence value without incrementing it' do
68
+ Sequel.migration do
69
+ up do
70
+ create_sequence :position
71
+ end
72
+ end.apply(MysqlDB, :up)
73
+
74
+ Ware.db.nextval(:position)
75
+
76
+ assert_equal 1, Ware.db.currval(:position)
77
+ assert_equal 1, Ware.db.lastval(:position)
78
+ assert_equal 1, Ware.db.currval(:position)
79
+ assert_equal 1, Ware.db.lastval(:position)
80
+ end
81
+
82
+ test 'sets sequence value' do
83
+ Sequel.migration do
84
+ up do
85
+ create_sequence :position
86
+ end
87
+ end.apply(MysqlDB, :up)
88
+
89
+ Ware.db.nextval(:position)
90
+ assert_equal Ware.db.currval(:position), 1
91
+
92
+ # in mariaDB, 'lastval' only works after 'nextval' rather than 'setval'
93
+ Ware.db.setval(:position, 101)
94
+ Ware.db.nextval(:position)
95
+ assert_equal Ware.db.lastval(:position), 102
96
+ end
97
+
98
+ test 'drops sequence and check_sequences' do
99
+ Sequel.migration do
100
+ up do
101
+ create_sequence :position
102
+ end
103
+ end.apply(MysqlDB, :up)
104
+
105
+ sequence = MysqlDB.check_sequences.find_all do |seq|
106
+ seq[:Tables_in_test] == 'position'
107
+ end
108
+
109
+ assert_equal 1, sequence.size
110
+
111
+ Sequel.migration do
112
+ down do
113
+ drop_sequence :position
114
+ end
115
+ end.apply(MysqlDB, :down)
116
+
117
+ sequence = MysqlDB.check_sequences.find do |seq|
118
+ seq[:sequence_name] == 'position'
119
+ end
120
+
121
+ assert_nil sequence
122
+ end
123
+
124
+ test 'orders sequences' do
125
+ list = MysqlDB.check_sequences.map { |s| s[:Tables_in_test] }
126
+ assert !list.include?('a')
127
+ assert !list.include?('b')
128
+ assert !list.include?('c')
129
+
130
+ Sequel.migration do
131
+ up do
132
+ drop_table :things, if_exists: true
133
+ # drop_table :masters, if_exists: true
134
+ create_sequence :c
135
+ create_sequence :a
136
+ create_sequence :b
137
+ end
138
+ end.apply(MysqlDB, :up)
139
+
140
+ list = MysqlDB.check_sequences.map { |s| s[:Tables_in_test] }
141
+ assert list.include?('a')
142
+ assert list.include?('b')
143
+ assert list.include?('c')
144
+ end
145
+
146
+ test 'creates table that references sequence' do
147
+ Sequel.migration do
148
+ up do
149
+ drop_table :builders, if_exists: true
150
+ create_sequence :position_id, if_exists: false
151
+ create_table :builders do
152
+ primary_key :id
153
+ String :name, text: true
154
+
155
+ # PostgreSQL uses bigint as the sequence's default type.
156
+ Bignum :position, null: false
157
+ end
158
+ set_column_default_nextval :builders, :position, :position_id
159
+ end
160
+ end.apply(MysqlDB, :up)
161
+
162
+ builder1 = Builder.create(name: 'Builder 1')
163
+ pos1 = MysqlDB.currval(:position_id)
164
+ assert_equal pos1, builder1.reload.position
165
+
166
+ builder2 = Builder.create(name: 'Builder 2')
167
+ pos2 = MysqlDB.currval(:position_id)
168
+ assert_equal pos2, builder2.reload.position
169
+
170
+ assert_equal pos2 - pos1, 1
171
+ end
172
+ end
@@ -0,0 +1,183 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'postgresql_test_helper'
4
+
5
+ class PostgresqlSequenceTest < Minitest::Test
6
+ include PostgresqlTestHelper
7
+
8
+ setup do
9
+ recreate_table
10
+ end
11
+
12
+ test 'adds sequence with default values' do
13
+ Sequel.migration do
14
+ up do
15
+ # create_sequence :position, {start: 1, increment: 1} - default values
16
+ create_sequence :position
17
+ end
18
+ end.apply(PostgresqlDB, :up)
19
+
20
+ assert_equal 1, PostgresqlDB.nextval('position')
21
+ assert_equal 2, PostgresqlDB.nextval('position')
22
+ end
23
+
24
+ test 'adds sequence reader within inherited class' do
25
+ Sequel.migration do
26
+ up do
27
+ create_sequence :position
28
+ end
29
+ end.apply(PostgresqlDB, :up)
30
+
31
+ assert_equal 1, InheritedThing.db.nextval(:position)
32
+ assert_equal 2, InheritedThing.db.nextval(:position)
33
+ end
34
+
35
+ test 'adds sequence starting at 100' do
36
+ Sequel.migration do
37
+ up do
38
+ create_sequence :position, start: 100
39
+ end
40
+ end.apply(PostgresqlDB, :up)
41
+
42
+ assert_equal 100, Thing.db.nextval(:position)
43
+ assert_equal 101, Thing.db.nextval(:position)
44
+ end
45
+
46
+ test 'adds sequence incremented by 2' do
47
+ Sequel.migration do
48
+ up do
49
+ create_sequence :position, increment: 2
50
+ end
51
+ end.apply(PostgresqlDB, :up)
52
+
53
+ assert_equal 1, Thing.db.nextval(:position)
54
+ assert_equal 3, Thing.db.nextval(:position)
55
+ end
56
+
57
+ test 'adds sequence incremented by 2 (using :step alias)' do
58
+ Sequel.migration do
59
+ up do
60
+ create_sequence :position, step: 2
61
+ end
62
+ end.apply(PostgresqlDB, :up)
63
+
64
+ assert_equal 1, Thing.db.nextval(:position)
65
+ assert_equal 3, Thing.db.nextval(:position)
66
+ end
67
+
68
+ test 'returns current (or last as alias) sequence value without incrementing it' do
69
+ Sequel.migration do
70
+ up do
71
+ create_sequence :position, start: 2, increment: 2
72
+ end
73
+ end.apply(PostgresqlDB, :up)
74
+
75
+ Thing.db.nextval(:position)
76
+
77
+ assert_equal 2, Thing.db.currval(:position)
78
+ assert_equal 2, Thing.db.lastval(:position)
79
+ assert_equal 2, Thing.db.currval(:position)
80
+ assert_equal 2, Thing.db.lastval(:position)
81
+ end
82
+
83
+ test 'sets sequence value' do
84
+ Sequel.migration do
85
+ up do
86
+ create_sequence :position
87
+ end
88
+ end.apply(PostgresqlDB, :up)
89
+
90
+ Thing.db.nextval(:position)
91
+ assert_equal Thing.db.currval(:position), 1
92
+
93
+ Thing.db.setval(:position, 101)
94
+ assert_equal 101, Thing.db.currval(:position)
95
+ end
96
+
97
+ test 'drops sequence and check_sequences' do
98
+ Sequel.migration do
99
+ up do
100
+ create_sequence :position
101
+ end
102
+ end.apply(PostgresqlDB, :up)
103
+
104
+ sequence = PostgresqlDB.check_sequences.find_all do |seq|
105
+ seq[:sequence_name] == 'position'
106
+ end
107
+
108
+ assert_equal 1, sequence.size
109
+
110
+ Sequel.migration do
111
+ down do
112
+ drop_sequence :position
113
+ end
114
+ end.apply(PostgresqlDB, :down)
115
+
116
+ sequence = PostgresqlDB.check_sequences.find do |seq|
117
+ seq[:sequence_name] == 'position'
118
+ end
119
+
120
+ assert_nil sequence
121
+ end
122
+
123
+ test 'orders sequences' do
124
+ list = PostgresqlDB.check_sequences.map { |s| s[:sequence_name] }
125
+ assert !list.include?('a')
126
+ assert !list.include?('b')
127
+ assert !list.include?('c')
128
+
129
+ Sequel.migration do
130
+ up do
131
+ drop_table :things, if_exists: true
132
+ # drop_table :masters, if_exists: true
133
+ create_sequence :c
134
+ create_sequence :a
135
+ create_sequence :b
136
+ end
137
+ end.apply(PostgresqlDB, :up)
138
+
139
+ list = PostgresqlDB.check_sequences.map { |s| s[:sequence_name] }
140
+ assert list.include?('a')
141
+ assert list.include?('b')
142
+ assert list.include?('c')
143
+ end
144
+
145
+ test 'checks custom sequence generated from code' do
146
+ assert_equal PostgresqlDB.custom_sequence?(:c), false
147
+
148
+ Sequel.migration do
149
+ up do
150
+ create_sequence :c
151
+ end
152
+ end.apply(PostgresqlDB, :up)
153
+
154
+ assert_equal PostgresqlDB.custom_sequence?(:c), true
155
+ end
156
+
157
+ test 'creates table that references sequence' do
158
+ Sequel.migration do
159
+ up do
160
+ drop_table :masters, if_exists: true
161
+ create_sequence :position_id, if_exists: false
162
+ create_table :masters do
163
+ primary_key :id
164
+ String :name, text: true
165
+
166
+ # PostgreSQL uses bigint as the sequence's default type.
167
+ Bignum :position, null: false
168
+ end
169
+ set_column_default_nextval :masters, :position, :position_id
170
+ end
171
+ end.apply(PostgresqlDB, :up)
172
+
173
+ master1 = Master.create(name: 'MASTER 1')
174
+ pos1 = PostgresqlDB.currval(:position_id)
175
+ assert_equal pos1, master1.reload.position
176
+
177
+ master2 = Master.create(name: 'MASTER 2')
178
+ pos2 = PostgresqlDB.currval(:position_id)
179
+ assert_equal pos2, master2.reload.position
180
+
181
+ assert_equal pos2 - pos1, 1
182
+ end
183
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+
6
+ require 'bundler/setup'
7
+ require 'sequel'
8
+ require 'sequel/extensions/migration'
9
+ require 'sequel/sequence'
10
+ require 'minitest/utils'
11
+ require 'minitest/autorun'