Skip to content

Commit e0b8659

Browse files
committed
Schema v1 to Aardvark migrator
- Handle elements without crosswalk (via lookup tables) - Support migrating collections in dct_isPartOf_sm - Convert single to multivalued fields where appropriate - Retain custom fields and remove deprecated fields Closes #121
1 parent c2c5427 commit e0b8659

4 files changed

Lines changed: 129 additions & 22 deletions

File tree

lib/geo_combine/migrators/v1_aardvark_migrator.rb

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,78 @@
22

33
module GeoCombine
44
module Migrators
5-
# TODO: WARNING! This class is not fully implemented and should not be used in
6-
# production. See https://github.com/OpenGeoMetadata/GeoCombine/issues/121
7-
# for remaining work.
8-
#
95
# migrates the v1 schema to the aardvark schema
106
class V1AardvarkMigrator
117
attr_reader :v1_hash
128

139
# @param v1_hash [Hash] parsed json in the v1 schema
14-
def initialize(v1_hash:)
10+
# @param collection_id_map [Hash] a hash mapping collection names to ids for converting dct_isPartOf_sm
11+
def initialize(v1_hash:, collection_id_map: {})
1512
@v1_hash = v1_hash
13+
@v2_hash = v1_hash
14+
@collection_id_map = collection_id_map
1615
end
1716

1817
def run
19-
v2_hash = convert_keys
20-
v2_hash['gbl_mdVersion_s'] = 'Aardvark'
21-
v2_hash
18+
# Return unchanged if already in the aardvark schema
19+
return @v2_hash if @v2_hash['gbl_mdVersion_s'] == 'Aardvark'
20+
21+
# Convert the record
22+
convert_keys
23+
convert_single_to_multi_valued_fields
24+
convert_non_crosswalked_fields
25+
remove_deprecated_fields
26+
27+
# Mark the record as converted and return it
28+
@v2_hash['gbl_mdVersion_s'] = 'Aardvark'
29+
@v2_hash
2230
end
2331

32+
# Namespace and URI changes to fields
2433
def convert_keys
25-
v1_hash.transform_keys do |k|
34+
@v2_hash.transform_keys! do |k|
2635
SCHEMA_FIELD_MAP[k] || k
2736
end
2837
end
2938

39+
# Fields that need to be converted from single to multi-valued
40+
def convert_single_to_multi_valued_fields
41+
@v2_hash = @v2_hash.each_with_object({}) do |(k, v), h|
42+
h[k] = if !v.is_a?(Array) && k.match?(/.*_[s|i]m/)
43+
[v]
44+
else
45+
v
46+
end
47+
end
48+
end
49+
50+
# Convert non-crosswalked fields via lookup tables
51+
def convert_non_crosswalked_fields
52+
# Keys may or may not include whitespace, so we normalize them.
53+
# Resource class is required so we default to "Other"; resource type is not required.
54+
@v2_hash['gbl_resourceClass_s'] = RESOURCE_CLASS_MAP[@v1_hash['dc_type_s'].gsub(/\s+/, '')] || ['Other']
55+
resource_type = RESOURCE_TYPE_MAP[@v1_hash['layer_geom_type_s'].gsub(/\s+/, '')]
56+
@v2_hash['gbl_resourceType_s'] = resource_type unless resource_type.nil?
57+
58+
# If the user specified a collection id map, use it to convert the collection names to ids
59+
is_part_of = @v1_hash['dct_isPartOf_sm']&.map { |name| @collection_id_map[name] }&.compact
60+
if is_part_of.empty?
61+
@v2_hash.delete('dct_isPartOf_sm')
62+
else
63+
@v2_hash['dct_isPartOf_sm'] = is_part_of
64+
end
65+
end
66+
67+
# Remove fields that are no longer used
68+
def remove_deprecated_fields
69+
@v2_hash = @v2_hash.except(*SCHEMA_FIELD_MAP.keys, 'dc_type_s', 'layer_geom_type_s')
70+
end
71+
3072
SCHEMA_FIELD_MAP = {
3173
'dc_title_s' => 'dct_title_s', # new namespace
3274
'dc_description_s' => 'dct_description_sm', # new namespace; single to multi-valued
3375
'dc_language_s' => 'dct_language_sm', # new namespace; single to multi-valued
34-
'dc_language_sm' => 'dct_language_sm', # new namespace; single to multi-valued
76+
'dc_language_sm' => 'dct_language_sm', # new namespace
3577
'dc_creator_sm' => 'dct_creator_sm', # new namespace
3678
'dc_publisher_s' => 'dct_publisher_sm', # new namespace; single to multi-valued
3779
'dct_provenance_s' => 'schema_provider_s', # new URI name
@@ -47,6 +89,30 @@ def convert_keys
4789
'geoblacklight_version' => 'gbl_mdVersion_s', # new URI name
4890
'suppressed_b' => 'gbl_suppressed_b' # new namespace
4991
}.freeze
92+
93+
# Map Dublin Core types to Aardvark resource class sets
94+
# See: https://github.com/OpenGeoMetadata/opengeometadata.github.io/blob/main/docs/ogm-aardvark/resource-class.md
95+
RESOURCE_CLASS_MAP = {
96+
'Collection' => ['Collections'],
97+
'Dataset' => ['Datasets'],
98+
'Image' => ['Imagery'],
99+
'InteractiveResource' => ['Websites'],
100+
'PhysicalObject' => ['Maps'],
101+
'Service' => ['Web services'],
102+
'StillImage' => ['Imagery']
103+
}.freeze
104+
105+
# Map geometry types to Aardvark resource type sets
106+
# See: https://github.com/OpenGeoMetadata/opengeometadata.github.io/blob/main/docs/ogm-aardvark/resource-type.md
107+
RESOURCE_TYPE_MAP = {
108+
'Polygon' => ['Polygon data'],
109+
'Raster' => ['Raster data'],
110+
'Line' => ['Line data'],
111+
'Point' => ['Point data'],
112+
'PaperMap' => ['Physical maps'],
113+
'MultiPolygon' => ['Polygon data'],
114+
'MultiLineString' => ['Line data']
115+
}.freeze
50116
end
51117
end
52118
end

spec/fixtures/docs/full_geoblacklight.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
"dct_spatial_sm":[
2929
"Uganda"
3030
],
31+
"dct_isPartOf_sm":[
32+
"Uganda GIS Maps and Data, 2000-2010"
33+
],
3134
"solr_geom":"ENVELOPE(29.572742, 35.000308, 4.234077, -1.478794)",
3235
"solr_year_i":2005
3336
}

spec/fixtures/docs/full_geoblacklight_aardvark.json

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
11
{
22
"gbl_mdVersion_s":"Aardvark",
3-
"dct_identifier_sm":"http://purl.stanford.edu/cz128vq0535",
3+
"dct_identifier_sm":[
4+
"http://purl.stanford.edu/cz128vq0535"
5+
],
46
"dct_title_s":"2005 Rural Poverty GIS Database: Uganda",
5-
"dct_description_sm":"This polygon shapefile contains 2005 poverty data for 855 rural subcounties in Uganda. These data are intended for researchers, students, policy makers and the general public for reference and mapping purposes, and may be used for basic applications such as viewing, querying, and map output production.",
7+
"dct_description_sm":[
8+
"This polygon shapefile contains 2005 poverty data for 855 rural subcounties in Uganda. These data are intended for researchers, students, policy makers and the general public for reference and mapping purposes, and may be used for basic applications such as viewing, querying, and map output production."
9+
],
610
"dct_accessRights_s":"Public",
711
"schema_provider_s":"Stanford",
812
"dct_references_s":"{\"http://schema.org/url\":\"http://purl.stanford.edu/cz128vq0535\",\"http://schema.org/downloadUrl\":\"http://stacks.stanford.edu/file/druid:cz128vq0535/data.zip\",\"http://www.loc.gov/mods/v3\":\"http://purl.stanford.edu/cz128vq0535.mods\",\"http://www.isotc211.org/schemas/2005/gmd/\":\"http://opengeometadata.stanford.edu/metadata/edu.stanford.purl/druid:cz128vq0535/iso19139.xml\",\"http://www.w3.org/1999/xhtml\":\"http://opengeometadata.stanford.edu/metadata/edu.stanford.purl/druid:cz128vq0535/default.html\",\"http://www.opengis.net/def/serviceType/ogc/wfs\":\"https://geowebservices.stanford.edu/geoserver/wfs\",\"http://www.opengis.net/def/serviceType/ogc/wms\":\"https://geowebservices.stanford.edu/geoserver/wms\"}",
913
"gbl_wxsIdentifier_s":"druid:cz128vq0535",
1014
"id":"stanford-cz128vq0535",
11-
"layer_geom_type_s":"Polygon",
15+
"gbl_resourceType_s": [
16+
"Polygon data"
17+
],
1218
"gbl_mdModified_dt":"2015-01-13T18:46:38Z",
1319
"dct_format_s":"Shapefile",
14-
"dct_language_sm":"English",
15-
"dc_type_s":"Dataset",
16-
"dct_publisher_sm":"Uganda Bureau of Statistics",
20+
"dct_language_sm":[
21+
"English"
22+
],
23+
"gbl_resourceClass_s":[
24+
"Datasets"
25+
],
26+
"dct_publisher_sm":[
27+
"Uganda Bureau of Statistics"
28+
],
1729
"dct_creator_sm":[
1830
"Uganda Bureau of Statistics"
1931
],
@@ -29,5 +41,7 @@
2941
"Uganda"
3042
],
3143
"solr_geom":"ENVELOPE(29.572742, 35.000308, 4.234077, -1.478794)",
32-
"gbl_indexYear_im":2005
44+
"gbl_indexYear_im":[
45+
2005
46+
]
3347
}

spec/lib/geo_combine/migrators/v1_aardvark_migrator_spec.rb

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,41 @@
66
include JsonDocs
77

88
describe '#run' do
9-
it 'migrates keys' do
9+
it 'migrates fields to new names and types' do
1010
input_hash = JSON.parse(full_geoblacklight)
11-
# TODO: Note that this fixture has not yet been fully converted to
12-
# aardvark. See https://github.com/OpenGeoMetadata/GeoCombine/issues/121
13-
# for remaining work.
1411
expected_output = JSON.parse(full_geoblacklight_aardvark)
1512
expect(described_class.new(v1_hash: input_hash).run).to eq(expected_output)
1613
end
1714

15+
it 'removes deprecated fields' do
16+
input_hash = JSON.parse(full_geoblacklight)
17+
output = described_class.new(v1_hash: input_hash).run
18+
expect(output.keys).not_to include(described_class::SCHEMA_FIELD_MAP.keys)
19+
expect(output.keys).not_to include('dc_type_s')
20+
expect(output.keys).not_to include('layer_geom_type_s')
21+
end
22+
23+
it 'leaves custom fields unchanged' do
24+
input_hash = JSON.parse(full_geoblacklight)
25+
input_hash['custom_field'] = 'custom_value'
26+
output = described_class.new(v1_hash: input_hash).run
27+
expect(output['custom_field']).to eq('custom_value')
28+
end
29+
1830
context 'when the given record is already in aardvark schema' do
19-
xit 'returns the record unchanged'
31+
it 'returns the record unchanged' do
32+
input_hash = JSON.parse(full_geoblacklight_aardvark)
33+
expect(described_class.new(v1_hash: input_hash).run).to eq(input_hash)
34+
end
35+
end
36+
37+
context 'when the user supplies a mapping for collection names to ids' do
38+
it 'converts the collection names to ids' do
39+
input_hash = JSON.parse(full_geoblacklight)
40+
collection_id_map = { 'Uganda GIS Maps and Data, 2000-2010' => 'stanford-rb371kw9607' }
41+
output = described_class.new(v1_hash: input_hash, collection_id_map: collection_id_map).run
42+
expect(output['dct_isPartOf_sm']).to eq(['stanford-rb371kw9607'])
43+
end
2044
end
2145
end
2246
end

0 commit comments

Comments
 (0)