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 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: