sequel-sequence 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +6 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +11 -0
- data/README.md +26 -7
- data/lib/sequel/sequence/database/mysql2.rb +3 -2
- data/lib/sequel/sequence/database/postgresql.rb +3 -2
- data/lib/sequel/sequence/database/sqlite.rb +132 -0
- data/lib/sequel/sequence/database.rb +24 -1
- data/lib/sequel/sequence/version.rb +1 -1
- data/lib/sequel/sequence.rb +5 -0
- data/sequel-sequence.gemspec +2 -0
- data/test/sequel/mysql_sequence_test.rb +3 -3
- data/test/sequel/postgresql_sequence_test.rb +2 -2
- data/test/sequel/sqlite_sequence_test.rb +257 -0
- data/test/sqlite_test_helper.rb +29 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7012e03aa326861bef294edcf042850f662f9122664da409aa0dd764d9375d9
|
4
|
+
data.tar.gz: b309b36a931be17ee7cb628c21083ef8543bb60139a249aa9fd1d42378321297
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c13a9a6e000990aaee2bdcca4d3d7519a7164c3217d4164f35e40e43deb76f652215169396647568cb03cf111d2a103f2f0f5d5f45e174b8107588e4be1808f
|
7
|
+
data.tar.gz: e9483ab69ea26d780164a4e4683d75c2bd86d8c5d92983b506645c5544a3ebc277f25f12a463b1f959f675f0e780eaf3b22a82b9560e247f16f2a895518d0e53
|
data/.github/workflows/ci.yml
CHANGED
@@ -56,6 +56,7 @@ jobs:
|
|
56
56
|
DEBIAN_FRONTEND="noninteractive" sudo apt-get install -yqq mysql-client libmysqlclient-dev postgresql-client libpq-dev
|
57
57
|
mysql --host 127.0.0.1 --port ${{ job.services.mysql.ports[3306] }} -uroot -proot -e "SHOW GRANTS FOR 'root'@'localhost'"
|
58
58
|
env PGPASSWORD=postgres psql -h localhost -p ${{ job.services.postgres.ports[5432] }} -U postgres -l
|
59
|
+
sqlite3 --version
|
59
60
|
|
60
61
|
- name: Set up Ruby
|
61
62
|
uses: ruby/setup-ruby@v1
|
@@ -73,6 +74,10 @@ jobs:
|
|
73
74
|
run: |
|
74
75
|
psql -c 'create database "test";' -U postgres -h localhost -p ${{ job.services.postgres.ports[5432] }}
|
75
76
|
|
77
|
+
- name: Create SQLite database
|
78
|
+
run: |
|
79
|
+
mkdir ./db && touch ./db/test.sqlite3 && sqlite3 ./db/test.sqlite3
|
80
|
+
|
76
81
|
- name: Run Tests
|
77
82
|
run: bundle exec rake test
|
78
83
|
env:
|
@@ -86,6 +91,7 @@ jobs:
|
|
86
91
|
TEST_MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
|
87
92
|
TEST_MYSQL_USERNAME: root
|
88
93
|
TEST_MYSQL_PASSWORD: root
|
94
|
+
TEST_SQLITE_DATABASE: "db/test.sqlite3"
|
89
95
|
|
90
96
|
- name: Run Rubocop
|
91
97
|
run: bundle exec rake rubocop
|
data/.gitignore
CHANGED
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.3.0 - 2023-09-21
|
15
|
+
|
16
|
+
- [Added] A parametrized 'IF EXISTS' condition into the drop_sequence.
|
17
|
+
- [Added] A parametrized 'IF NOT EXISTS' condition into the create_sequence.
|
18
|
+
- [Added] Gem API support for SQLite databases.
|
19
|
+
- [Fixed] Tests for the Mysql database.
|
20
|
+
|
14
21
|
## v0.2.0 - 2023-09-14
|
15
22
|
|
16
23
|
- [Added] CI features based on GitHub Actions.
|
data/CONTRIBUTING.md
CHANGED
@@ -123,8 +123,19 @@ MariaDB [(none)]> USE test;
|
|
123
123
|
MariaDB [test]> CREATE TABLE IF NOT EXISTS wares(id int auto_increment, primary key(id));
|
124
124
|
MariaDB [test]> CREATE TABLE IF NOT EXISTS builders(id int auto_increment, primary key(id));
|
125
125
|
```
|
126
|
+
- Add a test SQLite database:
|
127
|
+
```bash
|
128
|
+
mkdir db && touch db/test.sqlite3
|
129
|
+
```
|
130
|
+
- Add a couple of tables in the SQLite database:
|
131
|
+
```bash
|
132
|
+
sqlite3 db/test.sqlite3
|
133
|
+
sqlite> create table objects(id integer primary key autoincrement);
|
134
|
+
sqlite> create table apprentices(id integer primary key autoincrement);
|
135
|
+
```
|
126
136
|
- Run the tests separately:
|
127
137
|
```bash
|
128
138
|
bundle exec rake TEST=test/sequel/postgresql_sequence_test.rb
|
129
139
|
bundle exec rake TEST=test/sequel/mysql_sequence_test.rb
|
140
|
+
bundle exec rake TEST=test/sequel/sqlite_sequence_test.rb
|
130
141
|
```
|
data/README.md
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
[](https://github.com/oreol-group/sequel-sequence)
|
4
4
|
[](https://rubygems.org/gems/sequel-sequence)
|
5
5
|
[](https://rubygems.org/profiles/it_architect)
|
6
|
+
[](https://codeclimate.com/github/Oreol-Group/sequel-sequence)
|
6
7
|
|
7
|
-
Adds a useful interface and support for PostgreSQL and MySQL `SEQUENCE` on Sequel migrations
|
8
|
+
Adds a useful interface and support for PostgreSQL and MySQL `SEQUENCE` on Sequel migrations. Gem includes functionality to cover the needs of SQLite users as well.
|
8
9
|
|
9
10
|
## Installation
|
10
11
|
|
@@ -18,14 +19,14 @@ Or add the following line to your project's Gemfile:
|
|
18
19
|
gem "sequel-sequence"
|
19
20
|
```
|
20
21
|
|
21
|
-
## Usage
|
22
|
+
## Usage with PostgreSQL and MariaDB
|
22
23
|
|
23
24
|
To create a `SEQUENCE`, just use the method `create_sequence`.
|
24
25
|
|
25
26
|
```ruby
|
26
27
|
Sequel.migration do
|
27
28
|
up do
|
28
|
-
create_sequence :position
|
29
|
+
create_sequence :position, if_exists: false
|
29
30
|
end
|
30
31
|
|
31
32
|
down do
|
@@ -39,22 +40,22 @@ You can also specify the initial value and increment:
|
|
39
40
|
```ruby
|
40
41
|
create_sequence :position, increment: 2
|
41
42
|
create_sequence :position, start: 100
|
43
|
+
create_sequence :position, if_exists: false
|
42
44
|
```
|
43
45
|
|
44
|
-
To define a column that has a sequence as its default value, use something like
|
45
|
-
the following:
|
46
|
+
To define a column that has a sequence as its default value, use something like the following:
|
46
47
|
|
47
48
|
```ruby
|
48
49
|
Sequel.migration do
|
49
50
|
change do
|
50
|
-
create_sequence :position_id
|
51
|
+
create_sequence :position_id, if_exists: false, start: 1
|
51
52
|
|
52
53
|
create_table(:things) do
|
53
54
|
primary_key :id
|
54
55
|
String :name, text: true
|
55
56
|
|
56
57
|
# PostgreSQL uses bigint as the sequence's default type.
|
57
|
-
Bignum :position
|
58
|
+
Bignum :position
|
58
59
|
|
59
60
|
Time :created_at, null: false
|
60
61
|
Time :updated_at, null: false
|
@@ -82,6 +83,24 @@ DB.lastval("position")
|
|
82
83
|
DB.setval("position", 1234)
|
83
84
|
```
|
84
85
|
|
86
|
+
## Usage with SQLite
|
87
|
+
|
88
|
+
In SQLite, the sequence functionality is implemented by registering tables in the database with a primary key of `id` and an additional integer field `fiction`.
|
89
|
+
```sql
|
90
|
+
CREATE TABLE `name_of_your_sequence_table`
|
91
|
+
(id integer primary key autoincrement, fiction integer);
|
92
|
+
```
|
93
|
+
|
94
|
+
You might utilize the last one 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.
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
DB.nextval_with_label("position", 1)
|
98
|
+
```
|
99
|
+
|
100
|
+
By default, `fiction` has a zero value.
|
101
|
+
|
102
|
+
Otherwise, the operation of this gem for SQLite is identical to the ways of using Sequence in more advanced databases.
|
103
|
+
|
85
104
|
## Maintainer
|
86
105
|
|
87
106
|
- [Nikolai Bocharov](https://github.com/oreol-group)
|
@@ -20,9 +20,10 @@ module Sequel
|
|
20
20
|
|
21
21
|
def create_sequence(name, options = {})
|
22
22
|
increment = options[:increment] || options[:step]
|
23
|
+
if_exists = build_exists_condition(options[:if_exists])
|
23
24
|
name = quote_name(name.to_s)
|
24
25
|
|
25
|
-
sql = ["CREATE SEQUENCE
|
26
|
+
sql = ["CREATE SEQUENCE #{if_exists} #{name}"]
|
26
27
|
sql << "INCREMENT BY #{increment}" if increment
|
27
28
|
sql << "START WITH #{options[:start]}" if options[:start]
|
28
29
|
sql << ';'
|
@@ -32,7 +33,7 @@ module Sequel
|
|
32
33
|
|
33
34
|
def drop_sequence(name)
|
34
35
|
name = quote_name(name.to_s)
|
35
|
-
sql = "DROP SEQUENCE #{name}"
|
36
|
+
sql = "DROP SEQUENCE IF EXISTS #{name}"
|
36
37
|
run(sql)
|
37
38
|
end
|
38
39
|
|
@@ -35,9 +35,10 @@ module Sequel
|
|
35
35
|
|
36
36
|
def create_sequence(name, options = {})
|
37
37
|
increment = options[:increment] || options[:step]
|
38
|
+
if_exists = build_exists_condition(options[:if_exists])
|
38
39
|
name = quote_name(name.to_s)
|
39
40
|
|
40
|
-
sql = ["CREATE SEQUENCE
|
41
|
+
sql = ["CREATE SEQUENCE #{if_exists} #{name}"]
|
41
42
|
sql << "INCREMENT BY #{increment}" if increment
|
42
43
|
sql << "START WITH #{options[:start]}" if options[:start]
|
43
44
|
sql << ';'
|
@@ -48,7 +49,7 @@ module Sequel
|
|
48
49
|
|
49
50
|
def drop_sequence(name)
|
50
51
|
name = quote_name(name.to_s)
|
51
|
-
sql = "DROP SEQUENCE #{name}"
|
52
|
+
sql = "DROP SEQUENCE IF EXISTS #{name}"
|
52
53
|
run(sql)
|
53
54
|
end
|
54
55
|
|
@@ -0,0 +1,132 @@
|
|
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 SQLite
|
9
|
+
def check_sequences
|
10
|
+
fetch('SELECT * FROM `sqlite_sequence`;').all.to_a
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_sequence(name, options = {})
|
14
|
+
check_options(options)
|
15
|
+
if_exists = build_exists_condition(options[:if_exists])
|
16
|
+
start_option = options[:start] || 1
|
17
|
+
sql = [create_sequence_table(stringify(name), if_exists)]
|
18
|
+
sql << insert_into_sqlite_sequence(stringify(name), start_option)
|
19
|
+
run(sql.join("\n"))
|
20
|
+
end
|
21
|
+
|
22
|
+
def drop_sequence(name, options = {})
|
23
|
+
if_exists = build_exists_condition(options[:if_exists])
|
24
|
+
run(drop_sequence_table(stringify(name), if_exists))
|
25
|
+
end
|
26
|
+
|
27
|
+
def nextval(name)
|
28
|
+
run(insert_into_sequence_table(stringify(name), 0))
|
29
|
+
take_seq(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def nextval_with_label(name, num_label = 0)
|
33
|
+
run(insert_into_sequence_table(stringify(name), num_label))
|
34
|
+
take_seq(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def lastval(name)
|
38
|
+
take_seq(stringify(name))
|
39
|
+
end
|
40
|
+
|
41
|
+
alias currval lastval
|
42
|
+
|
43
|
+
def setval(name, value)
|
44
|
+
current = lastval(stringify(name))
|
45
|
+
if current.nil?
|
46
|
+
create_sequence(stringify(name), { start: value })
|
47
|
+
elsif value < current
|
48
|
+
# sql = [delete_from_sqlite_sequence(name)]
|
49
|
+
# sql << drop_sequence_table(name)
|
50
|
+
# sql << insert_into_sqlite_sequence(name, value)
|
51
|
+
# run(sql.join("\n"))
|
52
|
+
log_info DANGER_OPT_ID
|
53
|
+
value = current
|
54
|
+
else
|
55
|
+
run(insert_into_sqlite_sequence(stringify(name), value))
|
56
|
+
end
|
57
|
+
value
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_column_default_nextval(table, column, sequence)
|
61
|
+
run(create_sequenced_column(stringify(table),
|
62
|
+
stringify(column),
|
63
|
+
stringify(sequence)))
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def stringify(name)
|
69
|
+
@name ||= {}
|
70
|
+
@name.fetch(name, nil) || (@name[name] = name.to_s)
|
71
|
+
end
|
72
|
+
|
73
|
+
def take_seq(name)
|
74
|
+
out = nil
|
75
|
+
fetch(select_max_seq(name)) do |row|
|
76
|
+
out = row[:id]
|
77
|
+
end
|
78
|
+
out
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_sequence_table(name, if_exists = nil)
|
82
|
+
%(
|
83
|
+
CREATE TABLE #{if_exists || IF_NOT_EXISTS} #{name}
|
84
|
+
(id integer primary key autoincrement, fiction integer);
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
def insert_into_sequence_table(name, num_label)
|
89
|
+
"INSERT INTO #{name} (fiction) VALUES (#{num_label});"
|
90
|
+
end
|
91
|
+
|
92
|
+
def insert_into_sqlite_sequence(name, value)
|
93
|
+
current = take_seq(name)
|
94
|
+
if current.nil?
|
95
|
+
"INSERT INTO sqlite_sequence (name, seq) VALUES ('#{name}', #{value});"
|
96
|
+
else
|
97
|
+
%(
|
98
|
+
UPDATE sqlite_sequence
|
99
|
+
SET seq = #{[current, value].max}
|
100
|
+
WHERE name = '#{name}';
|
101
|
+
)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def delete_from_sqlite_sequence(name)
|
106
|
+
"DELETE FROM sqlite_sequence WHERE name = '#{name}';"
|
107
|
+
end
|
108
|
+
|
109
|
+
def drop_sequence_table(name, if_exists = nil)
|
110
|
+
"DROP TABLE #{if_exists || IF_EXISTS} #{name};"
|
111
|
+
end
|
112
|
+
|
113
|
+
def select_max_seq(name)
|
114
|
+
"SELECT MAX(seq) AS id FROM sqlite_sequence WHERE name = '#{name}';"
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_sequenced_column(table, column, sequence)
|
118
|
+
%(
|
119
|
+
CREATE TRIGGER IF NOT EXISTS #{table}_#{sequence} AFTER INSERT
|
120
|
+
ON #{table}
|
121
|
+
BEGIN
|
122
|
+
INSERT INTO #{sequence}(fiction) VALUES (0);
|
123
|
+
UPDATE #{table}
|
124
|
+
SET #{column} = (SELECT MAX(seq) FROM sqlite_sequence WHERE name = '#{sequence}')
|
125
|
+
WHERE rowid = NEW.rowid;
|
126
|
+
END;
|
127
|
+
)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -3,6 +3,16 @@
|
|
3
3
|
module Sequel
|
4
4
|
module Sequence
|
5
5
|
module Database
|
6
|
+
DANGER_OPT_ID = "Warning! The new sequence ID can't be less than the current one."
|
7
|
+
DANGER_OPT_INCREMENT = 'Warning! Increments greater than 1 are not supported.'
|
8
|
+
IF_EXISTS = 'IF EXISTS'
|
9
|
+
IF_NOT_EXISTS = 'IF NOT EXISTS'
|
10
|
+
|
11
|
+
def check_options(params)
|
12
|
+
log_info DANGER_OPT_INCREMENT if params[:increment] && params[:increment] != 1
|
13
|
+
log_info DANGER_OPT_INCREMENT if params[:step] && params[:step] != 1
|
14
|
+
end
|
15
|
+
|
6
16
|
def custom_sequence?(_sequence_name)
|
7
17
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
8
18
|
end
|
@@ -15,7 +25,7 @@ module Sequel
|
|
15
25
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
16
26
|
end
|
17
27
|
|
18
|
-
def drop_sequence(_name)
|
28
|
+
def drop_sequence(_name, _options = {})
|
19
29
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
20
30
|
end
|
21
31
|
|
@@ -35,6 +45,10 @@ module Sequel
|
|
35
45
|
name.to_s.split('.', 2).map { |part| quote_sequence_name(part) }.join('.')
|
36
46
|
end
|
37
47
|
|
48
|
+
def nextval_with_label(_name, _num_label = 0)
|
49
|
+
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
50
|
+
end
|
51
|
+
|
38
52
|
def nextval(_name)
|
39
53
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
40
54
|
end
|
@@ -50,6 +64,15 @@ module Sequel
|
|
50
64
|
def setval(_name, _value)
|
51
65
|
raise Sequel::MethodNotAllowed, Sequel::MethodNotAllowed::METHOD_NOT_ALLOWED
|
52
66
|
end
|
67
|
+
|
68
|
+
def build_exists_condition(option)
|
69
|
+
case option
|
70
|
+
when true
|
71
|
+
IF_EXISTS
|
72
|
+
when false
|
73
|
+
IF_NOT_EXISTS
|
74
|
+
end
|
75
|
+
end
|
53
76
|
end
|
54
77
|
end
|
55
78
|
end
|
data/lib/sequel/sequence.rb
CHANGED
@@ -4,6 +4,7 @@ require 'sequel/database'
|
|
4
4
|
require 'sequel/adapters/postgres'
|
5
5
|
# require 'sequel/adapters/mysql'
|
6
6
|
require 'sequel/adapters/mysql2'
|
7
|
+
require 'sequel/adapters/sqlite'
|
7
8
|
require 'sequel/error'
|
8
9
|
|
9
10
|
module Sequel
|
@@ -14,6 +15,7 @@ module Sequel
|
|
14
15
|
require 'sequel/sequence/database/postgresql'
|
15
16
|
# require "sequel/sequence/database/mysql"
|
16
17
|
require 'sequel/sequence/database/mysql2'
|
18
|
+
require 'sequel/sequence/database/sqlite'
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
@@ -30,3 +32,6 @@ Sequel::Mysql2::Database.include(
|
|
30
32
|
# Sequel::Mysql::Database.include(
|
31
33
|
# Sequel::Sequence::Database::Mysql
|
32
34
|
# )
|
35
|
+
Sequel::SQLite::Database.include(
|
36
|
+
Sequel::Sequence::Database::SQLite
|
37
|
+
)
|
data/sequel-sequence.gemspec
CHANGED
@@ -37,9 +37,11 @@ Gem::Specification.new do |spec|
|
|
37
37
|
# JRuby Adapter Dependencies
|
38
38
|
spec.add_development_dependency 'jdbc-mysql', '~> 8.0.17'
|
39
39
|
spec.add_development_dependency 'jdbc-postgres', '~> 42.2.14'
|
40
|
+
spec.add_development_dependency 'jdbc-sqlite3', '~> 3.42'
|
40
41
|
else
|
41
42
|
# MRI/Rubinius Adapter Dependencies
|
42
43
|
spec.add_development_dependency 'mysql2', '~> 0.5.3'
|
43
44
|
spec.add_development_dependency 'pg', '~> 1.5.4'
|
45
|
+
spec.add_development_dependency 'sqlite3', '~> 1.6.0'
|
44
46
|
end
|
45
47
|
end
|
@@ -72,7 +72,7 @@ class MysqlSequenceTest < Minitest::Test
|
|
72
72
|
assert_equal 3, MysqlDB.nextval(:position)
|
73
73
|
end
|
74
74
|
|
75
|
-
test
|
75
|
+
test "returns current/last sequence value, which doesn't increase by itself" do
|
76
76
|
with_migration do
|
77
77
|
def up
|
78
78
|
create_sequence :position
|
@@ -126,7 +126,7 @@ class MysqlSequenceTest < Minitest::Test
|
|
126
126
|
end.down
|
127
127
|
|
128
128
|
sequence = MysqlDB.check_sequences.find do |seq|
|
129
|
-
seq[:
|
129
|
+
seq[:Tables_in_test] == 'position'
|
130
130
|
end
|
131
131
|
|
132
132
|
assert_nil sequence
|
@@ -157,7 +157,7 @@ class MysqlSequenceTest < Minitest::Test
|
|
157
157
|
with_migration do
|
158
158
|
def up
|
159
159
|
drop_table :builders, if_exists: true
|
160
|
-
create_sequence :position_id, if_exists: false
|
160
|
+
create_sequence :position_id, if_exists: false, start: 1
|
161
161
|
create_table :builders do
|
162
162
|
primary_key :id
|
163
163
|
String :name, text: true
|
@@ -72,7 +72,7 @@ class PostgresqlSequenceTest < Minitest::Test
|
|
72
72
|
assert_equal 3, PostgresqlDB.nextval(:position)
|
73
73
|
end
|
74
74
|
|
75
|
-
test
|
75
|
+
test "returns current/last sequence value, which doesn't increase by itself" do
|
76
76
|
with_migration do
|
77
77
|
def up
|
78
78
|
create_sequence :position, start: 2, increment: 2
|
@@ -164,7 +164,7 @@ class PostgresqlSequenceTest < Minitest::Test
|
|
164
164
|
with_migration do
|
165
165
|
def up
|
166
166
|
drop_table :masters, if_exists: true
|
167
|
-
create_sequence :position_id, if_exists: false
|
167
|
+
create_sequence :position_id, if_exists: false, start: 1
|
168
168
|
create_table :masters, if_not_exists: true do
|
169
169
|
primary_key :id
|
170
170
|
String :name, text: true
|
@@ -0,0 +1,257 @@
|
|
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} - 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
|
+
SQLiteDB.nextval(:position)
|
130
|
+
assert_equal 102, SQLiteDB.lastval(:position)
|
131
|
+
end
|
132
|
+
|
133
|
+
test 'sets a new sequence value with a label' do
|
134
|
+
with_migration do
|
135
|
+
def up
|
136
|
+
create_sequence :position
|
137
|
+
end
|
138
|
+
end.up
|
139
|
+
|
140
|
+
SQLiteDB.nextval(:position)
|
141
|
+
SQLiteDB.nextval_with_label(:position, 1)
|
142
|
+
SQLiteDB.nextval_with_label(:position, 1)
|
143
|
+
fiction_set_size = SQLiteDB.fetch('SELECT * FROM position where fiction = 1;').all.size
|
144
|
+
assert_equal 2, fiction_set_size
|
145
|
+
|
146
|
+
fiction_set_size = SQLiteDB.fetch('SELECT * FROM position where fiction = 0;').all.size
|
147
|
+
assert_equal 1, 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 'dropsthe 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 'creates table that references sequence' do
|
224
|
+
with_migration do
|
225
|
+
def up
|
226
|
+
drop_table :apprentices, if_exists: true
|
227
|
+
create_sequence :position_id, if_exists: false, start: 1
|
228
|
+
create_table :apprentices do
|
229
|
+
primary_key :id
|
230
|
+
String :name, text: true
|
231
|
+
Bignum :position
|
232
|
+
end
|
233
|
+
set_column_default_nextval :apprentices, :position, :position_id
|
234
|
+
end
|
235
|
+
end.up
|
236
|
+
|
237
|
+
class Apprentice < Sequel::Model; end
|
238
|
+
|
239
|
+
apprentice1 = Apprentice.create(name: 'Apprentice 1')
|
240
|
+
pos1 = SQLiteDB.lastval(:position_id) - 1
|
241
|
+
assert_equal pos1, apprentice1.reload.position
|
242
|
+
|
243
|
+
apprentice2 = Apprentice.create(name: 'Apprentice 2')
|
244
|
+
pos2 = SQLiteDB.currval(:position_id) - 1
|
245
|
+
assert_equal pos2, apprentice2.reload.position
|
246
|
+
|
247
|
+
assert_equal pos2 - pos1, 1
|
248
|
+
|
249
|
+
SQLiteDB.nextval(:position_id)
|
250
|
+
|
251
|
+
apprentice4 = Apprentice.create(name: 'Apprentice 4')
|
252
|
+
pos4 = SQLiteDB.currval(:position_id) - 1
|
253
|
+
assert_equal pos4, apprentice4.reload.position
|
254
|
+
|
255
|
+
assert_equal pos4 - pos2, 2
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,29 @@
|
|
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.run 'DROP TABLE IF EXISTS objects'
|
15
|
+
SQLiteDB.drop_sequence 'a'
|
16
|
+
SQLiteDB.drop_sequence 'b'
|
17
|
+
SQLiteDB.drop_sequence 'c'
|
18
|
+
sql = 'CREATE TABLE objects (id INTEGER PRIMARY KEY AUTOINCREMENT, quantity INTEGER DEFAULT(0), slug VARCHAR(255));'
|
19
|
+
SQLiteDB.run sql
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_migration(&block)
|
23
|
+
migration_class = Sequel::Migration
|
24
|
+
|
25
|
+
Sequel::Model.db = SQLiteDB
|
26
|
+
|
27
|
+
Class.new(migration_class, &block).new(SQLiteDB)
|
28
|
+
end
|
29
|
+
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.
|
4
|
+
version: 0.3.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-
|
11
|
+
date: 2023-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -142,6 +142,20 @@ 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
161
|
in Postgresql and Mysql databases within the Sequel ORM.
|
@@ -174,12 +188,15 @@ files:
|
|
174
188
|
- lib/sequel/sequence/database/mysql.rb
|
175
189
|
- lib/sequel/sequence/database/mysql2.rb
|
176
190
|
- lib/sequel/sequence/database/postgresql.rb
|
191
|
+
- lib/sequel/sequence/database/sqlite.rb
|
177
192
|
- lib/sequel/sequence/version.rb
|
178
193
|
- sequel-sequence.gemspec
|
179
194
|
- test/mysql_test_helper.rb
|
180
195
|
- test/postgresql_test_helper.rb
|
181
196
|
- test/sequel/mysql_sequence_test.rb
|
182
197
|
- test/sequel/postgresql_sequence_test.rb
|
198
|
+
- test/sequel/sqlite_sequence_test.rb
|
199
|
+
- test/sqlite_test_helper.rb
|
183
200
|
- test/test_helper.rb
|
184
201
|
homepage: https://rubygems.org/gems/sequel-sequence
|
185
202
|
licenses:
|