cocina-models 0.76.0 → 0.79.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff6e03954275e59dcc8fbf693f3aeef4b90742767771865508e81541f53f1cbf
4
- data.tar.gz: dacc3005506e32d5cca5b599477d1c450844272715e9500f8242bc19bf69972b
3
+ metadata.gz: 193f5886756d2fd6432e90ab5323f6ed5a11c699cb97f49d61394bc5fafd5f53
4
+ data.tar.gz: ecb1493a56b7b20f9733084c8a9a115e3a3c6639a8072bc371f53a51d69d0a2c
5
5
  SHA512:
6
- metadata.gz: bf5f815fb3c09ae4cba6d0e1cf16aafd7502cb731f523004c643806579475d6ac11882845a5d0178732f8d3c9edad56901bf8e05df7d5681a0afdc0032f14058
7
- data.tar.gz: 5b88e55c0e25e6dad32a4326a2063bf5a72fedc8146e90a7ead461a1fad0bb1f0f293d360f16884daf5582fa16f4e95fdb61307487e21b7a28b2250c69c1d9ad
6
+ metadata.gz: 8cc210b897872f3b90fd59e12f381f049b1389b0cf3d798a0375eea57282cf456c6591a8d474c5c612253123bca01ed9a9b931129c89153b8a8dae3ad713254b
7
+ data.tar.gz: f1a23590223b7760780e3b547b053355a1ba600fdc468ce563aef20a4c38cd3571345bde621f3f9f23248d27c29f0f3b5a829dd0c7d5c08d95d27efec472453d
data/README.md CHANGED
@@ -55,8 +55,37 @@ If there is a possibility that a model or validation change will conflict with s
55
55
 
56
56
  1. Create a cocina-models branch containing the proposed change and push to Github.
57
57
  2. On sdr-deploy, check out `main`, update the `Gemfile` so that cocina-models references the branch, and `bundle install`.
58
- 3. Run `bin/validate-cocina`.
59
- 4. Check `validate-cocina.csv` for validation errors.
58
+ 3. Select the appropriate database.
59
+ For QA:
60
+ ```
61
+ export DATABASE_NAME="dor_services"
62
+ export DATABASE_USERNAME=$DOR_SERVICES_DB_USER
63
+ export DATABASE_HOSTNAME=$DOR_SERVICES_DB_QA_HOST
64
+ export DATABASE_PASSWORD=$DOR_SERVICES_DB_QA_PWD
65
+ ```
66
+
67
+ For stage:
68
+ ```
69
+ export DATABASE_NAME="dor_services"
70
+ export DATABASE_USERNAME=$DOR_SERVICES_DB_USER
71
+ export DATABASE_HOSTNAME=$DOR_SERVICES_DB_STAGE_HOST
72
+ export DATABASE_PASSWORD=$DOR_SERVICES_DB_STAGE_PWD
73
+ ```
74
+
75
+ For production:
76
+ ```
77
+ export DATABASE_NAME="dor_services"
78
+ export DATABASE_USERNAME=$DOR_SERVICES_DB_USER
79
+ export DATABASE_HOSTNAME=$DOR_SERVICES_DB_PROD_HOST
80
+ export DATABASE_PASSWORD=$DOR_SERVICES_DB_PROD_PWD
81
+ ```
82
+
83
+ 4. Run `bin/validate-cocina`:
84
+ ```
85
+ export RUBYOPT='-W:no-deprecated -W:no-experimental'
86
+ RAILS_ENV=production bin/validate-cocina -p 8
87
+ ```
88
+ 5. Check `validate-cocina.csv` for validation errors.
60
89
 
61
90
  ## Releasing
62
91
 
@@ -132,6 +132,8 @@ event:
132
132
  description: The discussion of an academic or intellectual work for an audience, such as a seminar.
133
133
  - value: production
134
134
  description: The physical assembly of a resource not considered published, such as page proofs for a book.
135
+ - value: provenance
136
+ description: The resource's origins and history.
135
137
  - value: publication
136
138
  description: The publishing or issuing of a resource.
137
139
  - value: recording
@@ -389,6 +391,8 @@ identifier:
389
391
  - value: record id
390
392
  - value: Senate Number
391
393
  - value: Series
394
+ - value: SICI
395
+ code: sici
392
396
  - value: SIRSI
393
397
  - value: Source ID
394
398
  - value: sourceID
@@ -141,6 +141,8 @@ _Path: event.type_
141
141
  * The discussion of an academic or intellectual work for an audience, such as a seminar.
142
142
  * production
143
143
  * The physical assembly of a resource not considered published, such as page proofs for a book.
144
+ * provenance
145
+ * The resource's origins and history.
144
146
  * publication
145
147
  * The publishing or issuing of a resource.
146
148
  * recording
@@ -15,7 +15,6 @@ module Cocina
15
15
  # @param [TitleBuilder] title_builder - defaults to Title class
16
16
  # @param [Cocina::Models::Mapping::ErrorNotifier] notifier
17
17
  # @return [Hash] a hash that can be mapped to a cocina descriptive model
18
- # @raises [Cocina::Mapper::InvalidDescMetadata] if some assumption about descMetadata is violated
19
18
  def self.props(mods:, druid:, label:, title_builder: Title, notifier: nil)
20
19
  new(title_builder: title_builder, mods: mods, druid: druid, label: label, notifier: notifier).props
21
20
  end
@@ -5,8 +5,7 @@ module Cocina
5
5
  module Mapping
6
6
  # Utility methods for generating purl links
7
7
  class Purl
8
- class_attribute :base_url
9
- self.base_url = 'https://purl.stanford.edu'
8
+ class_attribute :base_url, default: 'https://purl.stanford.edu'
10
9
 
11
10
  def self.for(druid:)
12
11
  return nil if druid.nil?
@@ -199,8 +199,6 @@ module Cocina
199
199
  xml.affiliation note.value
200
200
  when 'description'
201
201
  xml.description note.value
202
- when 'citation status'
203
- xml.description UNCITED_DESCRIPTION if note.value == 'false'
204
202
  end
205
203
  end
206
204
  end
@@ -11,7 +11,7 @@ module Cocina
11
11
 
12
12
  def initialize(clazz, attributes)
13
13
  @clazz = clazz
14
- @attributes = attributes.deep_symbolize_keys
14
+ @attributes = attributes
15
15
  @error_paths = []
16
16
  end
17
17
 
@@ -29,9 +29,7 @@ module Cocina
29
29
  attr_reader :clazz, :attributes, :error_paths
30
30
 
31
31
  def meets_preconditions?
32
- resources.any? do |resource|
33
- titles_with_associated_name_note_for(resource).present?
34
- end
32
+ [Cocina::Models::Description, Cocina::Models::RequestDescription].include?(clazz)
35
33
  end
36
34
 
37
35
  def valid?(resource)
@@ -11,7 +11,7 @@ module Cocina
11
11
 
12
12
  def initialize(clazz, attributes)
13
13
  @clazz = clazz
14
- @attributes = attributes.deep_symbolize_keys
14
+ @attributes = attributes
15
15
  @error_paths = []
16
16
  end
17
17
 
@@ -30,8 +30,7 @@ module Cocina
30
30
  attr_reader :clazz, :attributes, :error_paths
31
31
 
32
32
  def meets_preconditions?
33
- attributes.key?(:description) || [Cocina::Models::Description,
34
- Cocina::Models::RequestDescription].include?(clazz)
33
+ [Cocina::Models::Description, Cocina::Models::RequestDescription].include?(clazz)
35
34
  end
36
35
 
37
36
  def validate_hash(hash, path)
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ module Validators
6
+ # Validates that there is only one of value, groupedValue, structuredValue, or parallelValue.
7
+ class DescriptionValuesValidator
8
+ def self.validate(clazz, attributes)
9
+ new(clazz, attributes).validate
10
+ end
11
+
12
+ def initialize(clazz, attributes)
13
+ @clazz = clazz
14
+ @attributes = attributes
15
+ @error_paths = []
16
+ end
17
+
18
+ def validate
19
+ return unless meets_preconditions?
20
+
21
+ validate_obj(attributes, [])
22
+
23
+ return if error_paths.empty?
24
+
25
+ raise ValidationError, "Multiple value, groupedValue, structuredValue, and parallelValue in description: #{error_paths.join(', ')}"
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :clazz, :attributes, :error_paths
31
+
32
+ def meets_preconditions?
33
+ [Cocina::Models::Description, Cocina::Models::RequestDescription].include?(clazz)
34
+ end
35
+
36
+ def validate_hash(hash, path)
37
+ validate_values(hash, path)
38
+ hash.each do |key, obj|
39
+ validate_obj(obj, path + [key])
40
+ end
41
+ end
42
+
43
+ def validate_array(array, path)
44
+ array.each_with_index do |obj, index|
45
+ validate_obj(obj, path + [index])
46
+ end
47
+ end
48
+
49
+ def validate_obj(obj, path)
50
+ validate_hash(obj, path) if obj.is_a?(Hash)
51
+ validate_array(obj, path) if obj.is_a?(Array)
52
+ end
53
+
54
+ def validate_values(hash, path)
55
+ return unless hash.count { |key, value| %i[value groupedValue structuredValue parallelValue].include?(key) && value.present? } > 1
56
+
57
+ error_paths << path_to_s(path)
58
+ end
59
+
60
+ def path_to_s(path)
61
+ # This matches the format used by descriptive spreadsheets
62
+ path_str = ''
63
+ path.each_with_index do |part, index|
64
+ if part.is_a?(Integer)
65
+ path_str += (part + 1).to_s
66
+ else
67
+ path_str += '.' if index.positive?
68
+ path_str += part.to_s
69
+ end
70
+ end
71
+ path_str
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -11,7 +11,8 @@ module Cocina
11
11
  PurlValidator,
12
12
  CatalogLinksValidator,
13
13
  AssociatedNameValidator,
14
- DescriptionTypesValidator
14
+ DescriptionTypesValidator,
15
+ DescriptionValuesValidator
15
16
  ].freeze
16
17
 
17
18
  def self.validate(clazz, attributes)
@@ -25,8 +26,7 @@ module Cocina
25
26
  # In the meantime, copying code.
26
27
  attributes_hash = deep_transform_values(attributes.to_h) do |value|
27
28
  value.class.name.starts_with?('Cocina::Models') ? value.to_h : value
28
- end.with_indifferent_access
29
-
29
+ end.deep_symbolize_keys.with_indifferent_access
30
30
  VALIDATORS.each { |validator| validator.validate(clazz, attributes_hash) }
31
31
  end
32
32
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cocina
4
4
  module Models
5
- VERSION = '0.76.0'
5
+ VERSION = '0.79.0'
6
6
  end
7
7
  end
data/lib/cocina/models.rb CHANGED
@@ -119,7 +119,7 @@ module Cocina
119
119
  # @param [DROWithMetadata,CollectionWithMetadata,AdminPolicyWithMetadata] cocina_object
120
120
  # @return [DRO,Collection,AdminPolicy]
121
121
  def self.without_metadata(cocina_object)
122
- build(cocina_object.to_h.except(:created, :modified, :lock))
122
+ build(cocina_object.to_h.except(:created, :modified, :lock), validate: false)
123
123
  end
124
124
 
125
125
  # Adds metadata to a DRO, Collection, AdminPolicy
@@ -144,7 +144,7 @@ module Cocina
144
144
  else
145
145
  AdminPolicyWithMetadata
146
146
  end
147
- clazz.new(props)
147
+ clazz.new(props, false, false)
148
148
  end
149
149
 
150
150
  def self.type_for(dyn)
@@ -12,8 +12,20 @@ module Cocina
12
12
  end
13
13
  end
14
14
 
15
+ SUPPORTED_TYPES = %i[
16
+ admin_policy
17
+ admin_policy_with_metadata
18
+ collection
19
+ collection_with_metadata
20
+ dro
21
+ dro_with_metadata
22
+ request_admin_policy
23
+ request_collection
24
+ request_dro
25
+ ].freeze
26
+
15
27
  def self.supported_type?(type)
16
- %i[dro collection admin_policy dro_with_metadata collection_with_metadata admin_policy_with_metadata].include?(type)
28
+ SUPPORTED_TYPES.include?(type)
17
29
  end
18
30
 
19
31
  WITH_METADATA_SUFFIX = '_with_metadata'
@@ -33,37 +45,60 @@ module Cocina
33
45
  type: Cocina::Models::ObjectType.object,
34
46
  id: 'druid:bc234fg5678',
35
47
  version: 1,
36
- label: 'test object',
37
- title: 'test object',
48
+ label: 'factory DRO label',
49
+ title: 'factory DRO title',
38
50
  source_id: 'sul:1234',
39
51
  admin_policy_id: 'druid:hv992ry2431'
40
52
  }.freeze
41
53
 
42
- COLLECTION_DEFAULTS = DRO_DEFAULTS.except(:source_id).merge(type: Cocina::Models::ObjectType.collection)
54
+ REQUEST_DRO_DEFAULTS = DRO_DEFAULTS.except(:id)
55
+
56
+ COLLECTION_DEFAULTS = {
57
+ type: Cocina::Models::ObjectType.collection,
58
+ id: 'druid:bb222ff5555',
59
+ version: 1,
60
+ label: 'factory collection label',
61
+ title: 'factory collection title',
62
+ admin_policy_id: 'druid:hv992ry2431'
63
+ }.freeze
64
+
65
+ REQUEST_COLLECTION_DEFAULTS = COLLECTION_DEFAULTS.except(:id)
43
66
 
44
67
  ADMIN_POLICY_DEFAULTS = {
45
68
  type: Cocina::Models::ObjectType.admin_policy,
46
- id: 'druid:bc234fg5678',
69
+ id: 'druid:cb432gf8765',
47
70
  version: 1,
48
- label: 'test admin policy',
49
- title: 'test admin policy',
71
+ label: 'factory APO label',
72
+ title: 'factory APO title',
50
73
  admin_policy_id: 'druid:hv992ry2431',
51
74
  agreement_id: 'druid:hp308wm0436'
52
75
  }.freeze
53
76
 
77
+ REQUEST_ADMIN_POLICY_DEFAULTS = ADMIN_POLICY_DEFAULTS.except(:id)
78
+
79
+ def self.build_dro_properties(id:, **kwargs)
80
+ build_request_dro_properties(**kwargs)
81
+ .merge(externalIdentifier: id)
82
+ .tap do |props|
83
+ props[:description][:purl] = "https://purl.stanford.edu/#{id.delete_prefix('druid:')}"
84
+ end
85
+ end
86
+
87
+ def self.build_dro(attributes)
88
+ Cocina::Models.build(build_dro_properties(**DRO_DEFAULTS.merge(attributes)))
89
+ end
90
+
54
91
  # rubocop:disable Metrics/ParameterLists
55
- def self.build_dro_properties(type:, id:, version:, label:, title:, source_id:, admin_policy_id:,
56
- barcode: nil, catkeys: [], collection_ids: [])
92
+ def self.build_request_dro_properties(type:, version:, label:, title:, source_id:, admin_policy_id:,
93
+ barcode: nil, catkeys: [], collection_ids: [])
57
94
  {
58
95
  type: type,
59
- externalIdentifier: id,
60
96
  version: version,
61
97
  label: label,
62
98
  access: {},
63
99
  administrative: { hasAdminPolicy: admin_policy_id },
64
100
  description: {
65
- title: [{ value: title }],
66
- purl: "https://purl.stanford.edu/#{id.delete_prefix('druid:')}"
101
+ title: [{ value: title }]
67
102
  },
68
103
  identification: {
69
104
  sourceId: source_id
@@ -82,22 +117,28 @@ module Cocina
82
117
  end
83
118
  # rubocop:enable Metrics/ParameterLists
84
119
 
85
- def self.build_dro(attributes)
86
- Cocina::Models.build(build_dro_properties(**DRO_DEFAULTS.merge(attributes)))
120
+ def self.build_request_dro(attributes)
121
+ Cocina::Models.build_request(build_request_dro_properties(**REQUEST_DRO_DEFAULTS.merge(attributes)))
122
+ end
123
+
124
+ def self.build_collection_properties(id:, **kwargs)
125
+ build_request_collection_properties(**kwargs)
126
+ .merge(externalIdentifier: id)
127
+ .tap do |props|
128
+ props[:description][:purl] = "https://purl.stanford.edu/#{id.delete_prefix('druid:')}"
129
+ end
87
130
  end
88
131
 
89
132
  # rubocop:disable Metrics/ParameterLists
90
- def self.build_collection_properties(type:, id:, version:, label:, title:, admin_policy_id:, source_id: nil, catkeys: [])
133
+ def self.build_request_collection_properties(type:, version:, label:, title:, admin_policy_id:, source_id: nil, catkeys: [])
91
134
  {
92
135
  type: type,
93
- externalIdentifier: id,
94
136
  version: version,
95
137
  label: label,
96
138
  access: {},
97
139
  administrative: { hasAdminPolicy: admin_policy_id },
98
140
  description: {
99
- title: [{ value: title }],
100
- purl: "https://purl.stanford.edu/#{id.delete_prefix('druid:')}"
141
+ title: [{ value: title }]
101
142
  },
102
143
  identification: {}
103
144
  }.tap do |props|
@@ -115,19 +156,34 @@ module Cocina
115
156
  Cocina::Models.build(build_collection_properties(**COLLECTION_DEFAULTS.merge(attributes)))
116
157
  end
117
158
 
159
+ def self.build_request_collection(attributes)
160
+ Cocina::Models.build_request(build_request_collection_properties(**REQUEST_COLLECTION_DEFAULTS.merge(attributes)))
161
+ end
162
+
118
163
  def self.build_admin_policy(attributes)
119
164
  Cocina::Models.build(build_admin_policy_properties(**ADMIN_POLICY_DEFAULTS.merge(attributes)))
120
165
  end
121
166
 
167
+ def self.build_request_admin_policy(attributes)
168
+ Cocina::Models.build_request(build_request_admin_policy_properties(**REQUEST_ADMIN_POLICY_DEFAULTS.merge(attributes)))
169
+ end
170
+
171
+ def self.build_admin_policy_properties(id:, **kwargs)
172
+ build_request_admin_policy_properties(**kwargs)
173
+ .merge(externalIdentifier: id)
174
+ .tap do |props|
175
+ props[:description][:purl] = "https://purl.stanford.edu/#{id.delete_prefix('druid:')}"
176
+ end
177
+ end
178
+
122
179
  # rubocop:disable Metrics/ParameterLists
123
- def self.build_admin_policy_properties(type:, id:, version:, label:, title:,
124
- admin_policy_id:, agreement_id:,
125
- use_statement: nil, copyright: nil, license: nil,
126
- registration_workflow: nil, collections_for_registration: nil,
127
- without_description: false)
180
+ def self.build_request_admin_policy_properties(type:, version:, label:, title:,
181
+ admin_policy_id:, agreement_id:,
182
+ use_statement: nil, copyright: nil, license: nil,
183
+ registration_workflow: nil, collections_for_registration: nil,
184
+ without_description: false)
128
185
  {
129
186
  type: type,
130
- externalIdentifier: id,
131
187
  version: version,
132
188
  label: label,
133
189
  administrative: {
@@ -139,8 +195,7 @@ module Cocina
139
195
  }
140
196
  },
141
197
  description: {
142
- title: [{ value: title }],
143
- purl: "https://purl.stanford.edu/#{id.delete_prefix('druid:')}"
198
+ title: [{ value: title }]
144
199
  }
145
200
  }.tap do |props|
146
201
  props[:administrative][:accessTemplate][:useAndReproductionStatement] = use_statement if use_statement
data/openapi.yml CHANGED
@@ -691,7 +691,7 @@ components:
691
691
  items:
692
692
  $ref: "#/components/schemas/DescriptiveValue"
693
693
  DescriptiveBasicValue:
694
- description: Basic value model for descriptive elements.
694
+ description: Basic value model for descriptive elements. Can only have one of value, parallelValue, groupedValue, or structuredValue.
695
695
  type: object
696
696
  # additionalProperties breaks the validator for allOf, unclear as to why.
697
697
  # additionalProperties: false
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocina-models
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.76.0
4
+ version: 0.79.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Coyne
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-28 00:00:00.000000000 Z
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -306,20 +306,6 @@ files:
306
306
  - docs/cocina-base.jsonld
307
307
  - docs/description_types.md
308
308
  - docs/index.html
309
- - docs/maps/Agent.json
310
- - docs/maps/Collection.json
311
- - docs/maps/DRO.json
312
- - docs/maps/Description.json
313
- - docs/maps/File.json
314
- - docs/maps/Fileset.json
315
- - docs/maps/README.md
316
- - docs/maps/ReleaseTag.json
317
- - docs/maps/Sequence.json
318
- - docs/maps/Title.json
319
- - docs/sampleETD/foxml-export.xml
320
- - docs/sampleETD/foxml.xml
321
- - docs/sampleETD/xn109qc9773_bibframe.ttl
322
- - docs/sampleETD/xn109qc9773_taco.json
323
309
  - exe/generator
324
310
  - lib/cocina/generator.rb
325
311
  - lib/cocina/generator/datatype.rb
@@ -476,6 +462,7 @@ files:
476
462
  - lib/cocina/models/validators/catalog_links_validator.rb
477
463
  - lib/cocina/models/validators/dark_validator.rb
478
464
  - lib/cocina/models/validators/description_types_validator.rb
465
+ - lib/cocina/models/validators/description_values_validator.rb
479
466
  - lib/cocina/models/validators/open_api_validator.rb
480
467
  - lib/cocina/models/validators/purl_validator.rb
481
468
  - lib/cocina/models/validators/validator.rb
data/docs/maps/Agent.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-06/schema#",
3
- "id": "http://cocina.sul.stanford.edu/schemas/Agent",
4
- "title": "Agent",
5
- "description": "An Agent - Person, Group, Organization, or other Acting body.",
6
- "type": "object",
7
- "required": ["name"],
8
- "properties": {
9
- "name": {
10
- "description": "Primary label or name for an Agent.",
11
- "type": "string"
12
- },
13
- "sunetID": {
14
- "description": "Stanford University NetID for the Agent.",
15
- "type": "string"
16
- }
17
- }
18
- }