beamer-rails 0.1.0.beta4-x86_64-linux-gnu

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fe6a0ee1fbe85423c69148ec557c4ec8a4712455da8b10e9107ccfeb2c1beba7
4
+ data.tar.gz: b44a3730c6b840e666c65088a7d6a1d2dc47fcc496303fd46730833e8b27291b
5
+ SHA512:
6
+ metadata.gz: 1ca61775b19b1a1a9ad32d6372468374c1bd11e64691f891a7c8ac52a1582a0c5b5e31b97165afc126c747c047541f2731e705e30db850c545ac79bec8663b36
7
+ data.tar.gz: 631067e86bc219b5013ec8cb401356cefeb33f4f8fc85e2be84a86b2a89045812c67d97d6df353f12c40634d8dd49a5272e0582164cccccaeb8d2859add48392
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Kevin McConnell
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.
data/exe/beamer ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../lib/beamer"
5
+
6
+ executable = File.join(Beamer.exe_dir, "beamer")
7
+
8
+ if File.exist?(executable)
9
+ exec(executable, *ARGV)
10
+ else
11
+ STDERR.puts("ERROR: Unsupported platform: #{Beamer.platform}")
12
+ exit 1
13
+ end
Binary file
Binary file
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/connection_adapters/sqlite3_adapter"
4
+
5
+ # ActiveRecord database adapter for Beamer-replicated SQLite databases.
6
+ #
7
+ # This adapter extends the standard SQLite3Adapter to automatically configure
8
+ # databases for Beamer replication. It loads the Beamer VFS extension and
9
+ # ensures the database connection uses it.
10
+ #
11
+ # @example database.yml configuration
12
+ # production:
13
+ # adapter: beamer
14
+ # database: storage/production.sqlite3
15
+ #
16
+ # @api private
17
+ class Beamer::ConnectionAdapter < ActiveRecord::ConnectionAdapters::SQLite3Adapter
18
+ ADAPTER_NAME = "Beamer"
19
+ BOOLEAN = ActiveRecord::Type::Boolean.new
20
+
21
+ # Initialize a new Beamer database connection.
22
+ #
23
+ # This loads the Beamer VFS extension, validates that the database is not
24
+ # in-memory, and configures the connection to use the Beamer VFS.
25
+ #
26
+ # @raise [Beamer::UnsupportedDatabaseType] if attempting to use an in-memory database
27
+ # @raise [Beamer::UnsupportedPlatform] if the Beamer extension is not available
28
+ def initialize(...)
29
+ Beamer.load
30
+
31
+ super
32
+
33
+ if @memory_database
34
+ raise Beamer::UnsupportedDatabaseType, "Beamer isn't compatible with in-memory databases"
35
+ end
36
+
37
+ configure_beamer(@connection_parameters)
38
+ end
39
+
40
+ def beamer_primary?
41
+ BOOLEAN.cast(execute_pragma("beamer_is_primary")) if beamer_primary
42
+ rescue ActiveRecord::StatementInvalid
43
+ nil
44
+ end
45
+
46
+ def beamer_primary
47
+ execute_pragma("beamer_primary").presence
48
+ rescue ActiveRecord::StatementInvalid
49
+ nil
50
+ end
51
+
52
+ def beamer_last_txn
53
+ execute_pragma("beamer_last_txn").presence
54
+ rescue ActiveRecord::StatementInvalid
55
+ nil
56
+ end
57
+
58
+ def beamer_zone
59
+ execute_pragma("beamer_zone").presence
60
+ end
61
+
62
+ def beamer_zone=(desired_zone)
63
+ execute_pragma("beamer_zone = #{quote(desired_zone)}").tap do |new_zone|
64
+ if new_zone != desired_zone
65
+ raise Beamer::ZoneChangeError, "Failed to set Beamer zone to #{desired_zone.inspect}"
66
+ end
67
+ end
68
+ end
69
+
70
+ private
71
+ def configure_beamer(config)
72
+ inject_vfs(config)
73
+ end
74
+
75
+ def inject_vfs(config)
76
+ if config[:database].blank?
77
+ end
78
+
79
+ database, query_string = config[:database].split("?", 2)
80
+ attributes = query_string ? CGI.parse(query_string) : {}
81
+
82
+ attributes["vfs"] = "beamer"
83
+ database = "file:#{database}" unless database.start_with?("file:")
84
+
85
+ config[:database] = "#{database}?#{URI.encode_www_form(attributes)}"
86
+ end
87
+
88
+ def execute_pragma(pragma)
89
+ execute("PRAGMA #{pragma}").first&.values&.first
90
+ end
91
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Rails integration for Beamer.
4
+ #
5
+ # This Railtie automatically registers the Beamer database adapter with ActiveRecord
6
+ # during Rails initialization, allowing you to use `adapter: beamer` in database.yml.
7
+ #
8
+ # @example database.yml configuration
9
+ # production:
10
+ # adapter: beamer
11
+ # database: storage/production.sqlite3
12
+ #
13
+ # @api private
14
+ class Beamer::Railtie < ::Rails::Railtie
15
+ # Register the Beamer adapter before Rails configuration is loaded.
16
+ # This ensures the adapter is available when database.yml is parsed.
17
+ config.before_configuration do
18
+ ActiveRecord::ConnectionAdapters.register("beamer", "Beamer::ConnectionAdapter", "beamer/connection_adapter")
19
+ ActiveRecord::Tasks::DatabaseTasks.register_task(/beamer/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
20
+
21
+ if defined?(ActiveRecord::Tenanted)
22
+ require "beamer/tenanted_database_adapter"
23
+ ActiveRecord::Tenanted::DatabaseAdapter.register("beamer", "Beamer::TenantedDatabaseAdapter")
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/tenanted/database_adapters/sqlite"
4
+
5
+ # Database adapter for ActiveRecord::Tenanted that enables Beamer replication
6
+ # for tenanted databases.
7
+ #
8
+ # This adapter extends the standard SQLite tenanted adapter with Beamer's VFS,
9
+ # allowing each tenant database to have its own replication state and benefit
10
+ # from Beamer's replication capabilities.
11
+ #
12
+ # The adapter is automatically registered when ActiveRecord::Tenanted is detected
13
+ # during Rails initialization (see Beamer::Railtie).
14
+ #
15
+ # @example Creating a tenanted database with Beamer
16
+ # # With adapter: beamer in database.yml
17
+ # ActiveRecord::Tenanted.create_tenant("tenant-1")
18
+ # # Creates a database using Beamer VFS with its own .beamer directory
19
+ #
20
+ # @see https://github.com/basecamp/activerecord-tenanted
21
+ # @api private
22
+ class Beamer::TenantedDatabaseAdapter < ActiveRecord::Tenanted::DatabaseAdapters::SQLite
23
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Beamer
4
+ VERSION = "0.1.0.beta4"
5
+
6
+ NATIVE_PLATFORMS = {
7
+ "arm-linux-gnu" => "../../release/arm-linux-gnu",
8
+ "arm-linux-musl" => "../../release/arm-linux-musl",
9
+ "arm64-darwin" => "../../release/arm64-darwin",
10
+ "arm64-linux-gnu" => "../../release/aarch64-linux-gnu",
11
+ "arm64-linux-musl" => "../../release/aarch64-linux-musl",
12
+ "x86_64-darwin" => "../../release/x86_64-darwin",
13
+ "x86_64-linux-gnu" => "../../release/x86_64-linux-gnu",
14
+ "x86_64-linux-musl" => "../../release/x86_64-linux-musl"
15
+ }
16
+ end
@@ -0,0 +1 @@
1
+ require_relative "./beamer"
data/lib/beamer.rb ADDED
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sqlite3"
4
+ require "rubygems"
5
+
6
+ require_relative "beamer/version"
7
+ require_relative "beamer/railtie" if defined?(Rails)
8
+
9
+ module Beamer
10
+ GEM_NAME = "beamer-rails"
11
+
12
+ autoload :ConnectionAdapter, "beamer/connection_adapter"
13
+
14
+ # Base exception class for the library.
15
+ class Error < StandardError; end
16
+
17
+ # Raised when the SQLite extension isn't packaged for the current OS, processor and ABI.
18
+ class UnsupportedPlatform < Error; end
19
+
20
+ # Raised when attempting to use Beamer to replicate an unsupported type of database.
21
+ class UnsupportedDatabaseType < Error; end
22
+
23
+ # Raised when a zone change operation fails.
24
+ class ZoneChangeError < Error; end
25
+
26
+ class << self
27
+ # Loads the Beamer SQLite extension for the current process.
28
+ #
29
+ # This registers the Beamer VFS globally with SQLite, enabling all subsequent
30
+ # database connections to use it. The VFS provides SQLite replication functionality.
31
+ #
32
+ # @return [SQLite3::Database] A temporary in-memory database used to load the extension
33
+ # @raise [UnsupportedPlatform] if the current platform doesn't have a precompiled extension
34
+ #
35
+ # @example
36
+ # Beamer.load
37
+ #
38
+ # @note This is called automatically when using `adapter: beamer` in database.yml.
39
+ # You typically don't need to call this manually if you are using Rails.
40
+ def load
41
+ if extension_path
42
+ SQLite3::Database.new(":memory:").tap do |db|
43
+ db.enable_load_extension(true)
44
+ db.load_extension(extension_path)
45
+ end
46
+ else
47
+ raise UnsupportedPlatform, "Unsupported platform: #{platform}"
48
+ end
49
+
50
+ true
51
+ end
52
+
53
+ # Returns the file system path to the Beamer SQLite extension for the current platform.
54
+ #
55
+ # @return [String, nil] Path to beamer extension, or nil if not found
56
+ #
57
+ # @example
58
+ # Beamer.extension_path
59
+ # # => "/path/to/gem/exe/x86_64-linux-gnu/beamer.so"
60
+ def extension_path
61
+ exe_path = "#{exe_dir}/beamer.so"
62
+
63
+ if File.exist?(exe_path)
64
+ exe_path
65
+ else
66
+ nil
67
+ end
68
+ end
69
+
70
+ # Returns the directory containing platform-specific executables and extensions.
71
+ #
72
+ # @return [String] Absolute path to the exe directory for the current platform
73
+ #
74
+ # @example
75
+ # Beamer.exe_dir
76
+ # # => "/path/to/gem/exe/x86_64-linux-gnu"
77
+ def exe_dir
78
+ File.expand_path("../../exe/#{platform}", __FILE__)
79
+ end
80
+
81
+ # Returns the normalized platform string for the current system.
82
+ #
83
+ # This method normalizes platform identifiers to match RubyGems conventions,
84
+ # adding the `-gnu` suffix to glibc-based Linux platforms.
85
+ #
86
+ # @return [String] Platform identifier (e.g., "x86_64-linux-gnu", "arm64-darwin")
87
+ #
88
+ # @example
89
+ # Beamer.platform
90
+ # # => "x86_64-linux-gnu" (on Ubuntu/Debian)
91
+ # # => "x86_64-linux-musl" (on Alpine Linux)
92
+ # # => "arm64-darwin" (on Apple Silicon Mac)
93
+ def platform
94
+ Beamer::NATIVE_PLATFORMS.keys.find { |p| Gem::Platform.match_gem?(Gem::Platform.new(p), GEM_NAME) } ||
95
+ raise(UnsupportedPlatform, "Can not find a matching platform for: #{Gem::Platform.local}")
96
+ end
97
+ end
98
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beamer-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.beta4
5
+ platform: x86_64-linux-gnu
6
+ authors:
7
+ - Kevin McConnell
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: sqlite3
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
40
+ email:
41
+ - kevin@37signals.com
42
+ executables:
43
+ - beamer
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - LICENSE.txt
48
+ - exe/beamer
49
+ - exe/x86_64-linux-gnu/beamer
50
+ - exe/x86_64-linux-gnu/beamer.so
51
+ - lib/beamer-rails.rb
52
+ - lib/beamer.rb
53
+ - lib/beamer/connection_adapter.rb
54
+ - lib/beamer/railtie.rb
55
+ - lib/beamer/tenanted_database_adapter.rb
56
+ - lib/beamer/version.rb
57
+ homepage: https://github.com/basecamp/beamer
58
+ licenses:
59
+ - MIT
60
+ metadata:
61
+ homepage_uri: https://github.com/basecamp/beamer
62
+ source_code_uri: https://github.com/basecamp/beamer
63
+ rubygems_mfa_required: 'true'
64
+ github_repo: ssh://github.com/basecamp/beamer
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 3.2.0
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubygems_version: 3.6.9
80
+ specification_version: 4
81
+ summary: Beamer SQLite replication for Rails
82
+ test_files: []