sequel-activerecord-adapter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ab2f715820608ebeb5599461592f548e15ee736e887eab787019fa491bb96d97
4
+ data.tar.gz: 60e410e9cde19d52d9338674235e62c0e8f9cfe0839674de0c220fe70b465abd
5
+ SHA512:
6
+ metadata.gz: 9de6d6449ca1ea8a7f7f471d157efefa844de7e42d3b8e0d5c8f87028aeb1160fdee30b6185447ec5e921b3c28127cbcb43720fe85933adf9778c50039feceac
7
+ data.tar.gz: eb7ef32a99ce269285e1677b0a6cd421638e7e7920dd4d5af0829d3c633e55322273a950b74d21826412272d2829c8139e6926f91baa91c101d65d2ce5165c31
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Janko Marohnić
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,108 @@
1
+ # Sequel ActiveRecord Adapter
2
+
3
+ This gem allows the [Sequel] library to reuse an existing ActiveRecord connection.
4
+ It supports `postgresql`, `mysql2` and `sqlite3` adapters.
5
+
6
+ This can be useful if you're using a library that uses Sequel for database
7
+ interaction (e.g. [Rodauth]), but you want to avoid creating a separate
8
+ database connection. Or if you're transitioning from ActiveRecord to Sequel,
9
+ and want the database connection to be reused.
10
+
11
+ Note that this is a best-effort implementation, so some discrepancies are still
12
+ possible. However, it's worth mentioning that this gem passes [Rodauth]'s test
13
+ suite for all adapters, which has some pretty advanced Sequel usage.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem "sequel-activerecord-adapter"
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```sh
26
+ $ bundle install
27
+ ```
28
+
29
+ Or install it yourself as:
30
+
31
+ ```sh
32
+ $ gem install sequel-activerecord-adapter
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ Given you've configured your ActiveRecord connection, you can create a Sequel
38
+ database and start making queries:
39
+
40
+ ```rb
41
+ require "sequel-activerecord-adapter"
42
+
43
+ DB = Sequel.activerecord
44
+ DB.create_table :posts do
45
+ primary_key :id
46
+ String :title, null: false
47
+ Stirng :body, null: false
48
+ end
49
+
50
+ DB[:posts].insert(
51
+ title: "Sequel ActiveRecord Adapter",
52
+ body: "Allows Sequel to reuse ActiveRecord's connection",
53
+ )
54
+ #=> 1
55
+
56
+ DB[:posts].all
57
+ #=> [{ title: "Sequel ActiveRecord Adapter", body: "Allows Sequel to reuse ActiveRecord's connection" }]
58
+
59
+ DB[:posts].update(title: "Sequel Active Record Adapter")
60
+ #=> 1
61
+ ```
62
+
63
+ Since Sequel is using ActiveRecord connection object to make queries, any SQL
64
+ queries will be logged to the ActiveRecord logger.
65
+
66
+ ### Configuration
67
+
68
+ By default, the connection configuration will be read from `ActiveRecord::Base`.
69
+ If you want to use connection configuration from a different model, you can
70
+ pass the model class:
71
+
72
+ ```rb
73
+ class MyModel < ActiveRecord::Base
74
+ connects_to database: { writing: :animals, reading: :animals_replica }
75
+ end
76
+ ```
77
+ ```rb
78
+ Sequel.activerecord(MyModel)
79
+ ```
80
+
81
+ If the correct adapter cannot be inferred from ActiveRecord configuration at
82
+ the time of initialization, you can always specify it explicitly:
83
+
84
+ ```rb
85
+ Sequel.activerecord(adapter: "postgresql")
86
+ ```
87
+
88
+ ## Tests
89
+
90
+ The Rakefile has rake tasks for setting up and tearing down different
91
+ databases, which you need to run first.
92
+
93
+ Then you can run the tests:
94
+
95
+ ```sh
96
+ $ rake test
97
+ ```
98
+
99
+ ## License
100
+
101
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
102
+
103
+ ## Code of Conduct
104
+
105
+ Everyone interacting in the Sequel::Activerecord::Adapter project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/janko/sequel-activerecord-adapter/blob/master/CODE_OF_CONDUCT.md).
106
+
107
+ [Sequel]: https://github.com/jeremyevans/sequel
108
+ [Rodauth]: https://github.com/jeremyevans/rodauth
@@ -0,0 +1,43 @@
1
+ require "sequel/core"
2
+ require "active_record"
3
+
4
+ require "sequel/adapters/activerecord"
5
+
6
+ module Sequel
7
+ def self.activerecord(model = nil, **options)
8
+ model ||= ::ActiveRecord::Base
9
+
10
+ activerecord_adapter = model.connection_config.fetch(:adapter)
11
+
12
+ case activerecord_adapter
13
+ when "postgresql" then adapter ||= :postgres
14
+ when "mysql2" then adapter ||= :mysql2
15
+ when "sqlite3" then adapter ||= :sqlite
16
+ else
17
+ raise Sequel::ActiveRecord::Error, "unsupported adapter: #{activerecord_adapter}"
18
+ end
19
+
20
+ db = connect(
21
+ adapter: adapter,
22
+ activerecord_model: model,
23
+ pool_class: Sequel::ConnectionPool, # fake connection pool
24
+ test: false, # don't force ActiveRecord connection
25
+ **options,
26
+ )
27
+
28
+ # general database extensions
29
+ db.extend Sequel::ActiveRecord::DatabaseMethods
30
+
31
+ # adapter-specific database extensions
32
+ Kernel.require "sequel/adapters/activerecord/#{activerecord_adapter}"
33
+ adapter_module = Sequel::ActiveRecord.const_get(activerecord_adapter.capitalize)
34
+ db.extend adapter_module::DatabaseMethods
35
+
36
+ db
37
+ end
38
+
39
+ module ActiveRecord
40
+ class Error < Sequel::Error
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,77 @@
1
+ require "active_record"
2
+
3
+ module Sequel
4
+ module ActiveRecord
5
+ module DatabaseMethods
6
+ # Ensure Sequel is not creating its own connection anywhere.
7
+ def connect(*)
8
+ raise Sequel::ActiveRecord::Error, "creating a Sequel connection is not allowed"
9
+ end
10
+
11
+ def transaction(savepoint: nil, rollback: nil, auto_savepoint: nil, server: nil, **options)
12
+ activerecord_not_supported!("#{options} transaction options") if options.any?
13
+
14
+ if in_transaction?
15
+ requires_new = savepoint || Thread.current[:sequel_activerecord_auto_savepoint]
16
+ else
17
+ requires_new = true
18
+ end
19
+
20
+ activerecord_model.transaction(requires_new: requires_new) do
21
+ begin
22
+ Thread.current[:sequel_activerecord_auto_savepoint] = true if auto_savepoint
23
+ yield
24
+ rescue Sequel::Rollback => exception
25
+ raise if rollback == :reraise
26
+ raise ::ActiveRecord::Rollback, exception.message, exception.backtrace
27
+ ensure
28
+ Thread.current[:sequel_activerecord_auto_savepoint] = nil if auto_savepoint
29
+ end
30
+
31
+ raise ::ActiveRecord::Rollback if rollback == :always
32
+ end
33
+ end
34
+
35
+ def in_transaction?(*)
36
+ activerecord_connection.transaction_open?
37
+ end
38
+
39
+ %i[after_commit after_rollback rollback_on_exit rollback_checker].each do |meth|
40
+ define_method(meth) { |*| activerecord_not_supported!("Database##{meth}") }
41
+ end
42
+
43
+ def synchronize(*)
44
+ activerecord_connection.lock.synchronize do
45
+ yield activerecord_raw_connection
46
+ end
47
+ end
48
+
49
+ def timezone
50
+ @timezone || activerecord_model.default_timezone || Sequel.database_timezone
51
+ end
52
+
53
+ private
54
+
55
+ # We won't be needing a real connection pool.
56
+ def connection_pool_default_options
57
+ { pool_class: Sequel::ConnectionPool }
58
+ end
59
+
60
+ def activerecord_raw_connection
61
+ activerecord_connection.raw_connection
62
+ end
63
+
64
+ def activerecord_connection
65
+ activerecord_model.connection
66
+ end
67
+
68
+ def activerecord_model
69
+ opts[:activerecord_model]
70
+ end
71
+
72
+ def activerecord_not_supported!(feature)
73
+ fail Sequel::ActiveRecord::Error, "#{feature} is currently not supported by ActiveRecord adapter"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,37 @@
1
+ module Sequel
2
+ module ActiveRecord
3
+ module Mysql2
4
+ module DatabaseMethods
5
+ def execute(sql, opts=OPTS)
6
+ original_query_options = activerecord_raw_connection.query_options.dup
7
+
8
+ activerecord_raw_connection.query_options.merge!(
9
+ as: :hash,
10
+ symbolize_keys: true,
11
+ cache_rows: false,
12
+ )
13
+
14
+ result = activerecord_connection.execute(sql)
15
+
16
+ if opts[:type] == :select
17
+ if block_given?
18
+ yield result
19
+ else
20
+ result
21
+ end
22
+ elsif block_given?
23
+ yield activerecord_raw_connection
24
+ end
25
+ rescue ::ActiveRecord::StatementInvalid => exception
26
+ if exception.cause.is_a?(::Mysql2::Error)
27
+ raise_error(exception.cause)
28
+ else
29
+ raise
30
+ end
31
+ ensure
32
+ activerecord_raw_connection.query_options.replace(original_query_options)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module Sequel
2
+ module ActiveRecord
3
+ module Postgresql
4
+ module DatabaseMethods
5
+ def execute(sql, opts=OPTS)
6
+ result = activerecord_connection.execute(sql)
7
+
8
+ if block_given?
9
+ yield result
10
+ else
11
+ result.cmd_tuples
12
+ end
13
+ rescue ::ActiveRecord::StatementInvalid => exception
14
+ raise_error(exception.cause, classes: database_error_classes)
15
+ ensure
16
+ result.clear if result
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
1
+ module Sequel
2
+ module ActiveRecord
3
+ module Sqlite3
4
+ module DatabaseMethods
5
+ def execute_ddl(sql, opts=OPTS)
6
+ execute(sql, opts)
7
+ end
8
+
9
+ private
10
+
11
+ def _execute(type, sql, opts, &block)
12
+ original_results_as_hash = activerecord_raw_connection.results_as_hash
13
+ activerecord_raw_connection.results_as_hash = false
14
+
15
+ case type
16
+ when :select
17
+ activerecord_connection.send(:log, sql) do
18
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
19
+ activerecord_raw_connection.query(sql, &block)
20
+ end
21
+ end
22
+ when :insert
23
+ activerecord_connection.execute(sql)
24
+ activerecord_raw_connection.last_insert_row_id
25
+ when :update
26
+ activerecord_connection.send(:execute_batch, sql)
27
+ activerecord_raw_connection.changes
28
+ end
29
+ rescue ::ActiveRecord::RecordNotUnique => exception
30
+ raise Sequel::UniqueConstraintViolation, exception.cause.message, exception.cause.backtrace
31
+ rescue ::ActiveRecord::StatementInvalid => exception
32
+ if exception.cause.is_a?(SQLite3::Exception)
33
+ raise_error(exception.cause)
34
+ else
35
+ raise
36
+ end
37
+ ensure
38
+ activerecord_raw_connection.results_as_hash = original_results_as_hash
39
+ end
40
+ end
41
+
42
+ class Result
43
+ def initialize(array)
44
+ binding.irb
45
+ @array = array
46
+ end
47
+
48
+ def types
49
+ return [] if @array.empty?
50
+ @array[0].types
51
+ end
52
+
53
+ def columns
54
+ return [] if @array.empty?
55
+ @array[0].fields
56
+ end
57
+
58
+ def each(&block)
59
+ @array.each(&block)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "sequel-activerecord-adapter"
3
+ spec.version = "0.1.0"
4
+ spec.authors = ["Janko Marohnić"]
5
+ spec.email = ["janko.marohnic@gmail.com"]
6
+
7
+ spec.summary = %q{Allows Sequel to use ActiveRecord connection for database interaction.}
8
+ spec.description = %q{Allows Sequel to use ActiveRecord connection for database interaction.}
9
+ spec.homepage = "https://github.com/janko/sequel-activerecord-adapter"
10
+ spec.license = "MIT"
11
+
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.2.0")
13
+
14
+ spec.add_dependency "sequel", "~> 5.0"
15
+ spec.add_dependency "activerecord", ">= 5.0", "< 7"
16
+
17
+ spec.add_development_dependency "pg", "~> 1.0"
18
+ spec.add_development_dependency "mysql2", "~> 0.5"
19
+ spec.add_development_dependency "sqlite3", "~> 1.4"
20
+ spec.add_development_dependency "minitest"
21
+
22
+ spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*.rb", "*.gemspec"]
23
+ spec.require_paths = ["lib"]
24
+ end
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sequel-activerecord-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janko Marohnić
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sequel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '7'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '5.0'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: pg
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: mysql2
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.5'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.5'
75
+ - !ruby/object:Gem::Dependency
76
+ name: sqlite3
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.4'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.4'
89
+ - !ruby/object:Gem::Dependency
90
+ name: minitest
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ description: Allows Sequel to use ActiveRecord connection for database interaction.
104
+ email:
105
+ - janko.marohnic@gmail.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - LICENSE.txt
111
+ - README.md
112
+ - lib/sequel-activerecord-adapter.rb
113
+ - lib/sequel/adapters/activerecord.rb
114
+ - lib/sequel/adapters/activerecord/mysql2.rb
115
+ - lib/sequel/adapters/activerecord/postgresql.rb
116
+ - lib/sequel/adapters/activerecord/sqlite3.rb
117
+ - sequel-activerecord-adapter.gemspec
118
+ homepage: https://github.com/janko/sequel-activerecord-adapter
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 2.2.0
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubygems_version: 3.1.1
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Allows Sequel to use ActiveRecord connection for database interaction.
141
+ test_files: []