cocina-models 0.121.0 → 0.123.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/AGENTS.md +2 -2
- data/Gemfile.lock +22 -6
- data/README.md +1 -1
- data/bin/enhance-report-csv +3 -5
- data/bin/validate-data +18 -6
- data/cocina-models.gemspec +1 -0
- data/description_types.yml +0 -2
- data/docs/description_types.md +0 -2
- data/identifier_source_codes.yml +210 -0
- data/lib/cocina/models/mapping/from_mods/name_builder.rb +1 -1
- data/lib/cocina/models/validators/composite_description_validator.rb +7 -1
- data/lib/cocina/models/validators/description_date_time_visitor_validator.rb +18 -9
- data/lib/cocina/models/validators/description_event_date_visitor_validator.rb +38 -0
- data/lib/cocina/models/validators/description_form_resource_type_visitor_validator.rb +46 -0
- data/lib/cocina/models/validators/description_identifier_source_code_visitor_validator.rb +41 -0
- data/lib/cocina/models/validators/description_location_source_code_visitor_validator.rb +43 -0
- data/lib/cocina/models/validators/description_role_source_code_visitor_validator.rb +44 -0
- data/lib/cocina/models/validators/description_subject_temporal_encoding_visitor_validator.rb +43 -0
- data/lib/cocina/models/validators/marc_relator_role_validator.rb +83 -0
- data/lib/cocina/models/validators/validator.rb +2 -1
- data/lib/cocina/models/version.rb +1 -1
- data/location_source_codes.yml +483 -0
- data/resource_type_values.yml +30 -0
- data/schema.json +293 -9
- data/temporal_subject_encoding_codes.yml +8 -0
- metadata +26 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 00e220a27c041178441f3a9372469f6f4aeacd6b9cf73bec45b36d0dfc8e8f1a
|
|
4
|
+
data.tar.gz: e6b6e939d33c2bbc9e88c99bdfef996b23d40df59667cf9f7c1b63b3b2a2b6ba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8fa102a60d4d216b439f514051d34afd07e57105afefd751d1c1b8f07411b876c5475237a0a577fb1240ac6eb564918ebf9a372d3596107f2787d041de8c9f77
|
|
7
|
+
data.tar.gz: 7eb1f0771c848747c833437e3aeb4fb616de5716bae81a8f1ba83a048ba8364953eb47332bae622b91b830807eb39395d0a186a8347605bed662ebc4ecec4807
|
data/.circleci/config.yml
CHANGED
data/AGENTS.md
CHANGED
|
@@ -22,10 +22,10 @@ Run `pv --version`. If pv is not installed, tell the user:
|
|
|
22
22
|
|
|
23
23
|
### Output format (always apply)
|
|
24
24
|
|
|
25
|
-
Every jq query produced by this skill **must output a CSV line** using `@csv`. The **first field must always be the external identifier** (`externalIdentifier`). Additional fields follow based on the user's query. Example:
|
|
25
|
+
Every jq query produced by this skill **must output a CSV line** using `@csv`. The **first field must always be the external identifier** (`externalIdentifier`). Additional fields follow based on the user's query. By default, multiple values should be joined by " | ". Example:
|
|
26
26
|
|
|
27
27
|
```
|
|
28
|
-
"druid:bc123df4567","some value
|
|
28
|
+
"druid:bc123df4567","some value | another value"
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Use `[.externalIdentifier, ...] | @csv` as the output expression. Apply this constraint automatically — do not ask the user whether to include the external identifier.
|
data/Gemfile.lock
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
cocina-models (0.
|
|
4
|
+
cocina-models (0.123.0)
|
|
5
5
|
activesupport
|
|
6
|
+
cocina_display
|
|
6
7
|
deprecation
|
|
7
8
|
dry-struct (~> 1.0)
|
|
8
9
|
dry-types (~> 1.1)
|
|
@@ -36,6 +37,14 @@ GEM
|
|
|
36
37
|
base64 (0.3.0)
|
|
37
38
|
bigdecimal (4.1.2)
|
|
38
39
|
builder (3.3.0)
|
|
40
|
+
cocina_display (2.6.0)
|
|
41
|
+
activesupport (>= 7)
|
|
42
|
+
edtf (~> 3.2)
|
|
43
|
+
geo_coord (~> 0.2)
|
|
44
|
+
i18n
|
|
45
|
+
iso8601 (~> 0.13.0)
|
|
46
|
+
janeway-jsonpath (>= 0.6, < 2)
|
|
47
|
+
zeitwerk (~> 2.7)
|
|
39
48
|
concurrent-ruby (1.3.6)
|
|
40
49
|
connection_pool (3.0.2)
|
|
41
50
|
csv (3.3.5)
|
|
@@ -81,6 +90,7 @@ GEM
|
|
|
81
90
|
logger
|
|
82
91
|
faraday-net_http (3.4.4)
|
|
83
92
|
net-http (~> 0.5)
|
|
93
|
+
geo_coord (0.2.0)
|
|
84
94
|
i18n (1.14.8)
|
|
85
95
|
concurrent-ruby (~> 1.0)
|
|
86
96
|
ice_nine (0.11.2)
|
|
@@ -90,7 +100,9 @@ GEM
|
|
|
90
100
|
prism (>= 1.3.0)
|
|
91
101
|
rdoc (>= 4.0.0)
|
|
92
102
|
reline (>= 0.4.2)
|
|
93
|
-
|
|
103
|
+
iso8601 (0.13.0)
|
|
104
|
+
janeway-jsonpath (1.0.0)
|
|
105
|
+
json (2.19.9)
|
|
94
106
|
jsonschema_rs (0.46.5-arm64-darwin)
|
|
95
107
|
bigdecimal (>= 3.1, < 5)
|
|
96
108
|
jsonschema_rs (0.46.5-x86_64-linux)
|
|
@@ -219,8 +231,9 @@ CHECKSUMS
|
|
|
219
231
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
220
232
|
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
|
221
233
|
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
|
222
|
-
bundler (4.0.
|
|
223
|
-
cocina-models (0.
|
|
234
|
+
bundler (4.0.14) sha256=d09a0a965cf772266a7e49e83610be7c2f4e49e61134c42a56804bb383cc24b8
|
|
235
|
+
cocina-models (0.123.0)
|
|
236
|
+
cocina_display (2.6.0) sha256=a30e4bd638023371985ab641164e4dbbb12fe9a669a168c1b8e2eac2e37739f4
|
|
224
237
|
concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
|
|
225
238
|
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
226
239
|
csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f
|
|
@@ -240,11 +253,14 @@ CHECKSUMS
|
|
|
240
253
|
erb (6.0.4) sha256=38e3803694be357fe2bfe312487c74beaf9fb4e5beb3e22498952fe1645b95d9
|
|
241
254
|
faraday (2.14.2) sha256=73ccb9994a9e8648f010e32eca2ae82e41c57860aa10932cda29418b9e0223ad
|
|
242
255
|
faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
|
|
256
|
+
geo_coord (0.2.0) sha256=ae4e2dc5799deafa4db9138f3d7e85cf5e7dbd00b3b8395f1e1dbd34e007d7e8
|
|
243
257
|
i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
|
|
244
258
|
ice_nine (0.11.2) sha256=5d506a7d2723d5592dc121b9928e4931742730131f22a1a37649df1c1e2e63db
|
|
245
259
|
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
|
|
246
260
|
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
|
247
|
-
|
|
261
|
+
iso8601 (0.13.0) sha256=298c2b15b7be5fa95a1372813d36a2257656cd8e906dfbc1f5cb409851425aa2
|
|
262
|
+
janeway-jsonpath (1.0.0) sha256=c8293f009f2aea9487ddee3067ca735a1f758eb1c8834ff4fab3ffd06c56d0a3
|
|
263
|
+
json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a
|
|
248
264
|
jsonschema_rs (0.46.5-arm64-darwin) sha256=e80414ed67f0956d3e06474a2fa076fc4a7b722f00e5d7142b70289c016ac6f1
|
|
249
265
|
jsonschema_rs (0.46.5-x86_64-linux) sha256=345c65ec7a5abf8879b9c9356752f0fdf4c9926f6480458fc32803a871b5cbb3
|
|
250
266
|
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
@@ -295,4 +311,4 @@ CHECKSUMS
|
|
|
295
311
|
zeitwerk (2.8.2) sha256=7212a61311083c604184b1ea2574b9aa05cd14f855a0841c06985cabe9181d12
|
|
296
312
|
|
|
297
313
|
BUNDLED WITH
|
|
298
|
-
4.0.
|
|
314
|
+
4.0.14
|
data/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Beyond what is necessary to test the generator, the Cocina model classes are not
|
|
|
62
62
|
|
|
63
63
|
## Testing validation changes
|
|
64
64
|
|
|
65
|
-
If there is a possibility that a model, mapping, or validation change will conflict with some existing objects then `bin/validate-data` should be used for testing. This operates on
|
|
65
|
+
If there is a possibility that a model, mapping, or validation change will conflict with some existing objects then `bin/validate-data` should be used for testing. This operates on an export of objects from the repository and reports any validation errors. You may get the file by running the script [bin/export-cocina-head-versions](https://github.com/sul-dlss/dor-services-app#export-cocina-json-data) and downloading the data file to your computer. See the [DSA README](https://github.com/sul-dlss/dor-services-app#scheduled-cocina-json-data-exports) for more info about the files and locations. Running a full validation takes about 2 hours.
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
Alternatively, you can use [validate-cocina](https://github.com/sul-dlss/dor-services-app/blob/main/bin/validate-cocina) for testing. This must be run on the `sdr-infra` VM since it requires deploying a branch of cocina-models. It is slower than using `bin/validate-data`, but all of the data is completely up to date.
|
data/bin/enhance-report-csv
CHANGED
|
@@ -67,18 +67,16 @@ def extract_fields(doc)
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def build_output(solr, rows, batch_size)
|
|
70
|
-
extra_col_count = (rows.first&.size || 1) - 1
|
|
71
|
-
extra_headers = extra_col_count.times.map { |i| "col#{i + 2}" }
|
|
72
|
-
|
|
73
70
|
CSV.generate do |out|
|
|
74
|
-
out << ([
|
|
71
|
+
out << (%w[druid value] + FIELD_HEADERS.values)
|
|
75
72
|
|
|
76
73
|
rows.each_slice(batch_size) do |batch|
|
|
77
74
|
docs = fetch_solr_docs(solr, batch.map { |row| row[0] })
|
|
78
75
|
|
|
79
76
|
batch.each do |row|
|
|
80
77
|
druid = row[0]
|
|
81
|
-
|
|
78
|
+
value = row.size > 1 ? row[1..].join('|') : ''
|
|
79
|
+
out << ([druid, value] + extract_fields(docs[druid]))
|
|
82
80
|
end
|
|
83
81
|
end
|
|
84
82
|
end
|
data/bin/validate-data
CHANGED
|
@@ -19,6 +19,7 @@ require 'cocina/models'
|
|
|
19
19
|
require 'json'
|
|
20
20
|
require 'ruby-progressbar'
|
|
21
21
|
require 'optparse'
|
|
22
|
+
require 'csv'
|
|
22
23
|
|
|
23
24
|
# Parse command line options
|
|
24
25
|
def parse_options # rubocop:disable Metrics/MethodLength
|
|
@@ -104,15 +105,16 @@ def worker_process(reader) # rubocop:disable Metrics/MethodLength
|
|
|
104
105
|
# Process each line in the batch
|
|
105
106
|
batch.each do |line_num, line_content|
|
|
106
107
|
json = JSON.parse(line_content)
|
|
108
|
+
druid = json['externalIdentifier']
|
|
107
109
|
Cocina::Models.build(json)
|
|
108
110
|
rescue JSON::ParserError => e
|
|
109
111
|
errors << { line: line_num, error: "JSON Parse Error: #{e.message}" }
|
|
110
112
|
rescue Cocina::Models::ValidationError => e
|
|
111
|
-
errors << { line: line_num, error: "Validation Error: #{
|
|
113
|
+
errors << { line: line_num, druid:, error: "Validation Error: #{e.message}" }
|
|
112
114
|
rescue Cocina::Models::UnknownTypeError => e
|
|
113
|
-
errors << { line: line_num, error: "Unknown Type Error: #{e.message}" }
|
|
115
|
+
errors << { line: line_num, druid:, error: "Unknown Type Error: #{e.message}" }
|
|
114
116
|
rescue StandardError => e
|
|
115
|
-
errors << { line: line_num, error: "Error: #{e.class} - #{e.message}" }
|
|
117
|
+
errors << { line: line_num, druid:, error: "Error: #{e.class} - #{e.message}" }
|
|
116
118
|
end
|
|
117
119
|
end
|
|
118
120
|
|
|
@@ -245,15 +247,25 @@ def print_summary(total_lines, errors, elapsed_time) # rubocop:disable Metrics/M
|
|
|
245
247
|
|
|
246
248
|
return unless errors.any?
|
|
247
249
|
|
|
250
|
+
sorted_errors = errors.sort_by { |e| e[:line] }
|
|
251
|
+
|
|
248
252
|
puts "\n"
|
|
249
253
|
puts 'Error details:'
|
|
250
254
|
puts '-' * 80
|
|
251
255
|
# Sort errors by line number for better readability
|
|
252
|
-
|
|
253
|
-
puts "Line #{error[:line]}: #{error[:error]}"
|
|
256
|
+
sorted_errors.each do |error|
|
|
257
|
+
puts "Line #{error[:line]}: #{error[:druid]} - #{error[:error]}"
|
|
254
258
|
end
|
|
255
259
|
puts "\n"
|
|
256
|
-
puts "Line numbers with errors: #{
|
|
260
|
+
puts "Line numbers with errors: #{sorted_errors.map { |e| e[:line] }.join(', ')}"
|
|
261
|
+
|
|
262
|
+
CSV.open('validate-data-errors.csv', 'w') do |csv|
|
|
263
|
+
csv << %w[line druid error]
|
|
264
|
+
sorted_errors.each do |error|
|
|
265
|
+
csv << [error[:line], error[:druid], error[:error]]
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
puts 'Errors written to validate-data-errors.csv'
|
|
257
269
|
end
|
|
258
270
|
|
|
259
271
|
# Main execution
|
data/cocina-models.gemspec
CHANGED
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.required_ruby_version = '>= 3.4'
|
|
26
26
|
|
|
27
27
|
spec.add_dependency 'activesupport'
|
|
28
|
+
spec.add_dependency 'cocina_display'
|
|
28
29
|
spec.add_dependency 'deprecation'
|
|
29
30
|
spec.add_dependency 'dry-struct', '~> 1.0'
|
|
30
31
|
spec.add_dependency 'dry-types', '~> 1.1'
|
data/description_types.yml
CHANGED
|
@@ -46,8 +46,6 @@ contributor:
|
|
|
46
46
|
description: An institution or other corporate or collective body.
|
|
47
47
|
- value: person
|
|
48
48
|
description: An individual identity.
|
|
49
|
-
- value: unspecified others
|
|
50
|
-
description: Designator for one or more additional contributors not named individually.
|
|
51
49
|
contributor.identifier:
|
|
52
50
|
- value: ORCID
|
|
53
51
|
description: Identifier from orcid.org.
|
data/docs/description_types.md
CHANGED
|
@@ -49,8 +49,6 @@ _Path: contributor.type_
|
|
|
49
49
|
* An institution or other corporate or collective body.
|
|
50
50
|
* person
|
|
51
51
|
* An individual identity.
|
|
52
|
-
* unspecified others
|
|
53
|
-
* Designator for one or more additional contributors not named individually.
|
|
54
52
|
## Contributor identifier types
|
|
55
53
|
_Path: contributor.identifier.type_
|
|
56
54
|
* ORCID
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# LC Standard Identifier Source Codes
|
|
2
|
+
# Source: https://www.loc.gov/standards/sourcelist/standard-identifier.html
|
|
3
|
+
# Additional codes: swets, apis
|
|
4
|
+
- agorha
|
|
5
|
+
- agrovoc
|
|
6
|
+
- allmovie
|
|
7
|
+
- allmusic
|
|
8
|
+
- allocine
|
|
9
|
+
- amnbo
|
|
10
|
+
- ansi
|
|
11
|
+
- apis
|
|
12
|
+
- archinl
|
|
13
|
+
- archinpe
|
|
14
|
+
- archinpr
|
|
15
|
+
- archna
|
|
16
|
+
- archns
|
|
17
|
+
- ark
|
|
18
|
+
- artsy
|
|
19
|
+
- artukart
|
|
20
|
+
- artukaw
|
|
21
|
+
- atg
|
|
22
|
+
- balat
|
|
23
|
+
- bbcth
|
|
24
|
+
- bdrc
|
|
25
|
+
- bdusc
|
|
26
|
+
- belvku
|
|
27
|
+
- belvwrk
|
|
28
|
+
- benezit
|
|
29
|
+
- bew
|
|
30
|
+
- bfi
|
|
31
|
+
- bibbi
|
|
32
|
+
- bigenc
|
|
33
|
+
- bnfcg
|
|
34
|
+
- bpn
|
|
35
|
+
- bsi
|
|
36
|
+
- cabt
|
|
37
|
+
- cana
|
|
38
|
+
- cantic
|
|
39
|
+
- cbwpid
|
|
40
|
+
- cerl
|
|
41
|
+
- cgndb
|
|
42
|
+
- clara
|
|
43
|
+
- cnbksy
|
|
44
|
+
- csfdcz
|
|
45
|
+
- danacode
|
|
46
|
+
- darome
|
|
47
|
+
- datoses
|
|
48
|
+
- discogs
|
|
49
|
+
- dkfilm
|
|
50
|
+
- dma
|
|
51
|
+
- doi
|
|
52
|
+
- dpb
|
|
53
|
+
- ean
|
|
54
|
+
- ecli
|
|
55
|
+
- eidr
|
|
56
|
+
- emlo
|
|
57
|
+
- fast
|
|
58
|
+
- fidecp
|
|
59
|
+
- filmaff
|
|
60
|
+
- filmport
|
|
61
|
+
- findagr
|
|
62
|
+
- fisa
|
|
63
|
+
- freebase
|
|
64
|
+
- fuoc
|
|
65
|
+
- gacsch
|
|
66
|
+
- gec
|
|
67
|
+
- geogndb
|
|
68
|
+
- geonames
|
|
69
|
+
- geprishisp
|
|
70
|
+
- gettyaat
|
|
71
|
+
- gettyart
|
|
72
|
+
- gettyobj
|
|
73
|
+
- gettytgn
|
|
74
|
+
- gettyulan
|
|
75
|
+
- gnd
|
|
76
|
+
- gnis
|
|
77
|
+
- goodra
|
|
78
|
+
- gtaa
|
|
79
|
+
- gtin-14
|
|
80
|
+
- hdl
|
|
81
|
+
- iaafa
|
|
82
|
+
- ibdb
|
|
83
|
+
- iconauth
|
|
84
|
+
- idref
|
|
85
|
+
- imdb
|
|
86
|
+
- isan
|
|
87
|
+
- isbn
|
|
88
|
+
- isbn-a
|
|
89
|
+
- isbnre
|
|
90
|
+
- isbnsbn
|
|
91
|
+
- isfdbau
|
|
92
|
+
- isfdbaw
|
|
93
|
+
- isfdbma
|
|
94
|
+
- isfdbpu
|
|
95
|
+
- isil
|
|
96
|
+
- ismn
|
|
97
|
+
- isni
|
|
98
|
+
- iso
|
|
99
|
+
- isrc
|
|
100
|
+
- issn
|
|
101
|
+
- issn-l
|
|
102
|
+
- issue-number
|
|
103
|
+
- istc
|
|
104
|
+
- iswc
|
|
105
|
+
- it-acnp
|
|
106
|
+
- itar
|
|
107
|
+
- kda
|
|
108
|
+
- kdw
|
|
109
|
+
- kinopo
|
|
110
|
+
- knpam
|
|
111
|
+
- kulturnav
|
|
112
|
+
- lattes
|
|
113
|
+
- lccn
|
|
114
|
+
- lcmd
|
|
115
|
+
- lcmpt
|
|
116
|
+
- lei
|
|
117
|
+
- libaus
|
|
118
|
+
- lmhl
|
|
119
|
+
- local
|
|
120
|
+
- margaz
|
|
121
|
+
- matrix-number
|
|
122
|
+
- mesh
|
|
123
|
+
- mocofo
|
|
124
|
+
- moma
|
|
125
|
+
- morana
|
|
126
|
+
- moviemetf
|
|
127
|
+
- moviemetr
|
|
128
|
+
- munzing
|
|
129
|
+
- muscl
|
|
130
|
+
- music-plate
|
|
131
|
+
- music-publisher
|
|
132
|
+
- musicb
|
|
133
|
+
- nacat
|
|
134
|
+
- nagb
|
|
135
|
+
- natgazfid
|
|
136
|
+
- nga
|
|
137
|
+
- ngva
|
|
138
|
+
- ngvw
|
|
139
|
+
- nipo
|
|
140
|
+
- nlg
|
|
141
|
+
- nndb
|
|
142
|
+
- npg
|
|
143
|
+
- nzggn
|
|
144
|
+
- odnb
|
|
145
|
+
- ofdb
|
|
146
|
+
- onix
|
|
147
|
+
- opensm
|
|
148
|
+
- orcid
|
|
149
|
+
- orgnr
|
|
150
|
+
- oxforddnb
|
|
151
|
+
- pcadbu
|
|
152
|
+
- pcadpe
|
|
153
|
+
- pcadpf
|
|
154
|
+
- permid
|
|
155
|
+
- picnypl
|
|
156
|
+
- pleiades
|
|
157
|
+
- pnta
|
|
158
|
+
- porthu
|
|
159
|
+
- prabook
|
|
160
|
+
- rbmsbt
|
|
161
|
+
- rbmsgt
|
|
162
|
+
- rbmspe
|
|
163
|
+
- rbmsppe
|
|
164
|
+
- rbmspt
|
|
165
|
+
- rbmsrd
|
|
166
|
+
- rbmste
|
|
167
|
+
- rid
|
|
168
|
+
- rkda
|
|
169
|
+
- ror
|
|
170
|
+
- s2a3bd
|
|
171
|
+
- saam
|
|
172
|
+
- scholaru
|
|
173
|
+
- scope
|
|
174
|
+
- scopus
|
|
175
|
+
- sici
|
|
176
|
+
- smgp
|
|
177
|
+
- snac
|
|
178
|
+
- spotify
|
|
179
|
+
- sprfbsb
|
|
180
|
+
- sprfbsk
|
|
181
|
+
- sprfcbb
|
|
182
|
+
- sprfcfb
|
|
183
|
+
- sprfhoc
|
|
184
|
+
- sprfoly
|
|
185
|
+
- sprfpfb
|
|
186
|
+
- ssaut
|
|
187
|
+
- stock-number
|
|
188
|
+
- strn
|
|
189
|
+
- stw
|
|
190
|
+
- svfilm
|
|
191
|
+
- swets
|
|
192
|
+
- tatearid
|
|
193
|
+
- theatr
|
|
194
|
+
- tpce
|
|
195
|
+
- trove
|
|
196
|
+
- unescot
|
|
197
|
+
- upc
|
|
198
|
+
- uri
|
|
199
|
+
- urn
|
|
200
|
+
- vd16
|
|
201
|
+
- vd17
|
|
202
|
+
- vd18
|
|
203
|
+
- vgmdb
|
|
204
|
+
- viaf
|
|
205
|
+
- videorecording-identifier
|
|
206
|
+
- wikidata
|
|
207
|
+
- wndla
|
|
208
|
+
- xgamea
|
|
209
|
+
- ysopai
|
|
210
|
+
- zbaut
|
|
@@ -60,7 +60,7 @@ module Cocina
|
|
|
60
60
|
|
|
61
61
|
# build non-parallel, single name
|
|
62
62
|
def build_name(name_node)
|
|
63
|
-
return
|
|
63
|
+
return nil if name_node.xpath('mods:etal', mods: Description::DESC_METADATA_NS).present?
|
|
64
64
|
|
|
65
65
|
name_parts = build_name_parts(name_node)
|
|
66
66
|
# If there are no name parts, do not map the name
|
|
@@ -7,8 +7,14 @@ module Cocina
|
|
|
7
7
|
class CompositeDescriptionValidator
|
|
8
8
|
VALIDATORS = [
|
|
9
9
|
DescriptionTypesVisitorValidator,
|
|
10
|
+
DescriptionIdentifierSourceCodeVisitorValidator,
|
|
11
|
+
DescriptionRoleSourceCodeVisitorValidator,
|
|
12
|
+
DescriptionFormResourceTypeVisitorValidator,
|
|
10
13
|
DescriptionValuesVisitorValidator,
|
|
11
|
-
DescriptionDateTimeVisitorValidator
|
|
14
|
+
DescriptionDateTimeVisitorValidator,
|
|
15
|
+
DescriptionEventDateVisitorValidator,
|
|
16
|
+
DescriptionSubjectTemporalEncodingVisitorValidator,
|
|
17
|
+
DescriptionLocationSourceCodeVisitorValidator
|
|
12
18
|
].freeze
|
|
13
19
|
|
|
14
20
|
def self.validate(clazz, attributes)
|
|
@@ -8,8 +8,9 @@ module Cocina
|
|
|
8
8
|
# Validates that dates of known types are type-valid using the visitor pattern.
|
|
9
9
|
class DescriptionDateTimeVisitorValidator < BaseDescriptionVisitorValidator
|
|
10
10
|
VALIDATABLE_TYPES = %w[edtf iso8601 w3cdtf].freeze
|
|
11
|
+
VALID_ENCODING_CODES = %w[edtf iso8601 marc temper w3cdtf].freeze
|
|
11
12
|
|
|
12
|
-
def visit_hash(hash:, path:) # rubocop:disable Metrics/CyclomaticComplexity
|
|
13
|
+
def visit_hash(hash:, path:) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
13
14
|
# Only dates nested under a `date` key are subject to validation.
|
|
14
15
|
# For example, event.date is in scope but event.note is not.
|
|
15
16
|
return unless in_date_path?(path)
|
|
@@ -32,7 +33,10 @@ module Cocina
|
|
|
32
33
|
# recursing into its children, so the encoding is always registered
|
|
33
34
|
# before any child value hashes are visited.
|
|
34
35
|
code = hash.dig(:encoding, :code)
|
|
35
|
-
|
|
36
|
+
if code
|
|
37
|
+
encoding_paths[path.dup] = code if VALIDATABLE_TYPES.include?(code)
|
|
38
|
+
invalid_encoding_codes << "#{path_to_s(path)}.encoding.code (#{code})" unless VALID_ENCODING_CODES.include?(code)
|
|
39
|
+
end
|
|
36
40
|
|
|
37
41
|
value = hash[:value]
|
|
38
42
|
return unless value.is_a?(String)
|
|
@@ -62,17 +66,18 @@ module Cocina
|
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
def validate!
|
|
65
|
-
|
|
69
|
+
errors = []
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
next if values.empty?
|
|
71
|
+
errors << "Unrecognized date encoding codes in description: #{invalid_encoding_codes.join(', ')}" if invalid_encoding_codes.any?
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
unless invalid_groups.empty?
|
|
74
|
+
invalid_dates = invalid_groups.filter_map do |path, values|
|
|
75
|
+
[*values, encoding_paths[path]] unless values.empty?
|
|
76
|
+
end
|
|
77
|
+
errors << "Invalid date(s) in description: #{invalid_dates}" if invalid_dates.any?
|
|
71
78
|
end
|
|
72
79
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
raise ValidationError, "Invalid date(s) in description: #{invalid_dates}"
|
|
80
|
+
raise ValidationError, errors.join('; ') if errors.any?
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
private
|
|
@@ -81,6 +86,10 @@ module Cocina
|
|
|
81
86
|
@encoding_paths ||= {}
|
|
82
87
|
end
|
|
83
88
|
|
|
89
|
+
def invalid_encoding_codes
|
|
90
|
+
@invalid_encoding_codes ||= []
|
|
91
|
+
end
|
|
92
|
+
|
|
84
93
|
def invalid_groups
|
|
85
94
|
@invalid_groups ||= {}
|
|
86
95
|
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cocina
|
|
4
|
+
module Models
|
|
5
|
+
module Validators
|
|
6
|
+
# Validates that event date structuredValue entries with a type also have a value.
|
|
7
|
+
class DescriptionEventDateVisitorValidator < BaseDescriptionVisitorValidator
|
|
8
|
+
def visit_hash(hash:, path:)
|
|
9
|
+
return unless hash[:type] && !hash[:value]
|
|
10
|
+
return unless event_date_structured_value?(path)
|
|
11
|
+
|
|
12
|
+
error_paths << path_to_s(path)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def validate!
|
|
16
|
+
return if error_paths.empty?
|
|
17
|
+
|
|
18
|
+
raise ValidationError,
|
|
19
|
+
"Missing value for type in description: #{error_paths.join(', ')}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def error_paths
|
|
25
|
+
@error_paths ||= []
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def event_date_structured_value?(path)
|
|
29
|
+
return false unless path[0] == 'event' && path[2] == 'date'
|
|
30
|
+
|
|
31
|
+
# Direct: event.date.structuredValue, e.g. ["event", 0, "date", 0, "structuredValue", 0]
|
|
32
|
+
# Via parallelValue: event.date.parallelValue.structuredValue, e.g. ["event", 0, "date", 0, "parallelValue", 0, "structuredValue", 0]
|
|
33
|
+
path[4] == 'structuredValue' || (path[4] == 'parallelValue' && path[6] == 'structuredValue')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cocina
|
|
4
|
+
module Models
|
|
5
|
+
module Validators
|
|
6
|
+
# Validates form.value against allowed values when form.source.value is a known controlled vocabulary.
|
|
7
|
+
class DescriptionFormResourceTypeVisitorValidator < BaseDescriptionVisitorValidator
|
|
8
|
+
def validate!
|
|
9
|
+
return if error_paths.empty?
|
|
10
|
+
|
|
11
|
+
raise ValidationError, "Unrecognized resource type values in description: #{error_paths.join(', ')}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def visit_hash(hash:, path:)
|
|
15
|
+
return unless form_entry_path?(path)
|
|
16
|
+
return unless hash[:type].to_s == 'resource type'
|
|
17
|
+
|
|
18
|
+
source_value = hash.dig(:source, :value)
|
|
19
|
+
return unless source_value && valid_values_by_source.key?(source_value)
|
|
20
|
+
|
|
21
|
+
value = hash[:value]
|
|
22
|
+
return unless value
|
|
23
|
+
return if valid_values_by_source[source_value].include?(value)
|
|
24
|
+
|
|
25
|
+
error_paths << "#{path_to_s(path)} (#{value})"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def error_paths
|
|
31
|
+
@error_paths ||= []
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def form_entry_path?(path)
|
|
35
|
+
path.length >= 2 && path[-1].is_a?(Integer) && path[-2].to_s == 'form'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# rubocop:disable Style/ClassVars
|
|
39
|
+
def valid_values_by_source
|
|
40
|
+
@@valid_values_by_source ||= YAML.load_file(::File.expand_path('../../../../resource_type_values.yml', __dir__))
|
|
41
|
+
end
|
|
42
|
+
# rubocop:enable Style/ClassVars
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cocina
|
|
4
|
+
module Models
|
|
5
|
+
module Validators
|
|
6
|
+
# Validates identifier.source.code values against identifier_source_codes.yml.
|
|
7
|
+
class DescriptionIdentifierSourceCodeVisitorValidator < BaseDescriptionVisitorValidator
|
|
8
|
+
def validate!
|
|
9
|
+
return if error_paths.empty?
|
|
10
|
+
|
|
11
|
+
raise ValidationError, "Unrecognized identifier source codes in description: #{error_paths.join(', ')}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def visit_hash(hash:, path:)
|
|
15
|
+
return unless identifier_path?(path)
|
|
16
|
+
|
|
17
|
+
source_code = hash.dig(:source, :code)
|
|
18
|
+
return unless source_code
|
|
19
|
+
|
|
20
|
+
error_paths << "#{path_to_s(path)}.source.code (#{source_code})" unless valid_codes.include?(source_code.downcase)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def error_paths
|
|
26
|
+
@error_paths ||= []
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def identifier_path?(path)
|
|
30
|
+
path.length >= 2 && path[-1].is_a?(Integer) && path[-2].to_s == 'identifier'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# rubocop:disable Style/ClassVars
|
|
34
|
+
def valid_codes
|
|
35
|
+
@@valid_codes ||= YAML.load_file(::File.expand_path('../../../../identifier_source_codes.yml', __dir__)).to_set(&:downcase)
|
|
36
|
+
end
|
|
37
|
+
# rubocop:enable Style/ClassVars
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|