DEV: Store details log entries in converter as JSON (#29778)

Plus small DB related fixes
This commit is contained in:
Gerhard Schlager 2024-11-19 23:54:00 +01:00 committed by GitHub
parent 75f4a14568
commit a48af2f120
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 42 additions and 21 deletions

View File

@ -4,5 +4,5 @@ CREATE TABLE log_entries
type TEXT NOT NULL, type TEXT NOT NULL,
message TEXT NOT NULL, message TEXT NOT NULL,
exception TEXT, exception TEXT,
details TEXT details JSON_TEXT
); );

View File

@ -3,23 +3,22 @@
require "date" require "date"
require "extralite" require "extralite"
require "ipaddr" require "ipaddr"
require "oj"
module Migrations module Migrations
module Database module Database
INTERMEDIATE_DB_SCHEMA_PATH = File.join(::Migrations.root_path, "db", "intermediate_db_schema") INTERMEDIATE_DB_SCHEMA_PATH = File.join(::Migrations.root_path, "db", "intermediate_db_schema")
UPLOADS_DB_SCHEMA_PATH = File.join(::Migrations.root_path, "db", "uploads_db_schema") UPLOADS_DB_SCHEMA_PATH = File.join(::Migrations.root_path, "db", "uploads_db_schema")
module_function def self.migrate(db_path, migrations_path:)
def migrate(db_path, migrations_path:)
Migrator.new(db_path).migrate(migrations_path) Migrator.new(db_path).migrate(migrations_path)
end end
def reset!(db_path) def self.reset!(db_path)
Migrator.new(db_path).reset! Migrator.new(db_path).reset!
end end
def connect(path) def self.connect(path)
connection = Connection.new(path:) connection = Connection.new(path:)
return connection unless block_given? return connection unless block_given?
@ -31,29 +30,34 @@ module Migrations
nil nil
end end
def format_datetime(value) def self.format_datetime(value)
value&.utc&.iso8601 value&.utc&.iso8601
end end
def format_date(value) def self.format_date(value)
value&.to_date&.iso8601 value&.to_date&.iso8601
end end
def format_boolean(value) def self.format_boolean(value)
return nil if value.nil? return nil if value.nil?
value ? 1 : 0 value ? 1 : 0
end end
def format_ip_address(value) def self.format_ip_address(value)
return nil if value.blank? return nil if value.blank?
IPAddr.new(value).to_s IPAddr.new(value).to_s
rescue ArgumentError rescue ArgumentError
nil nil
end end
def to_blob(value) def self.to_blob(value)
return nil if value.blank? return nil if value.blank?
Extralite::Blob.new(value) ::Extralite::Blob.new(value)
end
def self.to_json(value)
return nil if value.nil?
::Oj.dump(value, mode: :compat)
end end
end end
end end

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "extralite" require "extralite"
require "lru_redux"
module Migrations::Database module Migrations::Database
class Connection class Connection
@ -11,7 +10,7 @@ module Migrations::Database
def self.open_database(path:) def self.open_database(path:)
FileUtils.mkdir_p(File.dirname(path)) FileUtils.mkdir_p(File.dirname(path))
db = Extralite::Database.new(path) db = ::Extralite::Database.new(path)
db.pragma( db.pragma(
busy_timeout: 60_000, # 60 seconds busy_timeout: 60_000, # 60 seconds
journal_mode: "wal", journal_mode: "wal",
@ -30,8 +29,6 @@ module Migrations::Database
@transaction_batch_size = transaction_batch_size @transaction_batch_size = transaction_batch_size
@db = self.class.open_database(path:) @db = self.class.open_database(path:)
@statement_counter = 0 @statement_counter = 0
# don't cache too many prepared statements
@statement_cache = PreparedStatementCache.new(PREPARED_STATEMENT_CACHE_SIZE) @statement_cache = PreparedStatementCache.new(PREPARED_STATEMENT_CACHE_SIZE)
@fork_hooks = setup_fork_handling @fork_hooks = setup_fork_handling
@ -46,7 +43,7 @@ module Migrations::Database
end end
def closed? def closed?
!@db || @db.closed? @db.nil? || @db.closed?
end end
def insert(sql, parameters = []) def insert(sql, parameters = [])
@ -76,7 +73,7 @@ module Migrations::Database
end end
def close_connection(keep_path:) def close_connection(keep_path:)
return if !@db return if @db.nil?
commit_transaction commit_transaction
@statement_cache.clear @statement_cache.clear

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "singleton"
module Migrations::Database module Migrations::Database
module IntermediateDB module IntermediateDB
def self.setup(db_connection) def self.setup(db_connection)

View File

@ -18,7 +18,7 @@ module Migrations::Database::IntermediateDB
type, type,
message, message,
exception&.full_message(highlight: false), exception&.full_message(highlight: false),
details, ::Migrations::Database.to_json(details),
) )
end end
end end

View File

@ -21,12 +21,14 @@ module Migrations::Database
migrate_from_path(@migrations_path, performed_migrations) migrate_from_path(@migrations_path, performed_migrations)
@db.close @db.close
nil
end end
def reset! def reset!
[@db_path, "#{@db_path}-wal", "#{@db_path}-shm"].each do |path| [@db_path, "#{@db_path}-wal", "#{@db_path}-shm"].each do |path|
FileUtils.remove_file(path, force: true) if File.exist?(path) FileUtils.remove_file(path, force: true) if File.exist?(path)
end end
nil
end end
private private

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "lru_redux"
module Migrations::Database module Migrations::Database
class PreparedStatementCache < LruRedux::Cache class PreparedStatementCache < LruRedux::Cache
class PreparedStatementHash < Hash class PreparedStatementHash < Hash

View File

@ -140,4 +140,22 @@ RSpec.describe ::Migrations::Database do
expect(described_class.to_blob(nil)).to be_nil expect(described_class.to_blob(nil)).to be_nil
end end
end end
describe ".to_json" do
it "returns a JSON string for objects" do
expect(described_class.to_json(123)).to eq("123")
expect(described_class.to_json("hello world")).to eq(%q|"hello world"|)
expect(
described_class.to_json(
text: "foo",
number: 123,
date: DateTime.new(2023, 10, 5, 17, 30, 0),
),
).to eq(%q|{"text":"foo","number":123,"date":"2023-10-05T17:30:00.000+00:00"}|)
end
it "returns nil for nil input" do
expect(described_class.to_json(nil)).to be_nil
end
end
end end