sequel-sequence 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![CI](https://github.com/oreol-group/sequel-sequence/actions/workflows/ci.yml/badge.svg)](https://github.com/oreol-group/sequel-sequence)
|
4
4
|
[![Gem](https://img.shields.io/gem/v/sequel-sequence.svg)](https://rubygems.org/gems/sequel-sequence)
|
5
5
|
[![Downloads total](https://img.shields.io/gem/dt/sequel-sequence.svg)](https://rubygems.org/profiles/it_architect)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/Oreol-Group/sequel-sequence.svg)](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:
|