sequel-sequence 0.4.0 → 0.4.2

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: ba4270613514ab8a88b24fa9034314333feba102dff7719a8e238ca1c84e67d1
4
- data.tar.gz: 950c6494e0c9f55f6465beee78209649c784508c9c9c0dab1b9817576cbf3a7c
3
+ metadata.gz: a027c577de1ee27127880328c29208456a26635c9ea18b1c5eb3c1cb0dbbd5fc
4
+ data.tar.gz: 71764d6ec16bf3425ba3d3bfb4ac47c04dd2a6f7001342c0ae35ebec63af293d
5
5
  SHA512:
6
- metadata.gz: ed1505fd942d5247ea8ad64b47e1caa9cc420826ace83e4f8c075db257090576772219aa9f48007a0c9d84793f127ec82604a310688717b18ece0ceec8824d66
7
- data.tar.gz: c781c917e87029eec161ae656bb331552e6e0f531ceb8c6f3df8b836686f9f1bc7a4f277f81c15a9c515f2861624ed73f978a7be7b7db35d29a32c09aef277f5
6
+ metadata.gz: 5ce8091d3c644545cecff05c0f85a6252bdd8de015710770a861bfea81793fc50c5b96d19ce304fc2158cd40fc8bfde72f88309e0dc6dea468e2a977a533f980
7
+ data.tar.gz: a80404a67e51b77a1dd6ac40fe8ebbd93329b170e25855024f325e965f76ec9ad723ea2698fc4f699edad9cd7eb8555c5f6b28d870eb6c2f0355c44686904b19
data/.ci.gemfile ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'bundler', '>= 2.2.4'
6
+ gem 'minitest-utils', '~> 0.4.6'
7
+ gem 'pry-byebug', '~> 3.10.1'
8
+ gem 'rake', '~> 13.0.2'
9
+ gem 'rubocop', '~> 1.56.3'
10
+ gem 'sequel', '>= 5.28', '<6.0'
11
+ gem 'simplecov', '~> 0.22.0'
12
+
13
+ # MRI/Rubinius Adapter Dependencies
14
+ platform :ruby do
15
+ gem 'mysql2', '~> 0.5.3'
16
+ gem 'pg', '~> 1.5.4'
17
+ gem 'sqlite3', '~> 1.6.0'
18
+ end
19
+
20
+ # JRuby Adapter Dependencies
21
+ platform :jruby do
22
+ gem 'jdbc-mysql', '~> 8.0.17'
23
+ gem 'jdbc-postgres', '~> 42.2.14'
24
+ gem 'jdbc-sqlite3', '~> 3.42'
25
+ end
@@ -16,7 +16,6 @@ jobs:
16
16
  os: ['ubuntu-latest']
17
17
  sequel: ['~>5.28']
18
18
  ruby: ['3.2', '3.1', '3.0', '2.7']
19
- gemfile: ['Gemfile']
20
19
  runs-on: ${{ matrix.os }}
21
20
  name: Tests with Ruby ${{ matrix.ruby }}
22
21
 
@@ -58,7 +57,7 @@ jobs:
58
57
 
59
58
  env:
60
59
  SEQUEL: ${{ matrix.sequel }}
61
- BUNDLE_GEMFILE: ${{ matrix.gemfile }}
60
+ BUNDLE_GEMFILE: .ci.gemfile
62
61
  steps:
63
62
  - uses: actions/checkout@v4
64
63
 
@@ -126,5 +125,8 @@ jobs:
126
125
  env:
127
126
  TEST_SQLITE_DATABASE: "db/test.sqlite3"
128
127
 
128
+ - name: Run Mock Tests
129
+ run: bundle exec rake TEST=test/sequel/mock_sequence_test.rb
130
+
129
131
  - name: Run Rubocop
130
132
  run: bundle exec rake rubocop
data/CHANGELOG.md CHANGED
@@ -11,6 +11,24 @@ Prefix your message with one of the following:
11
11
  - [Security] in case of vulnerabilities.
12
12
  -->
13
13
 
14
+ ## v0.4.2 - 2023-10-03
15
+
16
+ - [Added] Additions into README.md.
17
+ - [Added] Exclusion of dependence on the Postgresql constraint for "PG::The object is not in the required state P: ERROR: currval of sequence "name_of_sequence" is not yet defined in this session".
18
+ - [Added] `custom_sequence?` method for MariaDB and SQLite.
19
+ - [Fixed] Dependencies on gems by moving them from .gemspec to Gemfile
20
+ - [Fixed] `currval` for initial state of sequence in Postgresql
21
+ - [Fixed] `lastval` for initial state of sequence in MariaDB
22
+ - [Changed] The default action `setval` for MariaDB to invoke `setval` if necessary
23
+ - [Changed] The class initialization algorithm in `sequence.rb` depending on the gems included in the user project.
24
+
25
+ ## v0.4.1 - 2023-09-28
26
+
27
+ - [Added] Important notice to README.md.
28
+ - [Added] MySQL tests cover 100%.
29
+ - [Added] SQLite tests cover 100%.
30
+ - [Added] Mock connection to check for additional ORM exceptions.
31
+
14
32
  ## v0.4.0 - 2023-09-26
15
33
 
16
34
  - [Fixed] Differences between MySQL and MariaDB.
data/CONTRIBUTING.md CHANGED
@@ -33,13 +33,14 @@ your contribution is according to how this project works.
33
33
 
34
34
  1. [Fork](https://help.github.com/forking/) sequel-sequence
35
35
  2. Create a topic branch - `git checkout -b my_branch`
36
- 3. Make your changes using [descriptive commit messages](#commit-messages)
37
- 4. Update CHANGELOG.md describing your changes by adding an entry to the
36
+ 3. Unlock gem dependencies in `sequel-sequence.gemspec`
37
+ 4. Make your changes using [descriptive commit messages](#commit-messages)
38
+ 5. Update CHANGELOG.md describing your changes by adding an entry to the
38
39
  "Unreleased" section. If this section is not available, create one right
39
40
  before the last version.
40
- 5. Push to your branch - `git push origin my_branch`
41
- 6. [Create a pull request](https://docs.github.com/articles/creating-a-pull-request)
42
- 7. That's it!
41
+ 6. Push to your branch - `git push origin my_branch`
42
+ 7. [Create a pull request](https://docs.github.com/articles/creating-a-pull-request)
43
+ 8. That's it!
43
44
 
44
45
  ## Styleguides
45
46
 
@@ -235,4 +236,14 @@ $ bundle exec rake TEST=test/sequel/postgresql_sequence_test.rb
235
236
  $ bundle exec rake TEST=test/sequel/mariadb_sequence_test.rb
236
237
  $ bundle exec rake TEST=test/sequel/mysql_sequence_test.rb
237
238
  $ bundle exec rake TEST=test/sequel/sqlite_sequence_test.rb
239
+ $ bundle exec rake TEST=test/sequel/mock_sequence_test.rb
240
+ ```
241
+
242
+ Short command:
243
+ ```bash
244
+ $ bundle exec rake postgresql
245
+ $ bundle exec rake mariadb
246
+ $ bundle exec rake mysql
247
+ $ bundle exec rake sqlite
248
+ $ bundle exec rake mock
238
249
  ```
data/README.md CHANGED
@@ -16,7 +16,7 @@ gem install sequel-sequence
16
16
  Or add the following line to your project's Gemfile:
17
17
 
18
18
  ```ruby
19
- gem "sequel-sequence"
19
+ gem 'sequel-sequence'
20
20
  ```
21
21
 
22
22
  ## Usage with PostgreSQL and MariaDB
@@ -24,6 +24,8 @@ gem "sequel-sequence"
24
24
  To create and delete a `SEQUENCE`, simply use the `create_sequence` and `drop_sequence` methods.
25
25
 
26
26
  ```ruby
27
+ require: 'sequel-sequence'
28
+
27
29
  Sequel.migration do
28
30
  up do
29
31
  create_sequence :position, if_exists: false
@@ -37,6 +39,8 @@ end
37
39
 
38
40
  It would also be correct to write:
39
41
  ```ruby
42
+ require: 'sequel-sequence'
43
+
40
44
  Sequel.migration do
41
45
  up do
42
46
  create_sequence :position
@@ -48,7 +52,7 @@ Sequel.migration do
48
52
  end
49
53
  ```
50
54
 
51
- You can also specify the initial value and increment:
55
+ You can also specify the following optional parameters: `if_exists` – a condition of acceptability; `start` – an initial value; `increment` or `step` – step size to the next auto incrementing value:
52
56
 
53
57
  ```ruby
54
58
  create_sequence :position, increment: 2
@@ -95,7 +99,7 @@ DB.currval("position")
95
99
  DB.lastval("position")
96
100
  # Both options are acceptable in PostgreSQL and MySQL.
97
101
 
98
- # Set sequence's current value. It must be greater than lastval or currval.
102
+ # Set a new sequence value. It must be greater than lastval or currval. Only PostgreSQL allows setting a lower value.
99
103
  DB.setval("position", 1234)
100
104
  ```
101
105
 
@@ -107,7 +111,7 @@ CREATE TABLE `name_of_your_sequence_table`
107
111
  (id integer primary key autoincrement, fiction integer);
108
112
  ```
109
113
 
110
- You might utilize the last field 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.
114
+ You might utilize the last field `fiction` 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.
111
115
  ```ruby
112
116
  create_sequence :position, if_exists: false, start: 1000, numeric_label: 1
113
117
  ```
@@ -120,6 +124,17 @@ By default, `fiction` has a zero value.
120
124
 
121
125
  Otherwise, the operation of this gem for SQLite and MySQL is similar to the ways of using Sequence in more advanced RDBMS. There is only one difference here, you won't be able to change the increment value from 1 to another using the `increment` or `step` parameter.
122
126
 
127
+ ## Known issues you may encounter
128
+
129
+ - This solution does not allow you to simultaneously work with MySQL and MariaDB databases from one application. If such a need arises, move the data processing functionality to different microservices.
130
+ - When you start with a new database in SQLite, you'll receive an error message - "`SQLite3::SQLException: no such table: sqlite_sequence`". `sqlite_sequence` table is not created, until you define at least one autoincrement and primary key column in your schema.
131
+
132
+ ## Additional handy functions
133
+
134
+ To discover a database information about `SEQUENCE`s you could take advantage of `check_sequences` and `custom_sequence?` methods.
135
+ - `custom_sequence?(:sequence_name)` allows you to instantly find out the availability of the called `SEQUENCE`.
136
+ - `check_sequences` provides complete information about known `SEQUENCE`s in the datebase. The output data depends on RDBMS.
137
+
123
138
  ## Maintainer
124
139
 
125
140
  - [Nikolai Bocharov](https://github.com/oreol-group)
data/Rakefile CHANGED
@@ -9,7 +9,8 @@ Rake::TestTask.new(:test) do |t|
9
9
  t.libs << 'lib'
10
10
  t.test_files = FileList['test/sequel/postgresql_sequence_test.rb',
11
11
  'test/sequel/mariadb_sequence_test.rb',
12
- 'test/sequel/sqlite_sequence_test.rb']
12
+ 'test/sequel/sqlite_sequence_test.rb',
13
+ 'test/sequel/mock_sequence_test.rb']
13
14
  end
14
15
 
15
16
  Rake::TestTask.new(:mysql) do |t|
@@ -18,6 +19,30 @@ Rake::TestTask.new(:mysql) do |t|
18
19
  t.test_files = FileList['test/sequel/mysql_sequence_test.rb']
19
20
  end
20
21
 
22
+ Rake::TestTask.new(:postgresql) do |t|
23
+ t.libs << 'test'
24
+ t.libs << 'lib'
25
+ t.test_files = FileList['test/sequel/postgresql_sequence_test.rb']
26
+ end
27
+
28
+ Rake::TestTask.new(:mariadb) do |t|
29
+ t.libs << 'test'
30
+ t.libs << 'lib'
31
+ t.test_files = FileList['test/sequel/mariadb_sequence_test.rb']
32
+ end
33
+
34
+ Rake::TestTask.new(:sqlite) do |t|
35
+ t.libs << 'test'
36
+ t.libs << 'lib'
37
+ t.test_files = FileList['test/sequel/sqlite_sequence_test.rb']
38
+ end
39
+
40
+ Rake::TestTask.new(:mock) do |t|
41
+ t.libs << 'test'
42
+ t.libs << 'lib'
43
+ t.test_files = FileList['test/sequel/mock_sequence_test.rb']
44
+ end
45
+
21
46
  RuboCop::RakeTask.new
22
47
 
23
48
  task default: %i[test rubocop]
data/lib/sequel/error.rb CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sequel
4
- class MethodNotAllowed < StandardError
5
- METHOD_NOT_ALLOWED = 'Method not allowed'
4
+ (
5
+ # Error raised when attempting to utilize an invalid adapter to SEQUENCE interface.
6
+ MethodNotAllowed = Class.new(Error)
7
+ ).name
6
8
 
7
- # Initialize a new Error object
8
- def initialize(message = '')
9
- super(message)
10
- end
9
+ class Database
10
+ METHOD_NOT_ALLOWED = 'Method not allowed'
11
11
  end
12
12
  end
@@ -65,12 +65,21 @@ module Sequel
65
65
 
66
66
  # for Postgres
67
67
  def currval(name)
68
- name = quote(name.to_s)
68
+ quoted_name = quote(name.to_s)
69
69
  out = nil
70
- fetch("SELECT currval(#{name})") do |row|
70
+ fetch("SELECT currval(#{quoted_name})") do |row|
71
71
  out = row[:currval]
72
72
  end
73
73
  out
74
+ rescue Sequel::DatabaseError => e
75
+ # We exclude dependence on the postgresql constraint.
76
+ if e.message =~ /\APG::ObjectNotInPrerequisiteState:(.)*is not yet defined in this session\n\z/
77
+ return nextval(name)
78
+ end
79
+
80
+ # :nocov:
81
+ raise e
82
+ # :nocov:
74
83
  end
75
84
 
76
85
  # for MariaDB
@@ -86,11 +95,12 @@ module Sequel
86
95
  end
87
96
 
88
97
  def set_column_default_nextval(table, column, sequence)
89
- table = table.to_s
90
- column = column.to_s
91
- sequence = quote(sequence.to_s)
92
- run "ALTER TABLE IF EXISTS #{table} " \
93
- "ALTER COLUMN #{column} SET DEFAULT nextval(#{sequence}::regclass)"
98
+ sql = %(
99
+ ALTER TABLE IF EXISTS #{table}
100
+ ALTER COLUMN #{quote_name(column.to_s)}
101
+ SET DEFAULT nextval(#{quote(sequence.to_s)}::regclass)
102
+ ).strip
103
+ run sql
94
104
  end
95
105
  end
96
106
  end
@@ -1,71 +1,104 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Mariadb
4
- def quote_column_name(name)
5
- "`#{name.gsub('`', '``')}`"
6
- end
3
+ module Sequel
4
+ module Sequence
5
+ module Database
6
+ module Server
7
+ module Mariadb
8
+ def quote_column_name(name)
9
+ "`#{name.gsub('`', '``')}`"
10
+ end
7
11
 
8
- def quote_sequence_name(name)
9
- "`#{name.gsub(/[`"']/, '')}`"
10
- end
12
+ def quote_sequence_name(name)
13
+ "`#{name.gsub(/[`"']/, '')}`"
14
+ end
11
15
 
12
- def check_sequences
13
- fetch("SHOW FULL TABLES WHERE Table_type = 'SEQUENCE';").all.to_a
14
- end
16
+ def custom_sequence?(sequence_name)
17
+ db = name_of_current_database
18
+ return false if db.empty?
15
19
 
16
- def create_sequence(name, options = {})
17
- increment = options[:increment] || options[:step]
18
- if_exists = build_exists_condition(options[:if_exists])
19
- name = quote_name(name.to_s)
20
+ sql = "SHOW FULL TABLES WHERE Table_type = 'SEQUENCE' and Tables_in_#{db} = '#{sequence_name}';"
21
+ fetch(sql).all.size.positive?
22
+ end
20
23
 
21
- sql = ["CREATE SEQUENCE #{if_exists || Sequel::Database::IF_NOT_EXISTS} #{name}"]
22
- sql << "INCREMENT BY #{increment}" if increment
23
- sql << "START WITH #{options[:start]}" if options[:start]
24
- sql << ';'
24
+ def check_sequences
25
+ fetch("SHOW FULL TABLES WHERE Table_type = 'SEQUENCE';").all.to_a
26
+ end
25
27
 
26
- run(sql.join("\n"))
27
- end
28
+ def create_sequence(name, options = {})
29
+ increment = options[:increment] || options[:step]
30
+ if_exists = build_exists_condition(options[:if_exists])
31
+ name = quote_name(name.to_s)
28
32
 
29
- def drop_sequence(name)
30
- name = quote_name(name.to_s)
31
- sql = "DROP SEQUENCE IF EXISTS #{name}"
32
- run(sql)
33
- end
33
+ sql = ["CREATE SEQUENCE #{if_exists || Sequel::Database::IF_NOT_EXISTS} #{name}"]
34
+ sql << "INCREMENT BY #{increment}" if increment
35
+ sql << "START WITH #{options[:start]}" if options[:start]
36
+ sql << ';'
34
37
 
35
- def nextval(name)
36
- name = quote(name.to_s)
37
- out = nil
38
- fetch("SELECT nextval(#{name});") do |row|
39
- out = row["nextval(#{name})".to_sym]
40
- end
41
- out
42
- end
38
+ run(sql.join("\n"))
39
+ end
43
40
 
44
- def lastval(name)
45
- name = quote(name.to_s)
46
- out = nil
47
- fetch("SELECT lastval(#{name});") do |row|
48
- out = row["lastval(#{name})".to_sym]
49
- end
50
- out
51
- end
41
+ def drop_sequence(name)
42
+ name = quote_name(name.to_s)
43
+ sql = "DROP SEQUENCE IF EXISTS #{name}"
44
+ run(sql)
45
+ end
52
46
 
53
- alias currval lastval
47
+ def nextval(name)
48
+ name = quote(name.to_s)
49
+ out = nil
50
+ fetch("SELECT nextval(#{name});") do |row|
51
+ out = row["nextval(#{name})".to_sym]
52
+ end
53
+ out
54
+ end
54
55
 
55
- def setval(name, value)
56
- name = quote(name.to_s)
57
- out = nil
58
- fetch("SELECT setval(#{name}, #{value});") do |row|
59
- out = row["setval(#{name}, #{value})".to_sym]
60
- end
61
- out
62
- end
56
+ def lastval(name)
57
+ quoted_name = quote(name.to_s)
58
+ out = nil
59
+ fetch("SELECT lastval(#{quoted_name});") do |row|
60
+ out = row["lastval(#{quoted_name})".to_sym]
61
+ end
62
+ return nextval(name) if out.nil?
63
+
64
+ out
65
+ end
66
+
67
+ alias currval lastval
63
68
 
64
- def set_column_default_nextval(table, column, sequence)
65
- table = table.to_s
66
- column = column.to_s
67
- sequence = quote(sequence.to_s)
68
- run "ALTER TABLE IF EXISTS #{table} " \
69
- "ALTER COLUMN #{column} SET DEFAULT nextval(#{sequence});"
69
+ def setval(name, value)
70
+ current = lastval(name)
71
+ if value <= current
72
+ log_info Sequel::Database::DANGER_OPT_ID if value < current
73
+ value = current
74
+ else
75
+ quoted_name = quote(name.to_s)
76
+ value -= 1
77
+ out = nil
78
+ fetch("SELECT setval(#{quoted_name}, #{value});") do |row|
79
+ out = row["setval(#{quoted_name}, #{value})".to_sym]
80
+ end
81
+ value = nextval(name)
82
+ end
83
+ value
84
+ end
85
+
86
+ def set_column_default_nextval(table, column, sequence)
87
+ sql = %(
88
+ ALTER TABLE IF EXISTS #{quote(table.to_s)}
89
+ ALTER COLUMN #{quote_name(column.to_s)}
90
+ SET DEFAULT nextval(#{quote(sequence.to_s)})
91
+ ).strip
92
+ run sql
93
+ end
94
+
95
+ private
96
+
97
+ def name_of_current_database
98
+ fetch('SELECT DATABASE() AS db;').first[:db]
99
+ end
100
+ end
101
+ end
102
+ end
70
103
  end
71
104
  end