Add SQLite support

- UUID support
- Schema compatibility layer, ignore MySQL specific options
- Search not working yet
This commit is contained in:
Donal McBreen
2025-11-19 12:02:26 +00:00
parent 7f76835150
commit a2333d9a37
8 changed files with 137 additions and 11 deletions
+3
View File
@@ -31,6 +31,9 @@
!/tmp/storage/.keep
/data
*.sqlite3
*.sqlite3_*
/public/assets
# Ignore master key for decrypting credentials and more.
+5
View File
@@ -1,7 +1,12 @@
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
# SQLite doesn't use separate replica databases
if ENV.fetch("DATABASE_ADAPTER", "mysql") == "sqlite"
connects_to database: { writing: :primary, reading: :primary }
else
connects_to database: { writing: :primary, reading: :replica }
end
attribute :id, :uuid, default: -> { ActiveRecord::Type::Uuid.generate }
end
+25 -4
View File
@@ -1,4 +1,7 @@
<%
database_adapter = ENV.fetch("DATABASE_ADAPTER", "mysql")
use_sqlite = database_adapter == "sqlite"
if ENV["MIGRATE"].present?
mysql_app_user_key = "MYSQL_ALTER_USER"
mysql_app_password_key = "MYSQL_ALTER_PASSWORD"
@@ -12,13 +15,24 @@
%>
default: &default
<% if use_sqlite %>
adapter: sqlite3
pool: 50
timeout: 5000
<% else %>
adapter: trilogy
host: <%= ENV.fetch "FIZZY_DB_HOST", "127.0.0.1" %>
port: <%= ENV.fetch "FIZZY_DB_PORT", 3306 %>
pool: 50
timeout: 5000
<% end %>
development:
<% if use_sqlite %>
primary:
<<: *default
database: db/development.sqlite3
<% else %>
primary:
<<: *default
database: fizzy_development
@@ -26,28 +40,34 @@ development:
replica:
<<: *default
database: fizzy_development
replica: true
port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
replica: true
cable:
<<: *default
database: development_cable
migrations_paths: db/cable_migrate
port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
migrations_paths: db/cable_migrate
cache:
<<: *default
database: development_cache
migrations_paths: db/cache_migrate
port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
migrations_paths: db/cache_migrate
queue:
<<: *default
database: development_queue
migrations_paths: db/queue_migrate
port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
migrations_paths: db/queue_migrate
<% end %>
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<% if use_sqlite %>
primary:
<<: *default
database: db/test.sqlite3
<% else %>
primary:
<<: *default
database: fizzy_test
@@ -57,6 +77,7 @@ test:
database: fizzy_test
port: <%= ENV.fetch "FIZZY_DB_PORT", 33380 %>
replica: true
<% end %>
production: &production
primary:
+5
View File
@@ -6,8 +6,13 @@ end
# Use DB read/write splitting for Active Storage models
ActiveSupport.on_load(:active_storage_record) do
# SQLite doesn't use separate replica databases
if ENV.fetch("DATABASE_ADAPTER", "mysql") == "sqlite"
connects_to database: { writing: :primary, reading: :primary }
else
connects_to database: { writing: :primary, reading: :replica }
end
end
module ActiveStorageControllerExtensions
extend ActiveSupport::Concern
@@ -0,0 +1,54 @@
# SQLite compatibility layer - filters out MySQL-specific options when using SQLite
# Define modules outside on_load so they're available immediately
module SQLiteCompatibility
module SQLiteTableDefinitionCompatibility
# Override column method to filter out MySQL-specific options
def column(name, type, **options)
# Check if we're using SQLite by checking the connection adapter
if @conn.is_a?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
# Remove MySQL-specific options that SQLite doesn't support
options = options.except(:size, :charset, :collation, :unsigned)
end
super(name, type, **options)
end
# Override index method to filter out MySQL-specific index options
def index(column_name, **options)
if @conn.is_a?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
# Skip fulltext indexes entirely for SQLite
return if options[:type] == :fulltext
# SQLite doesn't support length-limited indexes
options = options.except(:length)
end
super(column_name, **options)
end
end
module SQLiteSchemaStatementCompatibility
# Override create_table to filter out MySQL-specific table options
def create_table(table_name, **options)
if is_a?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
# Remove MySQL-specific table options
options = options.except(:charset, :collation)
end
super(table_name, **options)
end
end
end
# Apply the prepends - both in on_load callback and immediately
def apply_sqlite_compatibility
if defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
ActiveRecord::ConnectionAdapters::TableDefinition.prepend(SQLiteCompatibility::SQLiteTableDefinitionCompatibility)
ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(SQLiteCompatibility::SQLiteSchemaStatementCompatibility)
end
end
# Run immediately if ActiveRecord is already loaded
apply_sqlite_compatibility
# Also run when ActiveRecord loads (for cases where it loads later)
ActiveSupport.on_load(:active_record) do
apply_sqlite_compatibility
end
+37
View File
@@ -16,7 +16,42 @@ ActiveSupport.on_load(:active_record) do
end
end
if defined?(ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter)
ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter.prepend(MysqlUuidAdapter)
end
module SqliteUuidAdapter
# Add UUID to SQLite's native database types
def native_database_types
@native_database_types_with_uuid ||= super.merge(uuid: { name: "blob", limit: 16 })
end
# Override lookup_cast_type to recognize BLOB as UUID type
def lookup_cast_type(sql_type)
if sql_type == "blob(16)"
ActiveRecord::Type.lookup(:uuid, adapter: :sqlite3)
else
super
end
end
# Override fetch_type_metadata to preserve UUID type and limit
def fetch_type_metadata(sql_type)
if sql_type == "blob(16)"
ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(
sql_type: sql_type,
type: :uuid,
limit: 16
)
else
super
end
end
end
if defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(SqliteUuidAdapter)
end
module SchemaDumperUuidType
# Map binary(16) columns to :uuid type in schema.rb
@@ -29,7 +64,9 @@ ActiveSupport.on_load(:active_record) do
end
end
if defined?(ActiveRecord::ConnectionAdapters::MySQL::SchemaDumper)
ActiveRecord::ConnectionAdapters::MySQL::SchemaDumper.prepend(SchemaDumperUuidType)
end
module TableDefinitionUuidSupport
def uuid(name, **options)
+2 -1
View File
@@ -39,5 +39,6 @@ module ActiveRecord
end
end
# Register the UUID type for Trilogy adapter
# Register the UUID type for Trilogy (MySQL) and SQLite3 adapters
ActiveRecord::Type.register(:uuid, ActiveRecord::Type::Uuid, adapter: :trilogy)
ActiveRecord::Type.register(:uuid, ActiveRecord::Type::Uuid, adapter: :sqlite3)
+2 -2
View File
@@ -7,5 +7,5 @@ kevin:
jz:
identity: jz
jason:
identity: jason
mike:
identity: mike