sequel-sequence 0.1.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: 10902f0e1d1afb59a3461ea44138203c9ddf3f0455b49ffe811c7b23aadc8ede
4
- data.tar.gz: 6e928d7c8827d2cc67c32d4fe28156490b99b187cbf6cbc19f546c2706e55087
3
+ metadata.gz: c7012e03aa326861bef294edcf042850f662f9122664da409aa0dd764d9375d9
4
+ data.tar.gz: b309b36a931be17ee7cb628c21083ef8543bb60139a249aa9fd1d42378321297
5
5
  SHA512:
6
- metadata.gz: 545bb293f276fd0f92441941fa9efc7dc432fd1b1a5131bb10a7465aba833db72f2ca2e29abc3f6cc427b958df3bc47354abf1d9d420efa77d1d610de85e2166
7
- data.tar.gz: 20273fe64a4e90fd2f8345ea8b08d96819bb4c52ff26684b2e67d49674c0360fc0926a66c565041b6a16f8e49d348133cca80cc629c4c14614a1116eb3e6dc60
6
+ metadata.gz: 7c13a9a6e000990aaee2bdcca4d3d7519a7164c3217d4164f35e40e43deb76f652215169396647568cb03cf111d2a103f2f0f5d5f45e174b8107588e4be1808f
7
+ data.tar.gz: e9483ab69ea26d780164a4e4683d75c2bd86d8c5d92983b506645c5544a3ebc277f25f12a463b1f959f675f0e780eaf3b22a82b9560e247f16f2a895518d0e53
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: "🐛 Bug Report"
3
+ about: Report a reproducible bug or regression.
4
+ title: 'Bug: '
5
+ labels: 'Status: Unconfirmed'
6
+
7
+ ---
8
+
9
+ <!--
10
+ - Please provide a clear and concise description of what the bug is.
11
+ - If possible, add an example reproducing your issue.
12
+ - Please test using the latest version of ar-sequence
13
+ to make sure your issue has not already been fixed.
14
+ -->
15
+
16
+ ## Description
17
+
18
+ [Add bug description here]
19
+
20
+ ## How to reproduce
21
+
22
+ [Add steps on how to reproduce this issue]
23
+
24
+ ## What do you expect
25
+
26
+ [Describe what do you expect to happen]
27
+
28
+ ## What happened instead
29
+
30
+ [Describe the actual results]
31
+
32
+ ## Software:
33
+
34
+ - Gem version: [Add gem version here]
35
+ - Ruby version: [Add version here]
36
+
37
+ ## Full backtrace
38
+
39
+ ```text
40
+ [Paste full backtrace here]
41
+ ```
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: "💡 Feature request"
3
+ about: Have an idea that may be useful? Make a suggestion!
4
+ title: 'Feature Request: '
5
+ labels: 'Feature request'
6
+
7
+ ---
8
+
9
+ ## Description
10
+
11
+ _A clear and concise description of what the problem is._
12
+
13
+ ## Describe the solution
14
+
15
+ _A clear and concise description of what you want to happen._
16
+
17
+ ## Alternatives you considered
18
+
19
+ _A clear and concise description of any alternative solutions or features you've considered._
20
+
21
+ ## Additional context
22
+
23
+ _Add any other context, screenshots, links, etc about the feature request here._
@@ -0,0 +1,38 @@
1
+ <!--
2
+ If you're making a doc PR or something tiny where the below is irrelevant,
3
+ delete this template and use a short description, but in your description aim to
4
+ include both what the change is, and why it is being made, with enough context
5
+ for anyone to understand.
6
+ -->
7
+
8
+ <details>
9
+ <summary>PR Checklist</summary>
10
+
11
+ ### PR Structure
12
+
13
+ - [ ] This PR has reasonably narrow scope (if not, break it down into smaller
14
+ PRs).
15
+ - [ ] This PR avoids mixing refactoring changes with feature changes (split into
16
+ two PRs otherwise).
17
+ - [ ] This PR's title starts is concise and descriptive.
18
+
19
+ ### Thoroughness
20
+
21
+ - [ ] This PR adds tests for the most critical parts of the new functionality or
22
+ fixes.
23
+ - [ ] I've updated any docs, `.md` files, etc… affected by this change.
24
+
25
+ </details>
26
+
27
+ ### What
28
+
29
+ [TODO: Short statement about what is changing.]
30
+
31
+ ### Why
32
+
33
+ [TODO: Why this change is being made. Include any context required to understand
34
+ the why.]
35
+
36
+ ### Known limitations
37
+
38
+ [TODO or N/A]
@@ -0,0 +1,14 @@
1
+ # Documentation:
2
+ # https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates
3
+
4
+ version: 2
5
+ updates:
6
+ - package-ecosystem: "github-actions"
7
+ directory: "/"
8
+ schedule:
9
+ interval: "monthly"
10
+
11
+ - package-ecosystem: "bundler"
12
+ directory: "/"
13
+ schedule:
14
+ interval: "monthly"
@@ -0,0 +1,97 @@
1
+ name: CI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs: {}
6
+ push:
7
+ branches: [ master ]
8
+ pull_request:
9
+ branches: ['**']
10
+
11
+ jobs:
12
+ tests:
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ os: ['ubuntu-latest']
17
+ sequel: ['~>5.28']
18
+ ruby: ['3.2', '3.1', '3.0', '2.7']
19
+ gemfile: ['Gemfile']
20
+ runs-on: ${{ matrix.os }}
21
+ name: Tests with Ruby ${{ matrix.ruby }}
22
+
23
+ services:
24
+ postgres:
25
+ image: postgres:13
26
+ env:
27
+ POSTGRES_USER: postgres
28
+ POSTGRES_PASSWORD: postgres
29
+ ports:
30
+ - 5432:5432
31
+ options: >-
32
+ --health-cmd pg_isready
33
+ --health-interval 10s
34
+ --health-timeout 5s
35
+ --health-retries 5
36
+ mysql:
37
+ image: mariadb:11.1
38
+ env:
39
+ MARIADB_ROOT_PASSWORD: root
40
+ ports:
41
+ - 3306:3306
42
+ options: >-
43
+ --health-cmd="healthcheck.sh --connect --innodb_initialized"
44
+ --health-interval 10s
45
+ --health-timeout 5s
46
+ --health-retries 3
47
+
48
+ env:
49
+ SEQUEL: ${{ matrix.sequel }}
50
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+
54
+ - name: Install db dependencies and check connections
55
+ run: |
56
+ DEBIAN_FRONTEND="noninteractive" sudo apt-get install -yqq mysql-client libmysqlclient-dev postgresql-client libpq-dev
57
+ mysql --host 127.0.0.1 --port ${{ job.services.mysql.ports[3306] }} -uroot -proot -e "SHOW GRANTS FOR 'root'@'localhost'"
58
+ env PGPASSWORD=postgres psql -h localhost -p ${{ job.services.postgres.ports[5432] }} -U postgres -l
59
+ sqlite3 --version
60
+
61
+ - name: Set up Ruby
62
+ uses: ruby/setup-ruby@v1
63
+ with:
64
+ ruby-version: ${{ matrix.ruby }}
65
+ bundler-cache: true
66
+
67
+ - name: Create MySQL database
68
+ run: |
69
+ mysql -e 'create database test; use test; create table if not exists wares(id int auto_increment, primary key(id)); create table if not exists builders(id int auto_increment, primary key(id));' --host 127.0.0.1 --port ${{ job.services.mysql.ports[3306] }} -uroot -proot
70
+
71
+ - name: Create PostgreSQL database
72
+ env:
73
+ PGPASSWORD: postgres
74
+ run: |
75
+ psql -c 'create database "test";' -U postgres -h localhost -p ${{ job.services.postgres.ports[5432] }}
76
+
77
+ - name: Create SQLite database
78
+ run: |
79
+ mkdir ./db && touch ./db/test.sqlite3 && sqlite3 ./db/test.sqlite3
80
+
81
+ - name: Run Tests
82
+ run: bundle exec rake test
83
+ env:
84
+ TEST_POSTGRES_DATABASE: test
85
+ TEST_POSTGRES_HOST: localhost
86
+ TEST_POSTGRES_PORT: ${{ job.services.postgres.ports[5432] }}
87
+ TEST_POSTGRES_USERNAME: postgres
88
+ TEST_POSTGRES_PASSWORD: postgres
89
+ TEST_MYSQL_DATABASE: test
90
+ TEST_MYSQL_HOST: 127.0.0.1
91
+ TEST_MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
92
+ TEST_MYSQL_USERNAME: root
93
+ TEST_MYSQL_PASSWORD: root
94
+ TEST_SQLITE_DATABASE: "db/test.sqlite3"
95
+
96
+ - name: Run Rubocop
97
+ run: bundle exec rake rubocop
data/.gitignore CHANGED
@@ -1,11 +1,17 @@
1
- .bundle
2
-
3
1
  ## MAC OS
4
2
  .DS_Store
5
3
 
6
4
  ## PROJECT::GENERAL
7
5
  coverage
6
+ rdoc
8
7
  doc
9
8
  pkg
10
9
  tmp
10
+ log
11
+ db
12
+
13
+ ## PROJECT::SPECIFIC
14
+ .bundle
15
+ .byebug_history
11
16
  Gemfile.lock
17
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,37 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.7
3
+ NewCops: enable
4
+ SuggestExtensions:
5
+ rubocop-rake: false
6
+
7
+ Naming/FileName:
8
+ Enabled: false
9
+
10
+ Metrics/MethodLength:
11
+ Enabled: false
12
+
13
+ Metrics/ClassLength:
14
+ Exclude:
15
+ - test/**/*
16
+
17
+ Metrics/AbcSize:
18
+ Enabled: false
19
+
20
+ Metrics/CyclomaticComplexity:
21
+ Enabled: false
22
+
23
+ Metrics/PerceivedComplexity:
24
+ Enabled: false
25
+
26
+ Gemspec/RequireMFA:
27
+ Enabled: false
28
+
29
+ Gemspec/DevelopmentDependencies:
30
+ EnforcedStyle: gemspec
31
+
32
+ Style/Documentation:
33
+ Enabled: false
34
+
35
+ Lint/ConstantDefinitionInBlock:
36
+ Exclude:
37
+ - test/**/*
data/CHANGELOG.md CHANGED
@@ -11,6 +11,20 @@ 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
+
21
+ ## v0.2.0 - 2023-09-14
22
+
23
+ - [Added] CI features based on GitHub Actions.
24
+ - [Fixed] README.md
25
+ - [Changed] Unit tests.
26
+ - [Fixed] Sequel::Sequence::Database exceptions.
27
+
14
28
  ## v0.1.0 - 2023-09-10
15
29
 
16
30
  - Initial release.
data/CONTRIBUTING.md CHANGED
@@ -9,7 +9,7 @@ changes to this document in a pull request.
9
9
  ## Code of Conduct
10
10
 
11
11
  Everyone interacting in this project's codebases, issue trackers, chat rooms and
12
- mailing lists is expected to follow the [code of conduct](https://github.com/fnando/sequel-sequence/blob/main/CODE_OF_CONDUCT.md).
12
+ mailing lists is expected to follow the [code of conduct](https://github.com/oreol-group/sequel-sequence/blob/master/CODE_OF_CONDUCT.md).
13
13
 
14
14
  ## Reporting bugs
15
15
 
@@ -26,7 +26,7 @@ the behavior, and find related reports.
26
26
  ## Contributing with code
27
27
 
28
28
  Before making any radicals changes, please make sure you discuss your intention
29
- by [opening an issue on Github](https://github.com/fnando/sequel-sequence/issues).
29
+ by [opening an issue on Github](https://github.com/oreol-group/sequel-sequence/issues).
30
30
 
31
31
  When you're ready to make your pull request, follow checklist below to make sure
32
32
  your contribution is according to how this project works.
@@ -81,11 +81,22 @@ test=# \dt
81
81
  --------+---------+-------+-----------
82
82
  public | masters | table | USER_NAME
83
83
  public | things | table | USER_NAME
84
- (2 rows)
85
84
  ```
86
- - If it doesn't exists, create one with a couple of tables:
85
+ and role `postgres`
86
+ ```bash
87
+ psql -d test -c 'SELECT rolname FROM pg_roles;'
88
+ rolname
89
+ ---------------------------
90
+ postgres
91
+ ```
92
+ - If none of them exist, create role
93
+ ```bash
94
+ psql -d postgres -c "create role postgres superuser createdb login password 'postgres';"
95
+ ```
96
+ and database with a couple of tables:
97
+
87
98
  ```bash
88
- sudo psql -U USER_NAME -d postgres
99
+ sudo psql -U postgres -d postgres
89
100
  postgres=# CREATE DATABASE test;
90
101
  postgres=# \c test
91
102
  test=# CREATE TABLE IF NOT EXISTS things ();
@@ -104,7 +115,6 @@ MariaDB [test]> SHOW TABLES;
104
115
  | builders |
105
116
  | wares |
106
117
  +----------------------+
107
- 4 rows in set (0.001 sec)
108
118
  ```
109
119
  - If it doesn't exists, create one with a couple of tables:
110
120
  ```bash
@@ -113,8 +123,19 @@ MariaDB [(none)]> USE test;
113
123
  MariaDB [test]> CREATE TABLE IF NOT EXISTS wares(id int auto_increment, primary key(id));
114
124
  MariaDB [test]> CREATE TABLE IF NOT EXISTS builders(id int auto_increment, primary key(id));
115
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
+ ```
116
136
  - Run the tests separately:
117
137
  ```bash
118
- bundle exec rake TEST=test/ar/postgresql_sequence_test.rb
119
- bundle exec rake TEST=test/ar/mysql_sequence_test.rb
138
+ bundle exec rake TEST=test/sequel/postgresql_sequence_test.rb
139
+ bundle exec rake TEST=test/sequel/mysql_sequence_test.rb
140
+ bundle exec rake TEST=test/sequel/sqlite_sequence_test.rb
120
141
  ```
data/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # sequel-sequence
2
2
 
3
- [![Tests](https://github.com/oreol-group/sequel-sequence/workflows/Tests/badge.svg)](https://github.com/oreol-group/sequel-sequence)
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
- [![Downloads total](https://img.shields.io/gem/dt/sequel-sequence.svg)](https://rubygems.org/gems/sequel-sequence)
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)
@@ -93,16 +112,16 @@ DB.setval("position", 1234)
93
112
  ## Contributing
94
113
 
95
114
  For more details about how to contribute, please read
96
- https://github.com/oreol-group/sequel-sequence/blob/main/CONTRIBUTING.md.
115
+ https://github.com/oreol-group/sequel-sequence/blob/master/CONTRIBUTING.md.
97
116
 
98
117
  ## License
99
118
 
100
119
  The gem is available as open source under the terms of the
101
120
  [MIT License](https://opensource.org/licenses/MIT). A copy of the license can be
102
- found at https://github.com/oreol-group/sequel-sequence/blob/main/LICENSE.md.
121
+ found at https://github.com/oreol-group/sequel-sequence/blob/master/LICENSE.md.
103
122
 
104
123
  ## Code of Conduct
105
124
 
106
125
  Everyone interacting in the sequel-sequence project's codebases, issue trackers,
107
126
  chat rooms and mailing lists is expected to follow the
108
- [code of conduct](https://github.com/oreol-group/sequel-sequence/blob/main/CODE_OF_CONDUCT.md).
127
+ [code of conduct](https://github.com/oreol-group/sequel-sequence/blob/master/CODE_OF_CONDUCT.md).
@@ -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