Repository URL to install this package:
|
Version:
7.3.3 ▾
|
# frozen_string_literal: true
require_relative 'admin_connection'
Sequel.extension :pg_json
module Faculty
module DatabaseHelper
# Macros for use in defining table helpers
module TableMacros
def define_table(table, helper_class, **)
schema = module_schema_name
helper = helper_class.new(table, schema:, **)
define_method(:"#{table}_record") do
warn "[DEPRECATION] `#{table}_record` is deprecated. Please use `dbt.#{schema}.#{table}` instead."
helper
end
SCHEMAS[schema][table] = helper
end
def module_schema_name
name.split('::').last.downcase.to_sym
end
end
# Generic spec helper for dealing with test records
class GenericTableHelper
attr_reader :qualified_table
def initialize(table, schema: nil, default_record: {}, pg_jsonb_fields: {})
@qualified_table = schema ? Sequel[schema][table] : table
@default_record = default_record
@pg_jsonb_fields = pg_jsonb_fields
end
def connection
raise "#{self.class} (for #{table_name}) is an instance of GenericTableHelper and has no connection"
end
def table
connection[qualified_table]
end
def table_name
return qualified_table unless qualified_table.is_a? Sequel::SQL::QualifiedIdentifier
"#{qualified_table.table}.#{qualified_table.column}"
end
def default_record_fields
@default_record
end
def include?(...)
!table.where(...).empty?
end
def insert(**fields)
table.insert_select(**fields_to_insert(**fields))
.then { |row| row.extend(Row).set(table, primary_keys) }
rescue Sequel::Error => e
raise e.class, "#{self.class} failed to insert to #{table_name}: #{e}"
end
def fields_to_insert(**fields)
wrap_jsonb_fields(deep_merge(default_record_fields, fields))
end
def wrap_jsonb_fields(fields)
fields.to_h do |k, v|
@pg_jsonb_fields.include?(k) ? [k, Sequel.pg_jsonb_wrap(v)] : [k, v]
end
end
# Shamelessly lifted from rails
# (https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/hash/deep_merge.rb)
def deep_merge(from, to, &block)
from.merge(to) do |key, this_val, other_val|
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
deep_merge(this_val, other_val, &block)
elsif block
yield key, this_val, other_val
else
other_val
end
end
end
def truncate
table.truncate(cascade: true)
end
def to_s
return @qualified_table unless @qualified_table.is_a? Sequel::SQL::QualifiedIdentifier
"#{@qualified_table.table}.#{@qualified_table.column}"
end
def inspect
"#<#{self.class} #{self}>"
end
private
def primary_keys
@primary_keys ||= connection.schema(@qualified_table).filter_map { |k, v| k if v[:primary_key] }
end
end
# Tables that are in the app's schema
class LocalTableHelper < GenericTableHelper
def connection
Faculty::SpecHelpers.connection
end
end
# Tables which are outside the app's schema
class ExternalTableHelper < GenericTableHelper
include AdminConnection
class << self
attr_accessor :db
end
def connection
ExternalTableHelper.db || super
end
end
# Extend the returned row with a cleanup method
module Row
def set(table, primary_keys)
@table = table
@primary_keys = primary_keys
self
end
def primary_keys
slice(*@primary_keys)
end
def primary_key
raise 'More than one primary key' if @primary_keys.length > 1
raise 'No primary keys' if @primary_keys.empty?
fetch @primary_keys.first
end
def cleanup
@table.where(**(@primary_keys.empty? ? self : primary_keys)).delete
end
end
end
end