activerecord-enhancedsqlite3-adapter 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +27 -0
- data/lib/activerecord-enhancedsqlite3-adapter.rb +12 -0
- data/lib/enhanced_sqlite3/adapter.rb +21 -9
- data/lib/enhanced_sqlite3/railtie.rb +49 -2
- data/lib/enhanced_sqlite3/resolver.rb +9 -0
- data/lib/enhanced_sqlite3/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0d679b0ee45b0838fc294f50e43b806301fba662e54f280b3d0e747de3e7670
|
4
|
+
data.tar.gz: 5b345ff772a3cba527a4fe638724bb372f488bc8ec3ceb4d3e8b76ee40b2f434
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 47288376cd918173cce7edf28fc2a8cbb8a86c749aa44aaf88e4b2f81fc922b3b5369e579abb8e9bab7585f7c8b2ae732c3f6a8601117e935a61effcf7d86276
|
7
|
+
data.tar.gz: 22ae8604263b8a75379a0f9c132d60cf4616d6695665742b4a6a358f24f0fa4daf1b5b1708ecf5599617293bc4a8fc76db89fbd204deaa70b430233db2f6891a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.6.0] - 2024-04-10
|
4
|
+
|
5
|
+
- Use the same busy_handler function as will be in the sqlite3-ruby gem ([@fractaledmind](https://github.com/fractaledmind/activerecord-enhancedsqlite3-adapter/pull/11))
|
6
|
+
- Allow for isolated reading and writing connection pools ([@fractaledmind](https://github.com/fractaledmind/activerecord-enhancedsqlite3-adapter/pull/12))
|
7
|
+
- Ensure that even Rails 7.0 apps can use insert returning ([@fractaledmind](https://github.com/fractaledmind/activerecord-enhancedsqlite3-adapter/pull/8))
|
8
|
+
- Load virtual columns extension only if the app is running 7.1 or less ([@npezza93](https://github.com/fractaledmind/activerecord-enhancedsqlite3-adapter/pull/7))
|
9
|
+
|
3
10
|
## [0.5.0] - 2023-12-24
|
4
11
|
|
5
12
|
- Load extensions installed via project-scoped `sqlpkg`
|
data/README.md
CHANGED
@@ -21,6 +21,14 @@ This gem hooks into your Rails application to enhance the `SQLite3Adapter` autom
|
|
21
21
|
|
22
22
|
Once installed, you can take advantage of the added features.
|
23
23
|
|
24
|
+
### Configuration
|
25
|
+
|
26
|
+
One optional advanced feature is to have this gem isolate reading and writing connection pools. This is useful if you have a large amount of write operations and want to avoid blocking reads.
|
27
|
+
|
28
|
+
You can configure this gem via the Rails configuration object, under the `enhanced_sqlite3` key. Currently, only 1 configuration option is available:
|
29
|
+
|
30
|
+
* `isolate_connection_pools` - Whether or not to isolate reading from writing connection pools. See [below](#isolated-connection-pools) for more information.
|
31
|
+
|
24
32
|
### Generated columns
|
25
33
|
|
26
34
|
You can now create `virtual` columns, both stored and dynamic. The [SQLite docs](https://www.sqlite.org/gencol.html) explain the difference:
|
@@ -81,6 +89,25 @@ default: &default
|
|
81
89
|
- sqlite_ulid
|
82
90
|
```
|
83
91
|
|
92
|
+
### Isolated connection pools
|
93
|
+
|
94
|
+
By default, Rails uses a single connection pool for both reading and writing. This can lead to contention if you have a large number of write operations. This gem allows you to isolate the connection pools for reading and writing.
|
95
|
+
|
96
|
+
To enable this feature, set the `isolate_connection_pools` configuration option to `true` in your `config/environments/*.rb` file or `config/application.rb` file:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
config.enhanced_sqlite3.isolate_connection_pools = true
|
100
|
+
```
|
101
|
+
|
102
|
+
If enabled, the gem will patch your application in 3 ways:
|
103
|
+
|
104
|
+
1. define separate `reader` and `writer` database configurations
|
105
|
+
2. activate Rails' automatic role database switching middleware, defaulting all requests to the `reader` connection pool
|
106
|
+
3. patch the ActiveRecord `#transaction` method to switch to the `writer` connection pool for write operations
|
107
|
+
4. patch the ActiveRecord `#log` method to log the database name for each database operation
|
108
|
+
|
109
|
+
This feature is experimental and may not work with all Rails configurations. Please report any issues you encounter.
|
110
|
+
|
84
111
|
## Development
|
85
112
|
|
86
113
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -1,3 +1,15 @@
|
|
1
1
|
require "active_record"
|
2
2
|
require "enhanced_sqlite3/version"
|
3
3
|
require "enhanced_sqlite3/railtie"
|
4
|
+
|
5
|
+
module EnhancedSQLite3
|
6
|
+
Error = Class.new(StandardError)
|
7
|
+
|
8
|
+
mattr_writer :isolate_connection_pools
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def isolate_connection_pools?
|
12
|
+
@isolate_connection_pools ||= @@isolate_connection_pools || false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -44,10 +44,27 @@ module EnhancedSQLite3
|
|
44
44
|
configure_busy_handler_timeout
|
45
45
|
check_version
|
46
46
|
configure_pragmas
|
47
|
-
|
47
|
+
configure_extensions
|
48
48
|
|
49
|
-
EnhancedSQLite3::SupportsVirtualColumns.apply!
|
50
|
-
EnhancedSQLite3::SupportsDeferrableConstraints.apply!
|
49
|
+
EnhancedSQLite3::SupportsVirtualColumns.apply! unless try(:supports_virtual_columns?)
|
50
|
+
EnhancedSQLite3::SupportsDeferrableConstraints.apply! unless try(:supports_deferrable_constraints?)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Patch the #transaction method to ensure that all transactions are sent to the writing role database connection pool.
|
54
|
+
def transaction(...)
|
55
|
+
ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role, prevent_writes: false) do
|
56
|
+
super(...)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Patch the #log method to ensure that all log messages are tagged with the database connection name.
|
61
|
+
def log(...)
|
62
|
+
db_connection_name = ActiveRecord::Base.connection_db_config.name
|
63
|
+
if Rails.logger.formatter.current_tags.include? db_connection_name
|
64
|
+
super
|
65
|
+
else
|
66
|
+
Rails.logger.tagged(db_connection_name) { super }
|
67
|
+
end
|
51
68
|
end
|
52
69
|
|
53
70
|
private
|
@@ -110,13 +127,8 @@ module EnhancedSQLite3
|
|
110
127
|
end
|
111
128
|
end
|
112
129
|
|
113
|
-
def
|
130
|
+
def configure_extensions
|
114
131
|
@raw_connection.enable_load_extension(true)
|
115
|
-
# first, load any extensions installed via `sqlpkg`
|
116
|
-
Dir.glob(".sqlpkg/**/*.{dll,so,dylib}") do |extension_path|
|
117
|
-
@raw_connection.load_extension(extension_path)
|
118
|
-
end
|
119
|
-
# then, load any extensions specified in the `database.yml`
|
120
132
|
@config.fetch(:extensions, []).each do |extension_name|
|
121
133
|
require extension_name
|
122
134
|
extension_classname = extension_name.camelize
|
@@ -2,16 +2,63 @@
|
|
2
2
|
|
3
3
|
require "rails/railtie"
|
4
4
|
require "enhanced_sqlite3/adapter"
|
5
|
+
require "enhanced_sqlite3/resolver"
|
5
6
|
|
6
7
|
module EnhancedSQLite3
|
7
8
|
class Railtie < ::Rails::Railtie
|
9
|
+
config.enhanced_sqlite3 = ActiveSupport::OrderedOptions.new
|
10
|
+
|
11
|
+
initializer "enhanced_sqlite3.config" do
|
12
|
+
config.enhanced_sqlite3.each do |name, value|
|
13
|
+
EnhancedSQLite3.public_send(:"#{name}=", value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
8
17
|
# Enhance the SQLite3 ActiveRecord adapter with optimized defaults
|
9
18
|
initializer "enhanced_sqlite3.enhance_active_record_sqlite3adapter" do |app|
|
10
19
|
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
11
|
-
# self refers to `SQLite3Adapter` here
|
12
|
-
# so we can call .prepend
|
20
|
+
# self refers to `SQLite3Adapter` here
|
13
21
|
prepend EnhancedSQLite3::Adapter
|
14
22
|
end
|
15
23
|
end
|
24
|
+
|
25
|
+
# Enhance the application with isolated reading and writing connection pools
|
26
|
+
initializer "enhanced_sqlite3.setup_isolated_connection_pools" do |app|
|
27
|
+
next unless EnhancedSQLite3.isolate_connection_pools?
|
28
|
+
|
29
|
+
ActiveSupport.on_load(:active_record) do
|
30
|
+
# self refers to `ActiveRecord::Base` here
|
31
|
+
env_configs = configurations.configs_for env_name: Rails.env
|
32
|
+
remaining_configs = configurations.configurations.reject { |configuration| env_configs.include? configuration }
|
33
|
+
if env_configs.one?
|
34
|
+
config = env_configs.first
|
35
|
+
reader = ActiveRecord::DatabaseConfigurations::HashConfig.new(
|
36
|
+
Rails.env, "reader", config.configuration_hash.merge(readonly: true)
|
37
|
+
)
|
38
|
+
writer = ActiveRecord::DatabaseConfigurations::HashConfig.new(
|
39
|
+
Rails.env, "writer", config.configuration_hash.merge(pool: 1)
|
40
|
+
)
|
41
|
+
|
42
|
+
# Replace the single production configuration with two separate reader and writer configurations
|
43
|
+
self.configurations = remaining_configs + [reader, writer]
|
44
|
+
else
|
45
|
+
reader = env_configs.find { |config| config.name == "reader" }
|
46
|
+
writer = env_configs.find { |config| config.name == "writer" }
|
47
|
+
|
48
|
+
# Ensure that that there is a reader and writer configuration for the current Rails environment
|
49
|
+
raise Error.new("#{Rails.env} has #{env_configs.size} configurations") unless reader && writer
|
50
|
+
end
|
51
|
+
|
52
|
+
connects_to database: {writing: :writer, reading: :reader}
|
53
|
+
end
|
54
|
+
|
55
|
+
# Since we aren't actually using separate databases, only separate connections,
|
56
|
+
# we don't need to ensure that requests "read your own writes" with a `delay`
|
57
|
+
config.active_record.database_selector = {delay: 0}
|
58
|
+
# Use our custom resolver to ensure that benchmarking requests are sent to the reading database connection
|
59
|
+
config.active_record.database_resolver = EnhancedSQLite3::Resolver
|
60
|
+
# Keep Rails' default resolver context
|
61
|
+
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
|
62
|
+
end
|
16
63
|
end
|
17
64
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-enhancedsqlite3-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Margheim
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- lib/activerecord-enhancedsqlite3-adapter.rb
|
112
112
|
- lib/enhanced_sqlite3/adapter.rb
|
113
113
|
- lib/enhanced_sqlite3/railtie.rb
|
114
|
+
- lib/enhanced_sqlite3/resolver.rb
|
114
115
|
- lib/enhanced_sqlite3/supports_deferrable_constraints.rb
|
115
116
|
- lib/enhanced_sqlite3/supports_virtual_columns.rb
|
116
117
|
- lib/enhanced_sqlite3/version.rb
|