cocina-models 0.69.1 → 0.71.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34c85f255c9d731cb4de00b8942aff8acc69a92a29cc4b96ca6c9e53c23fd87b
4
- data.tar.gz: d7322adfdca046658865fa2fbb8a815dff97a37068da256f73e33dc94ac0720d
3
+ metadata.gz: 5058bc2927b8788ad9c04142decbfcc7cf42b7daa3b84665d64dd00b432d8ff4
4
+ data.tar.gz: 524263003bc679432b5c120690775de4ebc14ef5fa6158337e0beff9c2bfb332
5
5
  SHA512:
6
- metadata.gz: 79c906f6229766b4918b2665fde81865a5e196865bb828c8bbbde32f4c04714119b241863b731683f94c1f2b1fb2612991020fa281f91a1fa9526a8ef99b6d0e
7
- data.tar.gz: '09dc6bf7f3fd2e6299e8b8fa645b3cce8c7619ffecb88406f463f082245613390b18e316c1b24b988001ad8c24a100a10cef0252740d1a784a696491cf881233'
6
+ metadata.gz: b84f98459177c74cc822a8dee105412c7023c3fda2e953e1f760c482ae3a2967f610207bb53cd33c510e2b0c861834b4cf1998459b70035ac9b22aa55c83b910
7
+ data.tar.gz: '018baa839ef5774c3969f91acb9545fb04ddf3be652ae3f3fafbc6458ddd7ec1d7c4ae5d5d33a9a8eab36476519cd310a33b61da34e4f934bef35ef490dc83fd'
data/.rubocop.yml CHANGED
@@ -107,7 +107,7 @@ RSpec/StubbedMock: # (new in 1.44)
107
107
  Enabled: true
108
108
 
109
109
  RSpec/MultipleMemoizedHelpers:
110
- Max: 6
110
+ Enabled: false
111
111
 
112
112
  # ----- Style ------
113
113
 
data/README.md CHANGED
@@ -53,10 +53,14 @@ which pushes the gem to rubygems.org. Next write up the release notes: https://
53
53
 
54
54
  ### Step 2: Update client gems coupled to the models
55
55
 
56
+ **NOTE**: You can skip this step if the new release is a patch-level bump only.
57
+
56
58
  Next, you should release versions of [sdr-client](https://github.com/sul-dlss/sdr-client) and [dor-services-client](https://github.com/sul-dlss/dor-services-client/) pinned to this version because applications such as [Argo](https://github.com/sul-dlss/argo) depend on both of these gems using the same models.
57
59
 
58
60
  ### Step 3: Update service API specifications and gems
59
61
 
62
+ **NOTE**: You can skip this first half of the step if there have not been any changes to the `cocina-models` OpenAPI spec since the prior release.
63
+
60
64
  The cocina-models gem is used in applications that have an API specification that accepts Cocina models. Next, make sure that the `openapi.yml` for these applications include the `openapi.yml` schema changes made in cocina-models. This list of services is known to include:
61
65
 
62
66
  * [sul-dlss/sdr-api](https://github.com/sul-dlss/sdr-api)
@@ -85,7 +89,9 @@ There are scripts to help with this:
85
89
 
86
90
  #### Step 4A: Create the PRs
87
91
 
88
- access-update-scripts repo has a script for this: `cocina_level2_prs.rb`. You will need a github access token with scopes of "read:org" and "repo" (see https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to run it, as noted in the comments at the top of that script.
92
+ There is a Jenkins CI job that you can run manually to create all the PRs you need. Head to https://sul-ci-prod.stanford.edu/job/SUL-DLSS/job/access-update-scripts/job/cocina-level2-updates/ and then click `Build Now`. Click the new build that is created and then `Console Output` to watch the build. Once it has completed, you can proceed with the next step.
93
+
94
+ If for some reason the above method does not work, the sul-dlss/access-update-scripts repo has a script for this: `cocina_level2_prs.rb`. You will need a github access token with scopes of "read:org" and "repo" (see https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to run it, as noted in the comments at the top of that script.
89
95
 
90
96
  #### Step 4B: Merge the PRs
91
97
 
@@ -95,11 +101,24 @@ access-update-scripts repo has a script for this: `cocina_level2_prs.rb`. You
95
101
 
96
102
  [sul-dlss/sdr-deploy](https://github.com/sul-dlss/sdr-deploy) has a flag in the deploy script to limit deploys to cocina dependent applications. Refer to instructions in the [sdr-deploy/README](https://github.com/sul-dlss/sdr-deploy/blob/main/README.md#only-deploy-repos-related-to-cocina-models-update).
97
103
 
104
+ Note that running the integration tests is currently the best way we have to check for unintended effects and/or bugs when rolling out cocina-models changes.
105
+
106
+ #### Step 5A: Deploy to QA and/or Stage
107
+
108
+ #### Step 5B: Run infrastructure_integration_tests
109
+
110
+ It is safest to ensure _all_ the integration tests run cleanly. However, patch releases of cocina-models may only warrant running individual tests that exercise the changes.
111
+
112
+ #### Step 5C: Deploy to Production
113
+
114
+ **[Turn off Google Books](https://sul-gbooks-prod.stanford.edu/features) when deploying to production.** This avoids failed deposit due to a temporary Cocina model mismatch. Unlike other applications, the deposits will fail without retry and require manual remediation.
115
+
98
116
  ## Usage conventions
99
117
 
100
118
  The following are the recommended naming conventions for code using Cocina models:
101
119
 
102
120
  * `cocina_item`: `Cocina::Models::DRO` instance
121
+ * `cocina_agreement`: `Cocina::Models::DRO` with type of Cocina::Models::ObjectType.agreement
103
122
  * `cocina_admin_policy`: `Cocina::Models::AdminPolicy` instance
104
123
  * `cocina_collection`: `Cocina::Models::Collection` instance
105
124
  * `cocina_object`: `Cocina::Models::DRO` or `Cocina::Models::AdminPolicy` or `Cocina::Models::Collection` instance
@@ -112,7 +131,7 @@ As of the 0.69.0 release, the `cocina-models` gem provides RSpec matchers for do
112
131
  * `expect(http_response_body_with_cocina_json).to equal_cocina_model(cocina_instance)`
113
132
  * `cocina_object_with` (AKA `match_cocina_object_with`): Compare a Cocina model instance with a hash containining part of the structure of a Cocina object. Example usage:
114
133
  * `expect(CocinaObjectStore).to have_received(:save).with(cocina_object_with(access: { view: 'world' }, structural: { contains: [...] }))`
115
- * expect(updated_cocina_item).to match_cocina_object_with(structural: { hasMemberOrders: [] })
134
+ * `expect(updated_cocina_item).to match_cocina_object_with(structural: { hasMemberOrders: [] })`
116
135
  * `cocina_object_with_types`: Check a Cocina object's type information. Example usage:
117
136
  * `expect(object_client).to have_received(:update).with(params: cocina_object_with_types(content_type: Cocina::Models::ObjectType.book, viewing_direction: 'left-to-right'))`
118
137
  * `cocina_admin_policy_with_registration_collections`: Check a Cocina admin policy's collections. Example usage:
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.required_ruby_version = '>= 2.7'
26
26
 
27
27
  spec.add_dependency 'activesupport'
28
+ spec.add_dependency 'deprecation'
28
29
  spec.add_dependency 'dry-struct', '~> 1.0'
29
30
  spec.add_dependency 'dry-types', '~> 1.1'
30
31
  spec.add_dependency 'openapi3_parser' # Parsing openapi doc
@@ -47,10 +47,13 @@ module Cocina
47
47
  end
48
48
 
49
49
  def types
50
- type_properties_doc = schema_doc.properties['type']
51
- return '' if type_properties_doc.nil? || type_properties_doc.enum.nil?
50
+ type_schema_property = schema_properties.find { |schema_property| schema_property.key == 'type' }
51
+ return '' if type_schema_property.nil?
52
52
 
53
- types_list = type_properties_doc.enum.map { |item| "'#{item}'" }.join(",\n ")
53
+ type_schema_doc = type_schema_property.schema_doc
54
+ return '' if type_schema_doc.enum.nil?
55
+
56
+ types_list = type_schema_doc.enum.map { |item| "'#{item}'" }.join(",\n ")
54
57
 
55
58
  <<~RUBY
56
59
  include Checkable
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ class AdminPolicyWithMetadata < Struct
6
+ include Validatable
7
+
8
+ include Checkable
9
+
10
+ TYPES = ['https://cocina.sul.stanford.edu/models/admin_policy'].freeze
11
+
12
+ # The version of Cocina with which this object conforms.
13
+ # example: 1.2.3
14
+ attribute :cocinaVersion, Types::Strict::String.default(Cocina::Models::VERSION)
15
+ attribute :type, Types::Strict::String.enum(*AdminPolicyWithMetadata::TYPES)
16
+ # example: druid:bc123df4567
17
+ attribute :externalIdentifier, Types::Strict::String
18
+ attribute :label, Types::Strict::String
19
+ attribute :version, Types::Strict::Integer
20
+ attribute(:administrative, AdminPolicyAdministrative.default { AdminPolicyAdministrative.new })
21
+ attribute :description, Description.optional.meta(omittable: true)
22
+ # When the object was created.
23
+ attribute :created, Types::Params::DateTime.meta(omittable: true)
24
+ # When the object was modified.
25
+ attribute :modified, Types::Params::DateTime.meta(omittable: true)
26
+ # Key for optimistic locking. The contents of the key is not specified.
27
+ attribute :lock, Types::Strict::String
28
+ end
29
+ end
30
+ end
@@ -25,9 +25,9 @@ module Cocina
25
25
  # Version for the Collection within SDR.
26
26
  attribute :version, Types::Strict::Integer
27
27
  attribute(:access, CollectionAccess.default { CollectionAccess.new })
28
- attribute :administrative, Administrative.optional.meta(omittable: true)
28
+ attribute(:administrative, Administrative.default { Administrative.new })
29
29
  attribute(:description, Description.default { Description.new })
30
- attribute :identification, CollectionIdentification.optional.meta(omittable: true)
30
+ attribute(:identification, CollectionIdentification.default { CollectionIdentification.new })
31
31
  end
32
32
  end
33
33
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ class CollectionWithMetadata < Struct
6
+ include Validatable
7
+
8
+ include Checkable
9
+
10
+ TYPES = ['https://cocina.sul.stanford.edu/models/collection',
11
+ 'https://cocina.sul.stanford.edu/models/curated-collection',
12
+ 'https://cocina.sul.stanford.edu/models/user-collection',
13
+ 'https://cocina.sul.stanford.edu/models/exhibit',
14
+ 'https://cocina.sul.stanford.edu/models/series'].freeze
15
+
16
+ # The version of Cocina with which this object conforms.
17
+ # example: 1.2.3
18
+ attribute :cocinaVersion, Types::Strict::String.default(Cocina::Models::VERSION)
19
+ # The content type of the Collection. Selected from an established set of values.
20
+ attribute :type, Types::Strict::String.enum(*CollectionWithMetadata::TYPES)
21
+ # example: druid:bc123df4567
22
+ attribute :externalIdentifier, Types::Strict::String
23
+ # Primary processing label (can be same as title) for a Collection.
24
+ attribute :label, Types::Strict::String
25
+ # Version for the Collection within SDR.
26
+ attribute :version, Types::Strict::Integer
27
+ attribute(:access, CollectionAccess.default { CollectionAccess.new })
28
+ attribute(:administrative, Administrative.default { Administrative.new })
29
+ attribute(:description, Description.default { Description.new })
30
+ attribute(:identification, CollectionIdentification.default { CollectionIdentification.new })
31
+ # When the object was created.
32
+ attribute :created, Types::Params::DateTime.meta(omittable: true)
33
+ # When the object was modified.
34
+ attribute :modified, Types::Params::DateTime.meta(omittable: true)
35
+ # Key for optimistic locking. The contents of the key is not specified.
36
+ attribute :lock, Types::Strict::String
37
+ end
38
+ end
39
+ end
@@ -37,8 +37,8 @@ module Cocina
37
37
  attribute(:access, DROAccess.default { DROAccess.new })
38
38
  attribute(:administrative, Administrative.default { Administrative.new })
39
39
  attribute(:description, Description.default { Description.new })
40
- attribute :identification, Identification.optional.meta(omittable: true)
41
- attribute :structural, DROStructural.optional.meta(omittable: true)
40
+ attribute(:identification, Identification.default { Identification.new })
41
+ attribute(:structural, DROStructural.default { DROStructural.new })
42
42
  attribute :geographic, Geographic.optional.meta(omittable: true)
43
43
  end
44
44
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ class DROWithMetadata < Struct
6
+ include Validatable
7
+
8
+ include Checkable
9
+
10
+ TYPES = ['https://cocina.sul.stanford.edu/models/object',
11
+ 'https://cocina.sul.stanford.edu/models/3d',
12
+ 'https://cocina.sul.stanford.edu/models/agreement',
13
+ 'https://cocina.sul.stanford.edu/models/book',
14
+ 'https://cocina.sul.stanford.edu/models/document',
15
+ 'https://cocina.sul.stanford.edu/models/geo',
16
+ 'https://cocina.sul.stanford.edu/models/image',
17
+ 'https://cocina.sul.stanford.edu/models/page',
18
+ 'https://cocina.sul.stanford.edu/models/photograph',
19
+ 'https://cocina.sul.stanford.edu/models/manuscript',
20
+ 'https://cocina.sul.stanford.edu/models/map',
21
+ 'https://cocina.sul.stanford.edu/models/media',
22
+ 'https://cocina.sul.stanford.edu/models/track',
23
+ 'https://cocina.sul.stanford.edu/models/webarchive-binary',
24
+ 'https://cocina.sul.stanford.edu/models/webarchive-seed'].freeze
25
+
26
+ # The version of Cocina with which this object conforms.
27
+ # example: 1.2.3
28
+ attribute :cocinaVersion, Types::Strict::String.default(Cocina::Models::VERSION)
29
+ # The content type of the DRO. Selected from an established set of values.
30
+ attribute :type, Types::Strict::String.enum(*DROWithMetadata::TYPES)
31
+ # example: druid:bc123df4567
32
+ attribute :externalIdentifier, Types::Strict::String
33
+ # Primary processing label (can be same as title) for a DRO.
34
+ attribute :label, Types::Strict::String
35
+ # Version for the DRO within SDR.
36
+ attribute :version, Types::Strict::Integer
37
+ attribute(:access, DROAccess.default { DROAccess.new })
38
+ attribute(:administrative, Administrative.default { Administrative.new })
39
+ attribute(:description, Description.default { Description.new })
40
+ attribute(:identification, Identification.default { Identification.new })
41
+ attribute(:structural, DROStructural.default { DROStructural.new })
42
+ attribute :geographic, Geographic.optional.meta(omittable: true)
43
+ # When the object was created.
44
+ attribute :created, Types::Params::DateTime.meta(omittable: true)
45
+ # When the object was modified.
46
+ attribute :modified, Types::Params::DateTime.meta(omittable: true)
47
+ # Key for optimistic locking. The contents of the key is not specified.
48
+ attribute :lock, Types::Strict::String
49
+ end
50
+ end
51
+ end
@@ -29,7 +29,7 @@ module Cocina
29
29
  attribute :label, Types::Strict::String
30
30
  # Version for the Fileset within SDR.
31
31
  attribute :version, Types::Strict::Integer
32
- attribute :structural, FileSetStructural.optional.meta(omittable: true)
32
+ attribute(:structural, FileSetStructural.default { FileSetStructural.new })
33
33
  end
34
34
  end
35
35
  end
@@ -12,7 +12,7 @@ module Cocina
12
12
  # Unique identifier in some other system. This is because a large proportion of what is deposited in SDR, historically and currently, are representations of objects that are also represented in other systems. For example, digitized paper and A/V collections have physical manifestations, and those physical objects are managed in systems that have their own identifiers. Similarly, books have barcodes, archival materials have collection numbers and physical locations, etc. The sourceId allows determining if an item has been deposited before and where to look for the original item if you're looking at its SDR representation. The format is: "namespace:identifier"
13
13
 
14
14
  # example: sul:PC0170_s3_Fiesta_Bowl_2012-01-02_210609_2026
15
- attribute :sourceId, Types::Strict::String.meta(omittable: true)
15
+ attribute :sourceId, Types::Strict::String
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cocina
4
+ module Models
5
+ class ObjectMetadata < Struct
6
+ # When the object was created.
7
+ attribute :created, Types::Params::DateTime.meta(omittable: true)
8
+ # When the object was modified.
9
+ attribute :modified, Types::Params::DateTime.meta(omittable: true)
10
+ # Key for optimistic locking. The contents of the key is not specified.
11
+ attribute :lock, Types::Strict::String
12
+ end
13
+ end
14
+ end
@@ -1,30 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'deprecation'
4
+
3
5
  module Cocina
4
6
  module Models
5
7
  # TitleBuilder selects the prefered title from the cocina object for solr indexing
6
8
  # rubocop:disable Metrics/ClassLength
7
9
  class TitleBuilder
8
- # @param [Cocina::Models::D*] cocina_object is the object to extract the title for
10
+ extend Deprecation
11
+ # @param [[Array<Cocina::Models::Title,Cocina::Models::DescriptiveValue>] titles the titles to consider
9
12
  # @param [Symbol] strategy ":first" is the strategy for selection when primary or display title are missing
10
13
  # @param [Boolean] add_punctuation determines if the title should be formmated with punctuation
11
14
  # @return [String] the title value for Solr
12
- def self.build(cocina_object, strategy: :first, add_punctuation: true)
13
- new(cocina_object, strategy: strategy, add_punctuation: add_punctuation).build_title
15
+ def self.build(titles, strategy: :first, add_punctuation: true)
16
+ if titles.respond_to?(:description)
17
+ Deprecation.warn(self, "Calling TitleBuilder.build with a #{titles.class} is deprecated. It must be called with an array of titles")
18
+ titles = titles.description.title
19
+ end
20
+ new(strategy: strategy, add_punctuation: add_punctuation).build(titles)
14
21
  end
15
22
 
16
- def initialize(cocina_object, strategy:, add_punctuation:)
17
- @cocina_object = cocina_object
23
+ def initialize(strategy:, add_punctuation:)
18
24
  @strategy = strategy
19
25
  @add_punctuation = add_punctuation
20
26
  end
21
27
 
28
+ # @param [[Array<Cocina::Models::Title>] titles the titles to consider
22
29
  # @return [String] the title value for Solr
23
- def build_title
24
- @titles = cocina_object.description.title
25
-
26
- cocina_title = primary_title || untyped_title
27
- cocina_title = other_title if cocina_title.blank?
30
+ def build(titles)
31
+ cocina_title = primary_title(titles) || untyped_title(titles)
32
+ cocina_title = other_title(titles) if cocina_title.blank?
28
33
 
29
34
  if strategy == :first
30
35
  extract_title(cocina_title)
@@ -35,7 +40,7 @@ module Cocina
35
40
 
36
41
  private
37
42
 
38
- attr_reader :cocina_object, :strategy, :titles
43
+ attr_reader :strategy
39
44
 
40
45
  def extract_title(cocina_title)
41
46
  result = if cocina_title.value
@@ -44,7 +49,7 @@ module Cocina
44
49
  title_from_structured_values(cocina_title.structuredValue,
45
50
  non_sorting_char_count(cocina_title))
46
51
  elsif cocina_title.parallelValue.present?
47
- return cocina_title.parallelValue.first.value
52
+ return build(cocina_title.parallelValue)
48
53
  end
49
54
  remove_trailing_punctuation(result.strip) if result.present?
50
55
  end
@@ -54,7 +59,7 @@ module Cocina
54
59
  end
55
60
 
56
61
  # @return [Cocina::Models::Title, nil] title that has status=primary
57
- def primary_title
62
+ def primary_title(titles)
58
63
  primary_title = titles.find do |title|
59
64
  title.status == 'primary'
60
65
  end
@@ -69,7 +74,7 @@ module Cocina
69
74
  end
70
75
  end
71
76
 
72
- def untyped_title
77
+ def untyped_title(titles)
73
78
  method = strategy == :first ? :find : :select
74
79
  untyped_title_for(titles.public_send(method))
75
80
  end
@@ -86,7 +91,7 @@ module Cocina
86
91
  end
87
92
 
88
93
  # This handles 'main title', 'uniform' or 'translated'
89
- def other_title
94
+ def other_title(titles)
90
95
  if strategy == :first
91
96
  titles.first
92
97
  else
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cocina
4
4
  module Models
5
- VERSION = '0.69.1'
5
+ VERSION = '0.71.0'
6
6
  end
7
7
  end
data/lib/cocina/models.rb CHANGED
@@ -21,6 +21,7 @@ class CocinaModelsInflector < Zeitwerk::Inflector
21
21
  'request_dro' => 'RequestDRO',
22
22
  'dro_access' => 'DROAccess',
23
23
  'dro_structural' => 'DROStructural',
24
+ 'dro_with_metadata' => 'DROWithMetadata',
24
25
  'request_dro_structural' => 'RequestDROStructural',
25
26
  'rspec' => 'RSpec',
26
27
  'version' => 'VERSION'
@@ -34,6 +35,8 @@ end
34
35
  loader = Zeitwerk::Loader.new
35
36
  loader.inflector = CocinaModelsInflector.new
36
37
  loader.push_dir(File.absolute_path("#{__FILE__}/../.."))
38
+ loader.ignore("#{__dir__}/rspec.rb")
39
+ loader.ignore("#{__dir__}/rspec/**/*.rb")
37
40
  loader.setup
38
41
 
39
42
  module Cocina
@@ -108,6 +111,38 @@ module Cocina
108
111
  clazz.new(dyn, false, validate)
109
112
  end
110
113
 
114
+ # Coerces DROWithMetadata, CollectionWithMetadata, AdminPolicyWithMetadata to DRO, Collection, AdminPolicy
115
+ # @param [DROWithMetadata,CollectionWithMetadata,AdminPolicyWithMetadata] cocina_object
116
+ # @return [DRO,Collection,AdminPolicy]
117
+ def self.without_metadata(cocina_object)
118
+ build(cocina_object.to_h.except(:created, :modified, :lock))
119
+ end
120
+
121
+ # Adds metadata to a DRO, Collection, AdminPolicy
122
+ # or updates for a DROWithMetadata, CollectionWithMetadata, AdminPolicyWithMetadata
123
+ # @param [DROWithMetadata,CollectionWithMetadata,
124
+ # AdminPolicyWithMetadata,DRO,Collection,AdminPolicy] cocina_object
125
+ # @param [String] lock
126
+ # @param [DateTime] created
127
+ # @param [DateTime] modified
128
+ # @return [DROWithMetadata,CollectionWithMetadata,AdminPolicyWithMetadata]
129
+ def self.with_metadata(cocina_object, lock, created: nil, modified: nil)
130
+ props = cocina_object.to_h
131
+ props[:created] = created.iso8601 if created
132
+ props[:modified] = modified.iso8601 if modified
133
+ props[:lock] = lock
134
+
135
+ clazz = case cocina_object.type
136
+ when *DRO::TYPES
137
+ DROWithMetadata
138
+ when *Collection::TYPES
139
+ CollectionWithMetadata
140
+ else
141
+ AdminPolicyWithMetadata
142
+ end
143
+ clazz.new(props)
144
+ end
145
+
111
146
  def self.type_for(dyn)
112
147
  dyn.with_indifferent_access.fetch('type')
113
148
  rescue KeyError
@@ -11,16 +11,21 @@ module Cocina
11
11
  matcher :cocina_object_with do |**kwargs|
12
12
  kwargs.each do |cocina_section, expected|
13
13
  match do |actual|
14
- expected.all? do |expected_key, expected_value|
15
- # NOTE: there's no better method on Hash that I could find for this.
16
- # #include? and #member? only check keys, not k/v pairs
17
- actual.public_send(cocina_section).to_h.any? do |actual_key, actual_value|
18
- if expected_value.is_a?(Hash) && actual_value.is_a?(Hash)
19
- expected_value.all? { |pair| actual_value.to_a.include?(pair) }
20
- else
21
- actual_key == expected_key && actual_value == expected_value
14
+ # created, modified, lock for *WithMetadata don't respond to all?
15
+ if expected.respond_to?(:all?)
16
+ expected.all? do |expected_key, expected_value|
17
+ # NOTE: there's no better method on Hash that I could find for this.
18
+ # #include? and #member? only check keys, not k/v pairs
19
+ actual.public_send(cocina_section).to_h.any? do |actual_key, actual_value|
20
+ if expected_value.is_a?(Hash) && actual_value.is_a?(Hash)
21
+ expected_value.all? { |pair| actual_value.to_a.include?(pair) }
22
+ else
23
+ actual_key == expected_key && actual_value == expected_value
24
+ end
22
25
  end
23
26
  end
27
+ else
28
+ expected == actual.public_send(cocina_section)
24
29
  end
25
30
  end
26
31
  end
data/openapi.yml CHANGED
@@ -31,6 +31,18 @@ paths:
31
31
  responses:
32
32
  '200':
33
33
  description: noop
34
+ /validate/DROWithMetadata:
35
+ post:
36
+ summary: Validate a DRO with object metadata
37
+ requestBody:
38
+ required: true
39
+ content:
40
+ application/json:
41
+ schema:
42
+ $ref: '#/components/schemas/DROWithMetadata'
43
+ responses:
44
+ '200':
45
+ description: noop
34
46
  /validate/Collection:
35
47
  post:
36
48
  summary: Validate a Collection
@@ -55,6 +67,18 @@ paths:
55
67
  responses:
56
68
  '200':
57
69
  description: noop
70
+ /validate/CollectionWithMetadata:
71
+ post:
72
+ summary: Validate a Collection with object metadata
73
+ requestBody:
74
+ required: true
75
+ content:
76
+ application/json:
77
+ schema:
78
+ $ref: '#/components/schemas/CollectionWithMetadata'
79
+ responses:
80
+ '200':
81
+ description: noop
58
82
  /validate/AdminPolicy:
59
83
  post:
60
84
  summary: Validate an AdminPolicy
@@ -79,6 +103,18 @@ paths:
79
103
  responses:
80
104
  '200':
81
105
  description: noop
106
+ /validate/AdminPolicyWithMetadata:
107
+ post:
108
+ summary: Validate an AdminPolicy with object metadata
109
+ requestBody:
110
+ required: true
111
+ content:
112
+ application/json:
113
+ schema:
114
+ $ref: '#/components/schemas/AdminPolicyWithMetadata'
115
+ responses:
116
+ '200':
117
+ description: noop
82
118
  /validate/Description:
83
119
  post:
84
120
  summary: Validate a Description
@@ -295,6 +331,14 @@ components:
295
331
  description: The license governing reuse of the Collection. Should be an IRI for known licenses (i.e. CC, RightsStatement.org URI, etc.).
296
332
  type: string
297
333
  nullable: true
334
+ # AdminPolicyWithMetadata schema should not be copied to sdr-api and dor-services-app.
335
+ AdminPolicyWithMetadata:
336
+ description: Admin Policy with addition object metadata.
337
+ type: object
338
+ additionalProperties: false
339
+ allOf:
340
+ - $ref: "#/components/schemas/AdminPolicy"
341
+ - $ref: "#/components/schemas/ObjectMetadata"
298
342
  AppliesTo:
299
343
  description: Property model for indicating the parts, aspects, or versions of the resource to which a
300
344
  descriptive element is applicable.
@@ -414,6 +458,8 @@ components:
414
458
  - type
415
459
  - version
416
460
  - access
461
+ - administrative
462
+ - identification
417
463
  CollectionAccess:
418
464
  description: Access metadata for collections
419
465
  type: object
@@ -450,6 +496,14 @@ components:
450
496
  $ref: '#/components/schemas/CatalogLink'
451
497
  sourceId:
452
498
  $ref: '#/components/schemas/SourceId'
499
+ # CollectionWithMetadata schema should not be copied to sdr-api and dor-services-app.
500
+ CollectionWithMetadata:
501
+ description: Collection with addition object metadata.
502
+ type: object
503
+ additionalProperties: false
504
+ allOf:
505
+ - $ref: "#/components/schemas/Collection"
506
+ - $ref: "#/components/schemas/ObjectMetadata"
453
507
  Contributor:
454
508
  description: Property model for describing agents contributing in some way to
455
509
  the creation and history of the resource.
@@ -894,6 +948,8 @@ components:
894
948
  - label
895
949
  - type
896
950
  - version
951
+ - identification
952
+ - structural
897
953
  DROAccess:
898
954
  type: object
899
955
  additionalProperties: false
@@ -968,6 +1024,14 @@ components:
968
1024
  type: array
969
1025
  items:
970
1026
  $ref: '#/components/schemas/Druid'
1027
+ # DROWithMetadata schema should not be copied to sdr-api and dor-services-app.
1028
+ DROWithMetadata:
1029
+ description: DRO with addition object metadata.
1030
+ type: object
1031
+ additionalProperties: false
1032
+ allOf:
1033
+ - $ref: "#/components/schemas/DRO"
1034
+ - $ref: "#/components/schemas/ObjectMetadata"
971
1035
  Druid:
972
1036
  type: string
973
1037
  pattern: '^druid:[b-df-hjkmnp-tv-z]{2}[0-9]{3}[b-df-hjkmnp-tv-z]{2}[0-9]{4}$'
@@ -1158,6 +1222,7 @@ components:
1158
1222
  - label
1159
1223
  - type
1160
1224
  - version
1225
+ - structural
1161
1226
  FileSetStructural:
1162
1227
  description: Structural metadata
1163
1228
  type: object
@@ -1191,6 +1256,8 @@ components:
1191
1256
  $ref: '#/components/schemas/DOI'
1192
1257
  sourceId:
1193
1258
  $ref: '#/components/schemas/SourceId'
1259
+ required:
1260
+ - sourceId
1194
1261
  Language:
1195
1262
  description: Languages, scripts, symbolic systems, and notations used in all
1196
1263
  or part of a resource or its descriptive metadata.
@@ -1343,6 +1410,25 @@ components:
1343
1410
  required:
1344
1411
  - type
1345
1412
  - digest
1413
+ # ObjectMetadata schema should not be copied to sdr-api and dor-services-app.
1414
+ ObjectMetadata:
1415
+ description: Metadata for a cocina object.
1416
+ type: object
1417
+ additionalProperties: false
1418
+ properties:
1419
+ created:
1420
+ description: When the object was created.
1421
+ type: string
1422
+ format: date-time
1423
+ modified:
1424
+ description: When the object was modified.
1425
+ type: string
1426
+ format: date-time
1427
+ lock:
1428
+ description: Key for optimistic locking. The contents of the key is not specified.
1429
+ type: string
1430
+ required:
1431
+ - lock
1346
1432
  Presentation:
1347
1433
  description: Presentation data for the File.
1348
1434
  type: object
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.69.1
4
+ version: 0.71.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Coyne
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-15 00:00:00.000000000 Z
11
+ date: 2022-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: deprecation
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: dry-struct
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -293,6 +307,7 @@ files:
293
307
  - lib/cocina/models/admin_policy.rb
294
308
  - lib/cocina/models/admin_policy_access_template.rb
295
309
  - lib/cocina/models/admin_policy_administrative.rb
310
+ - lib/cocina/models/admin_policy_with_metadata.rb
296
311
  - lib/cocina/models/administrative.rb
297
312
  - lib/cocina/models/applies_to.rb
298
313
  - lib/cocina/models/business_barcode.rb
@@ -304,6 +319,7 @@ files:
304
319
  - lib/cocina/models/collection.rb
305
320
  - lib/cocina/models/collection_access.rb
306
321
  - lib/cocina/models/collection_identification.rb
322
+ - lib/cocina/models/collection_with_metadata.rb
307
323
  - lib/cocina/models/contributor.rb
308
324
  - lib/cocina/models/controlled_digital_lending_access.rb
309
325
  - lib/cocina/models/dark_access.rb
@@ -324,6 +340,7 @@ files:
324
340
  - lib/cocina/models/dro_access.rb
325
341
  - lib/cocina/models/dro_rights_description_builder.rb
326
342
  - lib/cocina/models/dro_structural.rb
343
+ - lib/cocina/models/dro_with_metadata.rb
327
344
  - lib/cocina/models/druid.rb
328
345
  - lib/cocina/models/embargo.rb
329
346
  - lib/cocina/models/event.rb
@@ -341,6 +358,7 @@ files:
341
358
  - lib/cocina/models/location_based_access.rb
342
359
  - lib/cocina/models/location_based_download_access.rb
343
360
  - lib/cocina/models/message_digest.rb
361
+ - lib/cocina/models/object_metadata.rb
344
362
  - lib/cocina/models/object_type.rb
345
363
  - lib/cocina/models/presentation.rb
346
364
  - lib/cocina/models/purl.rb
@@ -377,7 +395,7 @@ homepage: https://github.com/sul-dlss/cocina-models
377
395
  licenses: []
378
396
  metadata:
379
397
  rubygems_mfa_required: 'true'
380
- post_install_message:
398
+ post_install_message:
381
399
  rdoc_options: []
382
400
  require_paths:
383
401
  - lib
@@ -393,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
393
411
  version: '0'
394
412
  requirements: []
395
413
  rubygems_version: 3.2.32
396
- signing_key:
414
+ signing_key:
397
415
  specification_version: 4
398
416
  summary: Data models for the SDR
399
417
  test_files: []