Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve lookup file prep failure error handling #191

Merged
merged 5 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ These changes are merged into the `main` branch, but have not been released. Aft

=== Dev

* Improve error handling for resolution of lookups for individual jobs (PR#191)

== Releases

=== 4.0.1 - 2023-09-13
Expand Down
77 changes: 77 additions & 0 deletions lib/kiba/extend/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,83 @@ class IterativeCleanupSettingUndefinedError < StandardError
include Kiba::Extend::ErrMod
end

class JobCannotBeUsedAsLookupError < TypeError
include Kiba::Extend::ErrMod
def initialize(key, klass, for_job)
@key = key
@klass = klass
@for_job = for_job
@msg = ":#{key} cannot be used as a lookup in :#{for_job} because "\
"its src_class (#{klass}) does not include "\
"Kiba::Extend::Soures::Lookupable"
super(msg)
end

def formatted
<<~STR
JOB FAILED: LOOKUP FILE SETUP ERROR FOR: #{for_job}
#{msg}
STR
end

private

attr_reader :key, :klass, :for_job, :type, :msg
end

# Exception raised if {Kiba::Extend::FileRegistry} contains no lookup
# key for file
class NoLookupOnError < NameError
include Kiba::Extend::ErrMod
# @param filekey [Symbol] key not found in
# {Kiba::Extend::FileRegistry}
def initialize(filekey, for_job)
@filekey = filekey
@for_job = for_job
msg = "No lookup_on value in registry entry hash for :#{filekey} -- "\
"Used as lookup in job: :#{for_job})"
super(msg)
end

def formatted
<<~STR
JOB FAILED: LOOKUP FILE SETUP ERROR FOR: #{for_job}
To fix: Add `lookup_on` to registry entry hash for
:#{filekey}
STR
end

private

attr_reader :filekey, :for_job
end

# Exception raised if the lookup key value for the file is not a Symbol
class NonSymbolLookupOnError < TypeError
include Kiba::Extend::ErrMod
# @param filekey [Symbol] registry entry key having the non-symbol
# `lookup_on` value
def initialize(filekey, for_job)
@filekey = filekey
@for_job = for_job
@msg = "The `lookup_on` value in the registry entry hash for "\
":#{filekey} is not a Ruby Symbol. "\
"Prepend a : to the field name to fix."
super(msg)
end

def formatted
<<~STR
JOB FAILED: LOOKUP FILE SETUP ERROR FOR: #{for_job}
#{msg}
STR
end

private

attr_reader :filekey, :for_job, :msg
end

class ProjectSettingUndefinedError < StandardError
include Kiba::Extend::ErrMod
end
Expand Down
25 changes: 17 additions & 8 deletions lib/kiba/extend/jobs/base_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ class BaseJob
# running any necessary jobs to create sources and/or lookups needed
# by the job. :run does all of the above and runs the job. Since 4.0.0
def initialize(files:, transformer:, mode: :run)
@destination_key = files[:destination].is_a?(Symbol) ?
files[:destination] :
files[:destination].first

if caller(2, 5).join(" ")["block in handle_requirements"]
@dependency = true
end
Expand Down Expand Up @@ -60,6 +64,8 @@ def run

private

attr_reader :destination_key

def job_data
@files[:destination].first.data
end
Expand All @@ -70,7 +76,8 @@ def setup_files(files)
tmp = {}
files.each do |type, arr|
meth = Kiba::Extend.registry.method("as_#{type}")
tmp[type] = [arr].flatten.map { |key| prep_file(meth, key) }
tmp[type] = [arr].flatten
.map { |key| prep_file(meth, key, destination_key) }
end
tmp
end
Expand All @@ -90,13 +97,15 @@ def pre_process
end
end

def prep_file(meth, key)
meth.call(key)
# rubocop:todo Layout/LineLength
rescue Kiba::Extend::Registry::FileRegistry::KeyNotRegisteredError => err
# rubocop:enable Layout/LineLength
puts "JOB FAILED: TRANSFORM ERROR IN: #{err.calling_job}"
err.info
def prep_file(meth, key, for_job)
meth.call(key, for_job)
rescue Kiba::Extend::ErrMod => err
if err.respond_to?(:formatted)
puts err.formatted
else
puts "JOB FAILED: TRANSFORM ERROR IN: #{err.calling_job}"
err.info
end
exit
end

Expand Down
58 changes: 38 additions & 20 deletions lib/kiba/extend/registry/file_registry.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

# rubocop:todo Layout/LineLength

require "dry-container"

require_relative "registered_source"
Expand All @@ -13,10 +11,12 @@
module Kiba
module Extend
module Registry
# Transforms a file_registry hash into an object that can return source, lookup, or destination
# config for that file, for passing to jobs
# Transforms a file_registry hash into an object that can return
# source, lookup, or destination config for that file, for
# passing to jobs
#
# An example of a file registry setup in a project can be found at:
# An example of a file registry setup in a project can be found
# at:
# https://github.com/lyrasis/fwm-cspace-migration/blob/main/lib/fwm/registry_data.rb
class FileRegistry
include Dry::Container::Mixin
Expand All @@ -39,26 +39,41 @@ def initialize(key, type = nil)
end
end

# @param filekey [String, Symbol] file registry key for file to be used as destination
# @param filekey [String, Symbol] file registry key for file
# to be used as destination
# @return [Kiba::Extend::Registry::RegisteredDestination]
def as_destination(filekey)
RegisteredDestination.new(key: filekey, data: lookup(filekey))
def as_destination(filekey, for_job)
RegisteredDestination.new(
key: filekey,
data: lookup(filekey),
for_job: for_job
)
rescue KeyNotRegisteredError => err
raise KeyNotRegisteredError.new(err.key, :destination)
end

# @param filekey [String, Symbol] file registry key for file to be used as a lookup source
# @param filekey [String, Symbol] file registry key for file to be used
# as a lookup source
# @return [Kiba::Extend::Registry::RegisteredLookup]
def as_lookup(filekey)
RegisteredLookup.new(key: filekey, data: lookup(filekey))
def as_lookup(filekey, for_job)
RegisteredLookup.new(
key: filekey,
data: lookup(filekey),
for_job: for_job
)
rescue KeyNotRegisteredError => err
raise KeyNotRegisteredError.new(err.key, :lookup)
end

# @param filekey [String, Symbol] file registry key for file to be used as a source
# @param filekey [String, Symbol] file registry key for file to be used
# as a source
# @return [Kiba::Extend::Registry::RegisteredSource]
def as_source(filekey)
RegisteredSource.new(key: filekey, data: lookup(filekey))
def as_source(filekey, for_job)
RegisteredSource.new(
key: filekey,
data: lookup(filekey),
for_job: for_job
)
rescue KeyNotRegisteredError => err
raise KeyNotRegisteredError.new(err.key, :source)
end
Expand All @@ -68,15 +83,18 @@ def entries
@entries ||= populate_entries
end

# Convenience method combining the steps of transforming initial registry entry hashes
# into FileRegistryEntry objects, and then making the registry immutable for the
# rest of the application's run. `:freeze` is from dry-container.
# Convenience method combining the steps of transforming
# initial registry entry hashes into FileRegistryEntry
# objects, and then making the registry immutable for the
# rest of the application's run. `:freeze` is from
# dry-container.
def finalize
transform
freeze
end

# Transforms registered file hashes into Kiba::Extend::Registry::FileRegistryEntry objects
# Transforms registered file hashes into
# {Kiba::Extend::Registry::FileRegistryEntry} objects
def transform
each { |key, val| decorate(key) { FileRegistryEntry.new(val) } }
@entries = populate_entries
Expand Down Expand Up @@ -123,7 +141,8 @@ def verify_supplied_files_exist
end.map(&:path).uniq.each do |file|
next if file.exist?

puts %(#{Kiba::Extend.warning_label}: Missing supplied file: #{file})
puts "#{Kiba::Extend.warning_label}: Missing supplied "\
"file: #{file}"
end
end

Expand All @@ -134,4 +153,3 @@ def validator
end
end
end
# rubocop:enable Layout/LineLength
2 changes: 1 addition & 1 deletion lib/kiba/extend/registry/registered_destination.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def initialize(entry_key)
end
end

def initialize(key:, data:)
def initialize(key:, data:, for_job:)
super
fail SuppliedEntryError.new(key) if supplied
end
Expand Down
24 changes: 15 additions & 9 deletions lib/kiba/extend/registry/registered_file.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# frozen_string_literal: true

# rubocop:todo Layout/LineLength

module Kiba
module Extend
module Registry
# Abstract base class defining interface for destination files, lookup files, and source files
# returned by {Kiba::Extend::FileRegistry}
# Abstract base class defining interface for destination files,
# lookup files, and source files returned by
# {Kiba::Extend::FileRegistry}
class RegisteredFile
# Exception raised if no path is given in {FileRegistry} hash
class NoFilePathError < StandardError
# @param filekey [Symbol] key for which a file path was not found in {Kiba::Extend::FileRegistry}
# @param filekey [Symbol] key for which a file path was not found in
# {Kiba::Extend::FileRegistry}
def initialize(filekey)
msg = "No file path for :#{filekey} is recorded in file registry hash"
msg = "No file path for :#{filekey} is recorded in file registry "\
"hash"
super(msg)
end
end
Expand All @@ -24,13 +25,17 @@ def initialize(filekey)
:desc

# @param key [Symbol] the {Kiba::Extend::FileRegistry} lookup key
# @param data [Hash] the hash of data for the file from {Kiba::Extend::FileRegistry}
def initialize(key:, data:)
# @param data [Hash] the hash of data for the file from
# {Kiba::Extend::FileRegistry}
# @param for_job [Symbol] registry entry job key of the job for which
# this registered file is being prepared
def initialize(key:, data:, for_job:)
raise FileNotRegisteredError, key unless data
raise NoFilePathError, key if data.errors.keys.any?(:missing_path)

@key = key
@data = data
@for_job = for_job
@path = data.path.to_s
@dest_class = data.dest_class
@dest_opt = data.dest_opt
Expand All @@ -47,6 +52,8 @@ def src_class

private

attr_reader :for_job

# returns equivalent source class for given destination class
def dest_src
src = dest_class.as_source_class
Expand All @@ -58,4 +65,3 @@ def dest_src
end
end
end
# rubocop:enable Layout/LineLength
47 changes: 13 additions & 34 deletions lib/kiba/extend/registry/registered_lookup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,30 @@
module Kiba
module Extend
module Registry
# Value object representing a file registered in a {Kiba::Extend::FileRegistry} that is being
# called into another job as a lookup table
# Value object representing a file registered in a
# {Kiba::Extend::FileRegistry} that is being called into
# another job as a lookup table
#
# Assumes this file will be used to build a {Kiba::Extend::Lookup}
class RegisteredLookup < RegisteredFile
include RequirableFile

class CannotBeUsedAsLookupError < TypeError
include Kiba::Extend::ErrMod
def initialize(klass)
super("The result of a registry entry with a #{klass} "\
"dest_class cannot be used as source file in a job")
end
end

# Exception raised if {Kiba::Extend::FileRegistry} contains no lookup key for file
class NoLookupKeyError < NameError
include Kiba::Extend::ErrMod
# @param filekey [Symbol] key not found in {Kiba::Extend::FileRegistry}
def initialize(filekey)
msg = "No lookup key column found for :#{filekey} in file registry hash"
super(msg)
end
end

# Exception raised if the lookup key value for the file is not a Symbol
class NonSymbolLookupKeyError < TypeError
include Kiba::Extend::ErrMod
# @param filekey [Symbol] key not found in {Kiba::Extend::FileRegistry}
def initialize(filekey)
msg = "Lookup key found for :#{filekey} is not a Ruby Symbol. Prepend a : to the field name to fix."
super(msg)
end
end

# @param key [Symbol] file key from {FileRegistry} data hash
# @param data [Hash] file data from {FileRegistry}
def initialize(key:, data:)
# @param for_job [Symbol] registry entry job key of the job for which
# this registered file is being prepared
def initialize(key:, data:, for_job:)
super
unless src_class.respond_to?(:is_lookupable?)
fail CannotBeUsedAsLookupError.new(src_class)
fail Kiba::Extend::JobCannotBeUsedAsLookupError.new(
key, src_class, for_job
)
end
unless lookup_on
fail Kiba::Extend::NoLookupOnError.new(key, for_job)
end
fail NoLookupKeyError, @key unless lookup_on
unless lookup_on.is_a?(Symbol)
fail NonSymbolLookupKeyError, @key
fail Kiba::Extend::NonSymbolLookupOnError.new(key, for_job)
end
end

Expand Down
Loading