activerecord-enhancedsqlite3-adapter 0.5.0 → 0.6.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 +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
|