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

Grouped fields with date details #173

Merged
merged 6 commits into from
Feb 6, 2024
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ This project bumps the version number for any changes (including documentation u

## [Unreleased] - i.e. pushed to main branch but not yet tagged as a release

## [5.0.5] - 2024-02-02
- For `date details` batch mode: add support for ingesting grouped fields at the same level as the structured date group. To find the group level of the structured date group, find the `date_field_group` value in the relevant CSV ingest template. If that field has a `REPEATING FIELD GROUP` value in the template, any other field values with the same `REPEATING FIELD GROUP` value can be ingested together.

## [5.0.4] - 2024-02-01
- Ensure `shortid` field is populated when mapping date details for authorities

Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GIT
PATH
remote: .
specs:
collectionspace-mapper (5.0.4)
collectionspace-mapper (5.0.5)
activesupport (= 7.0.4.3)
chronic
collectionspace-client (~> 0.15.0)
Expand Down
14 changes: 12 additions & 2 deletions lib/collectionspace/mapper/authority.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ module CollectionSpace
module Mapper
# special behavior for authority mapping
module Authority
def special_mappings
module_function

def extended(mod)
if mod.respond_to?(:add_mapping)
special_mappings(mod).each do |mapping|
mod.add_mapping(mapping)
end
end
end

def special_mappings(mod)
[
{
fieldname: "shortIdentifier",
namespace: handler.record.common_namespace,
namespace: mod.handler.record.common_namespace,
data_type: "string",
xpath: [],
required: "not in input data",
Expand Down
25 changes: 14 additions & 11 deletions lib/collectionspace/mapper/column_mappings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,23 @@ class ColumnMappings
include Enumerable
extend Forwardable

attr_reader :handler

def_delegators :@all, :each, :reject!

# @param mappings [Array<Hash>] from record mapper JSON file
# @param hander [CollectionSpace::Mapper::DataHandler]
def initialize(mappings:, handler:)
@handler = handler
handler.record.extensions.each { |ext| extend ext }
@transforms = handler.batch.transforms

@all = []
@lkup = {}
handler.record.extensions.each { |ext| extend ext }
mappings.each { |mapping| add_mapping(mapping) }

special_mappings.each { |mapping| add_mapping(mapping) }
# binding.pry
# special_mappings.each { |mapping| add_mapping(mapping) }
end

def <<(mapping)
Expand All @@ -47,21 +50,21 @@ def required_columns
all.select(&:required?)
end

private

attr_reader :handler, :transforms, :all, :lkup

def add_mapping(mapping)
mapobj = CollectionSpace::Mapper::ColumnMapping.new(
mapping: mapping
)
all << mapobj
lkup[mapobj.datacolumn] = mapobj
@all << mapobj
@lkup[mapobj.datacolumn] = mapobj
end

def special_mappings
[]
end
private

attr_reader :transforms, :all, :lkup

# def special_mappings
# []
# end
end
end
end
14 changes: 8 additions & 6 deletions lib/collectionspace/mapper/data_mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def set_identifier_value
end
thexpath = "//#{mapping.namespace}/#{mapping.fieldname}"
value = doc.xpath(thexpath).first

value = value.text
response.add_identifier(value)
end
Expand All @@ -53,22 +54,23 @@ def set_relation_id
end

def add_short_id
ns = handler.record.common_namespace
targetnode = doc.xpath("/document/#{ns}").first
child = Nokogiri::XML::Node.new("shortIdentifier", doc)

shortid =
if response.transformed_data.key?("shortidentifier")
response.transformed_data["shortidentifier"]
response.transformed_data["shortidentifier"][0]
else
term = response.split_data["termdisplayname"][0]
CollectionSpace::Mapper::Identifiers::AuthorityShortIdentifier.call(
term
)
end
response.add_identifier(shortid)
return if response.transformed_data.key?("shortidentifier")

ns = handler.record.common_namespace
targetnode = doc.xpath("/document/#{ns}").first
child = Nokogiri::XML::Node.new("shortIdentifier", doc)
child.content = shortid
targetnode.add_child(child)
response.add_identifier(shortid)
end

def map(xpath)
Expand Down
29 changes: 19 additions & 10 deletions lib/collectionspace/mapper/date_details.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
module CollectionSpace
module Mapper
module DateDetails
# Methods used in ColumnMappings
def special_mappings
module_function

def extended(mod)
if mod.respond_to?(:add_mapping)
special_mappings(mod).each do |mapping|
mod.add_mapping(mapping)
end
end
end

def special_mappings(mod)
base = [
{
fieldname: "date_field_group",
namespace: handler.record.common_namespace,
namespace: mod.handler.record.common_namespace,
data_type: "string",
xpath: [],
required: "y",
Expand All @@ -19,7 +28,7 @@ def special_mappings
},
{
fieldname: "scalarValuesComputed",
namespace: handler.record.common_namespace,
namespace: mod.handler.record.common_namespace,
data_type: "string",
xpath: [],
required: "y",
Expand All @@ -29,10 +38,10 @@ def special_mappings
transforms: {special: ["boolean"]}
}
]
[base, vocab_mappings, optionlist_mappings].flatten
[base, vocab_mappings(mod), optionlist_mappings(mod)].flatten
end

def vocab_mappings
def vocab_mappings(mod)
{
"dateLatestQualifierUnit" => "datequalifier",
"dateLatestEra" => "dateera",
Expand All @@ -43,7 +52,7 @@ def vocab_mappings
}.map do |fieldname, vocab|
{
fieldname: fieldname,
namespace: handler.record.common_namespace,
namespace: mod.handler.record.common_namespace,
data_type: "string",
xpath: [],
required: "n",
Expand All @@ -57,14 +66,14 @@ def vocab_mappings
end
end

def optionlist_mappings
def optionlist_mappings(mod)
{
"dateLatestQualifier" => "dateQualifiers",
"dateEarliestSingleQualifier" => "dateQualifiers"
}.map do |fieldname, vocab|
{
fieldname: fieldname,
namespace: handler.record.common_namespace,
namespace: mod.handler.record.common_namespace,
data_type: "string",
xpath: [],
required: "n",
Expand Down Expand Up @@ -93,7 +102,7 @@ def ensure_target_field_exists(response)
"date_field_group value `#{val}` is not a known structured date "\
"field group in a #{handler.record.recordtype} record. You must "\
"enter a field that appears as a column header in the CSV "\
"template for this record type."
"template for this record type. Case sensitive!"
)
end

Expand Down
72 changes: 69 additions & 3 deletions lib/collectionspace/mapper/date_details/data_prepper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,39 @@ def initialize(data, handler)
CollectionSpace::Mapper.structured_date_detailed_fields
.map { |field| [field.downcase, field] }
.to_h
@authority_data = nil
@grouped_data = nil
end

def prep
unless handler.grouped_fields
handler.check_fields(response.merged_data)
end
if handler.authority_handler
extract_authority_data
auth_prepped = handler.authority_handler
.prep(authority_data)
end
if handler.grouped_handler
extract_grouped_data
grouped_prepped = handler.grouped_handler.prep(grouped_data)
end
split_data
transform_data
handle_term_fields
extract_date_fields
clean_transformed
readd_id
combine_data_fields
merge_authority_data(auth_prepped) if authority_data
merge_grouped_data(grouped_prepped) if grouped_data
response
end

private

attr_reader :id_field, :target, :target_mapping, :date_fields,
:date_field_lookup
:date_field_lookup, :grouped_data, :authority_data

def date_data
@date_data ||= response.merged_data
Expand All @@ -46,6 +62,33 @@ def non_date_data
.reject { |field, _value| date_fields.any?(field) }
end

def extract_authority_data
@authority_data = {}
copy_id_field_to(authority_data)
end

def extract_grouped_data
@grouped_data = {}
copy_id_field_to(grouped_data)
move_grouped_fields_to_grouped_data
end

def copy_id_field_to(data_var)
if response.merged_data.key?(id_field)
data_var[id_field] = response.merged_data[id_field]
elsif response.merged_data.key?("termdisplayname")
data_var["termdisplayname"] =
response.merged_data["termdisplayname"]
end
end

def move_grouped_fields_to_grouped_data
handler.grouped_fields.each do |field|
grouped_data[field] = response.merged_data[field]
response.merged_data.delete(field)
end
end

def split_data
response.merged_data.each do |field, val|
splitval = if identifier?(field)
Expand Down Expand Up @@ -139,19 +182,42 @@ def clean_transformed
def readd_id
id = case id_field
when "shortidentifier"
readd_authority_id
[authority_short_id]
else
response.split_data[id_field]
end
response.transformed_data[id_field] = id
end

def readd_authority_id
def authority_short_id
term = response.split_data["termdisplayname"][0]
CollectionSpace::Mapper::Identifiers::AuthorityShortIdentifier.call(
term
)
end

def merge_authority_data(auth_prepped)
added_paths = auth_prepped.xpaths
.reject { |path, xpath| response.xpaths.key?(path) }

added_paths.each do |path, xpath|
response.xpaths[path] = xpath
response.combined_data[path] = auth_prepped.combined_data[path]
end
end

def merge_grouped_data(grouped_prepped)
path = handler.target_path

response.combined_data[path].merge!(
grouped_prepped.combined_data[path]
)
grouped_prepped.errors.each { |err| response.add_error(err) }
grouped_prepped.terms.each { |term| response.add_term(term) }
grouped_prepped.warnings.each do |warning|
response.add_warning(warning)
end
end
end
end
end
Expand Down
Loading
Loading