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 +4 -4
- data/.rubocop.yml +1 -1
- data/README.md +21 -2
- data/cocina-models.gemspec +1 -0
- data/lib/cocina/generator/schema.rb +6 -3
- data/lib/cocina/models/admin_policy_with_metadata.rb +30 -0
- data/lib/cocina/models/collection.rb +2 -2
- data/lib/cocina/models/collection_with_metadata.rb +39 -0
- data/lib/cocina/models/dro.rb +2 -2
- data/lib/cocina/models/dro_with_metadata.rb +51 -0
- data/lib/cocina/models/file_set.rb +1 -1
- data/lib/cocina/models/identification.rb +1 -1
- data/lib/cocina/models/object_metadata.rb +14 -0
- data/lib/cocina/models/title_builder.rb +20 -15
- data/lib/cocina/models/version.rb +1 -1
- data/lib/cocina/models.rb +35 -0
- data/lib/cocina/rspec/matchers.rb +13 -8
- data/openapi.yml +86 -0
- metadata +23 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5058bc2927b8788ad9c04142decbfcc7cf42b7daa3b84665d64dd00b432d8ff4
|
4
|
+
data.tar.gz: 524263003bc679432b5c120690775de4ebc14ef5fa6158337e0beff9c2bfb332
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz: '
|
6
|
+
metadata.gz: b84f98459177c74cc822a8dee105412c7023c3fda2e953e1f760c482ae3a2967f610207bb53cd33c510e2b0c861834b4cf1998459b70035ac9b22aa55c83b910
|
7
|
+
data.tar.gz: '018baa839ef5774c3969f91acb9545fb04ddf3be652ae3f3fafbc6458ddd7ec1d7c4ae5d5d33a9a8eab36476519cd310a33b61da34e4f934bef35ef490dc83fd'
|
data/.rubocop.yml
CHANGED
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
|
-
|
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:
|
data/cocina-models.gemspec
CHANGED
@@ -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
|
-
|
51
|
-
return '' if
|
50
|
+
type_schema_property = schema_properties.find { |schema_property| schema_property.key == 'type' }
|
51
|
+
return '' if type_schema_property.nil?
|
52
52
|
|
53
|
-
|
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
|
28
|
+
attribute(:administrative, Administrative.default { Administrative.new })
|
29
29
|
attribute(:description, Description.default { Description.new })
|
30
|
-
attribute
|
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
|
data/lib/cocina/models/dro.rb
CHANGED
@@ -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
|
41
|
-
attribute
|
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
|
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
|
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
|
-
|
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(
|
13
|
-
|
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(
|
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
|
24
|
-
|
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 :
|
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
|
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
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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.
|
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-
|
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: []
|