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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39e70601cb32fc0e4240423134984c665c0691ebb68aa2b1038b43ea0e978176
4
- data.tar.gz: ad285adcee5907a0d40d3ecd7d4e2bb67d3711876c75687276a58f71304cf48a
3
+ metadata.gz: c7012e03aa326861bef294edcf042850f662f9122664da409aa0dd764d9375d9
4
+ data.tar.gz: b309b36a931be17ee7cb628c21083ef8543bb60139a249aa9fd1d42378321297
5
5
  SHA512:
6
- metadata.gz: 0b97dc0b9a8b1c531d3863de2c52fde8ae2f0013aca027035fef391e2977db84520e6a00b059118a7c62ce77c57f7333abbfab56dad13d0b425d2ff4f923c02f
7
- data.tar.gz: e35322803655e71d7118c3ec3e63e554ffaa73e0669e3d0947ad386d277d8b465c66b677ee9aa9bc14843062fef0331865682df769e2b2aa3fa136bca8e7029c
6
+ metadata.gz: 7c13a9a6e000990aaee2bdcca4d3d7519a7164c3217d4164f35e40e43deb76f652215169396647568cb03cf111d2a103f2f0f5d5f45e174b8107588e4be1808f
7
+ data.tar.gz: e9483ab69ea26d780164a4e4683d75c2bd86d8c5d92983b506645c5544a3ebc277f25f12a463b1f959f675f0e780eaf3b22a82b9560e247f16f2a895518d0e53
@@ -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
@@ -8,7 +8,10 @@ doc
8
8
  pkg
9
9
  tmp
10
10
  log
11
+ db
11
12
 
12
13
  ## PROJECT::SPECIFIC
13
14
  .bundle
15
+ .byebug_history
14
16
  Gemfile.lock
17
+ *.gem
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, null: false
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 IF NOT EXISTS #{name}"]
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 IF NOT EXISTS #{name}"]
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sequel
4
4
  module Sequence
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
@@ -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
+ )
@@ -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 'returns current/last sequence value without incrementing it' do
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[:sequence_name] == 'position'
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 'returns current (or last as alias) sequence value without incrementing it' do
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.2.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-14 00:00:00.000000000 Z
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: