valkyrie 2.0.0.RC1 → 2.0.0.RC3

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: 3a6595012901f53ab2c47eca1f7aca4e02c6de433ab564c026ea23fc4157ae88
4
- data.tar.gz: 20ad473091497657070518c0b019a92436db6cc18b829aed53288c876b29a684
3
+ metadata.gz: 46ec28ef4c223e885ba6b6e5c8cb9e53d87ee08e550db09dd1d655af768a4043
4
+ data.tar.gz: 87b33c7db9d9211b4a8c294a9f6aeef8e2b06487523324eedcec2850960e6963
5
5
  SHA512:
6
- metadata.gz: 0deef685a04e187a7e8352aad5ff9bb7431617b905d03da8222b3f3591bc472f6cf9188bfd426d2afa221dd5778fed3f120c2e99d4e75d95b1d51fe0f66c9d0e
7
- data.tar.gz: 27c8e622b13e742ce3f4a6ec88d0d72daa3f90163ce5aba1658a77c4fb0d825349dec1867d1c8a4b1f8a48350c7d40a0f82fb129aa29e060585142b6456d6c85
6
+ metadata.gz: 475e3c5bc3064c1515fcad708c682eb90151dcea9d13628402125eccddceb786b4892b8d8945ec6bbc1bcc6429561c7e458f34aac45d3a8cb035db0c0a4328c4
7
+ data.tar.gz: a938133503843f807466f4ebb4bff76b09eaab6d615fe6d17b6b3dcf2d6af9841a6561815d8e16191fcbacfe5b4513094804140f3433e5214bc45427f4d1ac87
data/.circleci/config.yml CHANGED
@@ -11,6 +11,9 @@ jobs:
11
11
  curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
12
12
  chmod +x ~/docker-compose
13
13
  sudo mv ~/docker-compose /usr/local/bin/docker-compose
14
+ - run:
15
+ name: Update bundler
16
+ command: gem install bundler -v 1.16.2
14
17
  - restore_cache:
15
18
  keys:
16
19
  - bundle-{{ checksum "Gemfile" }}-{{ checksum "valkyrie.gemspec" }}
data/CHANGELOG.md CHANGED
@@ -1,3 +1,105 @@
1
+ # v1.5.0 2018-02-06
2
+
3
+ ## Changes since last release
4
+
5
+ * Fix solr casting when an updated_at key isn't present in the solr document.
6
+ [tpendragon](https://github.com/tpendragon)
7
+ * Add missing query service requirement to persister shared specs
8
+ [cjcolvar](https://github.com/cjcolvar)
9
+ * Provide a warning when postgres adapter overwrites an ID, deprecate this
10
+ behavior so it will throw an exception in the future.
11
+ [cam156](https://github.com/cam156)
12
+ [hackmastera](https://github.com/hackmastera)
13
+ [tpendragon](https://github.com/tpendragon)
14
+ * Add support for passing just an ID to find_inverse_references_by
15
+ [cam156](https://github.com/cam156)
16
+ [hackmastera](https://github.com/hackmastera)
17
+ * Fix memory adapter raising an exception in find_by_alternate_identifier when
18
+ there are resources without the alternate_identifier attribute.
19
+ [jeremyf](https://github.com/jeremyf)
20
+ * Provide a warning when using the postgres adapter without manually providing
21
+ the pg gem, so it can be an optional dependency in 2.0.0.
22
+ [hackmastera](https://github.com/hackmastera)
23
+ * Provide guidance in specs on how to define alternate_ids
24
+ [cjcolvar](https://github.com/cjcolvar)
25
+ * Upload files to Fedora using form/multipart.
26
+ [tpendragon](https://github.com/tpendragon)
27
+ * Improve CompositePersister documentation.
28
+ [tpendragon](https://github.com/tpendragon)
29
+ * Add a Valkyrie::Types::Params::ID type which handles when an HTML form passes
30
+ an empty string value.
31
+ [tpendragon](https://github.com/tpendragon)
32
+ * Deprecate .member on Valkyrie::Types::Array & Set
33
+ [tpendragon](https://github.com/tpendragon)
34
+ * Fix updated_at not being set correctly for the Solr adapter, fix shared specs.
35
+ [tpendragon](https://github.com/tpendragon)
36
+
37
+ Additional thanks to the following for code review and issue reports leading to
38
+ this release:
39
+
40
+ [awead](https://github.com/awead)
41
+ [escowles](https://github.com/escowles)
42
+ [kelynch](https://github.com/kelynch)
43
+ [mbklein](https://github.com/mbklein)
44
+ [mjgiarlo](https://github.com/mjgiarlo)
45
+ [no-reply](https://github.com/no-reply)
46
+ [revgum](https://github.com/revgum)
47
+
48
+ # v1.5.0 RC2 2018-02-01
49
+
50
+ ## Changes since last release
51
+
52
+ * Fix solr casting when an updated_at key isn't present in the solr document.
53
+ [tpendragon](https://github.com/tpendragon)
54
+
55
+ Additional thanks to the following for code review:
56
+
57
+ [mjgiarlo](https://github.com/mjgiarlo)
58
+
59
+ # v1.5.0 RC1 2018-02-01
60
+
61
+ ## Changes since last release
62
+
63
+ * Add missing query service requirement to persister shared specs
64
+ [cjcolvar](https://github.com/cjcolvar)
65
+ * Provide a warning when postgres adapter overwrites an ID, deprecate this
66
+ behavior so it will throw an exception in the future.
67
+ [cam156](https://github.com/cam156)
68
+ [hackmastera](https://github.com/hackmastera)
69
+ [tpendragon](https://github.com/tpendragon)
70
+ * Add support for passing just an ID to find_inverse_references_by
71
+ [cam156](https://github.com/cam156)
72
+ [hackmastera](https://github.com/hackmastera)
73
+ * Fix memory adapter raising an exception in find_by_alternate_identifier when
74
+ there are resources without the alternate_identifier attribute.
75
+ [jeremyf](https://github.com/jeremyf)
76
+ * Provide a warning when using the postgres adapter without manually providing
77
+ the pg gem, so it can be an optional dependency in 2.0.0.
78
+ [hackmastera](https://github.com/hackmastera)
79
+ * Provide guidance in specs on how to define alternate_ids
80
+ [cjcolvar](https://github.com/cjcolvar)
81
+ * Upload files to Fedora using form/multipart.
82
+ [tpendragon](https://github.com/tpendragon)
83
+ * Improve CompositePersister documentation.
84
+ [tpendragon](https://github.com/tpendragon)
85
+ * Add a Valkyrie::Types::Params::ID type which handles when an HTML form passes
86
+ an empty string value.
87
+ [tpendragon](https://github.com/tpendragon)
88
+ * Deprecate .member on Valkyrie::Types::Array & Set
89
+ [tpendragon](https://github.com/tpendragon)
90
+ * Fix updated_at not being set correctly for the Solr adapter, fix shared specs.
91
+ [tpendragon](https://github.com/tpendragon)
92
+
93
+ Additional thanks to the following for code review and issue reports leading to
94
+ this release:
95
+
96
+ [awead](https://github.com/awead)
97
+ [escowles](https://github.com/escowles)
98
+ [kelynch](https://github.com/kelynch)
99
+ [mbklein](https://github.com/mbklein)
100
+ [no-reply](https://github.com/no-reply)
101
+ [revgum](https://github.com/revgum)
102
+
1
103
  # v1.4.0 2018-01-08
2
104
 
3
105
  ## Changes since last release.
@@ -0,0 +1,36 @@
1
+ The Samvera community is dedicated to providing a welcoming and
2
+ positive experience for all its members, whether they are at a formal
3
+ gathering, in a social setting, or taking part in activities online.
4
+ The Samvera community welcomes participation from people all over the
5
+ world and these members bring with them a wide variety of
6
+ professional, personal and social backgrounds; whatever these may be,
7
+ we treat colleagues with dignity and respect.
8
+
9
+ Community members communicate primarily in English, though for many of
10
+ them this is not their native language. We therefore strive to express
11
+ ourselves simply and clearly remembering that unnecessary use of
12
+ jargon and slang will be a barrier to understanding for many of our
13
+ colleagues. We are sensitive to the fact that the international
14
+ nature of the community means that we span many different social norms
15
+ around language and behaviour and we strive to conduct ourselves,
16
+ online and in person, in ways that are unlikely to cause offence.
17
+
18
+ Samvera conversations are often information-rich and intended to
19
+ generate discussion and debate. We discuss ideas from a standpoint of
20
+ mutual respect and reasoned argument.
21
+
22
+ Community members work together to promote a respectful and safe
23
+ community. In the event that someone’s conduct is causing offence or
24
+ distress, Samvera has a detailed
25
+ [Anti-Harassment Policy and Protocol](https://wiki.duraspace.org/display/samvera/Anti-Harassment+Policy)
26
+ which can be applied to address the problem. The first step in dealing
27
+ with any serious misconduct is to contact a local meeting organizer,
28
+ the
29
+ [Samvera community helpers](https://wiki.duraspace.org/display/samvera/Samvera+Community+Helpers)
30
+ ([email](mailto:helpers@samvera.org)), a community member you
31
+ trust, or the
32
+ [Samvera Steering Group](https://wiki.duraspace.org/display/samvera/Samvera+Steering+Group+membership)
33
+ immediately; at Samvera events, these people can be identified by
34
+ distinctive name badges. The
35
+ [Policy and Protocol](https://wiki.duraspace.org/display/samvera/Anti-Harassment+Policy)
36
+ should be consulted for fuller details.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,161 @@
1
+ # How to Contribute
2
+
3
+ We want your help to make the Samvera community great. There are a few guidelines
4
+ that we need contributors to follow so that we can have a chance of
5
+ keeping on top of things.
6
+
7
+ ## Code of Conduct
8
+
9
+ The Samvera Community is dedicated to providing a welcoming and positive
10
+ experience for all its members, whether they are at a formal gathering, in
11
+ a social setting, or taking part in activities online. Please see our
12
+ [Code of Conduct](CODE_OF_CONDUCT.md) for more information.
13
+
14
+ ## Samvera Community Intellectual Property Licensing and Ownership
15
+
16
+ All code contributors must have an Individual Contributor License Agreement
17
+ (iCLA) on file with the Samvera Steering Group. If the contributor works for
18
+ an institution, the institution must have a Corporate Contributor License
19
+ Agreement (cCLA) on file.
20
+
21
+ https://wiki.duraspace.org/display/samvera/Samvera+Community+Intellectual+Property+Licensing+and+Ownership
22
+
23
+ You should also add yourself to the `CONTRIBUTORS.md` file in the root of the project.
24
+
25
+ ## Contribution Tasks
26
+
27
+ * Reporting Issues
28
+ * Making Changes
29
+ * Documenting Code
30
+ * Committing Changes
31
+ * Submitting Changes
32
+ * Reviewing and Merging Changes
33
+
34
+ ### Reporting Issues
35
+
36
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
37
+ * Submit a [Github issue](https://github.com/samvera-labs/valkyrie/issues/) by:
38
+ * Clearly describing the issue
39
+ * Provide a descriptive summary
40
+ * Explain the expected behavior
41
+ * Explain the actual behavior
42
+ * Provide steps to reproduce the actual behavior
43
+
44
+ ### Making Changes
45
+
46
+ * Fork the repository on GitHub
47
+ * Create a topic branch from where you want to base your work.
48
+ * This is usually the master branch.
49
+ * To quickly create a topic branch based on master; `git branch fix/master/my_contribution master`
50
+ * Then checkout the new branch with `git checkout fix/master/my_contribution`.
51
+ * Please avoid working directly on the `master` branch.
52
+ * You may find the [hub suite of commands](https://github.com/defunkt/hub) helpful
53
+ * Make sure you have added sufficient tests and documentation for your changes.
54
+ * Test functionality with RSpec; Test features / UI with Capybara.
55
+ * Run _all_ the tests to assure nothing else was accidentally broken.
56
+
57
+ ### Documenting Code
58
+
59
+ * All new public methods, modules, and classes should include inline documentation in [YARD](http://yardoc.org/).
60
+ * Documentation should seek to answer the question "why does this code exist?"
61
+ * Document private / protected methods as desired.
62
+ * If you are working in a file with no prior documentation, do try to document as you gain understanding of the code.
63
+ * If you don't know exactly what a bit of code does, it is extra likely that it needs to be documented. Take a stab at it and ask for feedback in your pull request. You can use the 'blame' button on GitHub to identify the original developer of the code and @mention them in your comment.
64
+ * This work greatly increases the usability of the code base and supports the on-ramping of new committers.
65
+ * We will all be understanding of one another's time constraints in this area.
66
+ * [Getting started with YARD](http://www.rubydoc.info/gems/yard/file/docs/GettingStarted.md)
67
+
68
+ ### Committing Changes
69
+
70
+ * Make commits of logical units.
71
+ * Check for unnecessary whitespace with `git diff --check` before committing.
72
+ * Make sure your commit messages are [well formed](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
73
+ * If you created an issue, you can close it by including "Closes #issue" in your commit message. See [Github's blog post for more details](https://github.com/blog/1386-closing-issues-via-commit-messages)
74
+
75
+ ```
76
+ Present tense short summary (50 characters or less)
77
+
78
+ More detailed description, if necessary. It should be wrapped to 72
79
+ characters. Try to be as descriptive as you can, even if you think that
80
+ the commit content is obvious, it may not be obvious to others. You
81
+ should add such description also if it's already present in bug tracker,
82
+ it should not be necessary to visit a webpage to check the history.
83
+
84
+ Include Closes #<issue-number> when relavent.
85
+
86
+ Description can have multiple paragraphs and you can use code examples
87
+ inside, just indent it with 4 spaces:
88
+
89
+ class PostsController
90
+ def index
91
+ respond_to do |wants|
92
+ wants.html { render 'index' }
93
+ end
94
+ end
95
+ end
96
+
97
+ You can also add bullet points:
98
+
99
+ - you can use dashes or asterisks
100
+
101
+ - also, try to indent next line of a point for readability, if it's too
102
+ long to fit in 72 characters
103
+ ```
104
+
105
+ * Make sure you have added the necessary tests for your changes.
106
+ * Run _all_ the tests to assure nothing else was accidentally broken.
107
+ * Then you are ready to submit a pull request
108
+
109
+ ### Submitting Changes
110
+
111
+ * Read the article ["Using Pull Requests"](https://help.github.com/articles/using-pull-requests) on GitHub.
112
+ * Make sure your branch is up to date with its parent branch (i.e. master)
113
+ * `git checkout master`
114
+ * `git pull --rebase`
115
+ * `git checkout <your-branch>`
116
+ * `git rebase master`
117
+ * It is a good idea to run your tests again.
118
+ * If you've made more than one commit take a moment to consider whether squashing commits together would help improve their logical grouping.
119
+ * [Detailed Walkthrough of One Pull Request per Commit](http://ndlib.github.io/practices/one-commit-per-pull-request/)
120
+ * `git rebase --interactive master` ([See Github help](https://help.github.com/articles/interactive-rebase))
121
+ * Squashing your branch's changes into one commit is "good form" and helps the person merging your request to see everything that is going on.
122
+ * Push your changes to a topic branch in your fork of the repository.
123
+ * Submit a pull request from your fork to the project.
124
+
125
+ ### Reviewing and Merging Changes
126
+
127
+ We adopted [Github's Pull Request Review](https://help.github.com/articles/about-pull-request-reviews/) for our repositories.
128
+ Common checks that may occur in our repositories:
129
+
130
+ 1. Travis CI - where our automated tests are running
131
+ 2. Approval Required - Github enforces at least one person approve a pull request. Also, all reviewers that have chimed in must approve.
132
+
133
+ If one or more of the required checks failed (or are incomplete), the code should not be merged (and the UI will not allow it). If all of the checks have passed, then anyone on the project (including the pull request submitter) may merge the code.
134
+
135
+ *Example: Carolyn submits a pull request, Justin reviews the pull request and approves. However, Justin is still waiting on other checks (Travis CI is usually the culprit), so he does not merge the pull request. Eventually, all of the checks pass. At this point, Carolyn or anyone else may merge the pull request.*
136
+
137
+ #### Things to Consider When Reviewing
138
+
139
+ First, the person contributing the code is putting themselves out there. Be mindful of what you say in a review.
140
+
141
+ * Ask clarifying questions
142
+ * State your understanding and expectations
143
+ * Provide example code or alternate solutions, and explain why
144
+
145
+ This is your chance for a mentoring moment of another developer. Take time to give an honest and thorough review of what has changed. Things to consider:
146
+
147
+ * Does the commit message explain what is going on?
148
+ * Does the code changes have tests? _Not all changes need new tests, some changes are refactorings_
149
+ * Do new or changed methods, modules, and classes have documentation?
150
+ * Does the commit contain more than it should? Are two separate concerns being addressed in one commit?
151
+ * Does the description of the new/changed specs match your understanding of what the spec is doing?
152
+ * Did the Travis tests complete successfully?
153
+
154
+ If you are uncertain, bring other contributors into the conversation by assigning them as a reviewer.
155
+
156
+ # Additional Resources
157
+
158
+ * [General GitHub documentation](http://help.github.com/)
159
+ * [GitHub pull request documentation](https://help.github.com/articles/about-pull-requests/)
160
+ * [Pro Git](http://git-scm.com/book) is both a free and excellent book about Git.
161
+ * [A Git Config for Contributing](http://ndlib.github.io/practices/my-typical-per-project-git-config/)
data/Gemfile CHANGED
@@ -3,3 +3,5 @@ source 'https://rubygems.org'
3
3
 
4
4
  # Specify your gem's dependencies in valkyrie.gemspec
5
5
  gemspec
6
+
7
+ gem 'pg'
data/README.md CHANGED
@@ -4,22 +4,30 @@ Valkyrie is a gem for enabling multiple backends for storage of files and metada
4
4
 
5
5
  ![Valkyrie Logo](valkyrie_logo.png)
6
6
 
7
- [![CircleCI](https://circleci.com/gh/samvera-labs/valkyrie.svg?style=svg)](https://circleci.com/gh/samvera-labs/valkyrie)
7
+ Code: [![Version](https://badge.fury.io/rb/valkyrie.png)](http://badge.fury.io/rb/valkyrie)
8
+ [![Build Status](https://circleci.com/gh/samvera-labs/valkyrie.svg?style=svg)](https://circleci.com/gh/samvera-labs/valkyrie)
8
9
  [![Coverage Status](https://coveralls.io/repos/github/samvera-labs/valkyrie/badge.svg?branch=master)](https://coveralls.io/github/samvera-labs/valkyrie?branch=master)
9
10
  [![Stories in Ready](https://badge.waffle.io/samvera-labs/valkyrie.png?label=ready&title=Ready)](https://waffle.io/samvera-labs/valkyrie)
11
+
12
+ Docs: [![Contribution Guidelines](http://img.shields.io/badge/CONTRIBUTING-Guidelines-blue.svg)](./CONTRIBUTING.md)
13
+ [![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)
10
14
  [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/github/samvera-labs/valkyrie)
11
15
 
16
+ Jump in: [![Slack Status](http://slack.samvera.org/badge.svg)](http://slack.samvera.org/)
17
+
12
18
  ## Primary Contacts
13
19
 
14
20
  ### Product Owner
15
-
16
21
  [Carolyn Cole](https://github.com/cam156)
17
22
 
18
23
  ### Technical Lead
19
-
20
24
  [Trey Pendragon](https://github.com/tpendragon)
21
25
 
22
- ## Installation
26
+ ## Help
27
+
28
+ The Samvera community is here to help. Please see our [support guide](./SUPPORT.md).
29
+
30
+ ## Getting Started
23
31
 
24
32
  Add this line to your application's Gemfile:
25
33
 
@@ -37,7 +45,6 @@ Valkyrie is configured in two places: an initializer that registers the persiste
37
45
  configuration file that sets which options are used by default in which environments.
38
46
 
39
47
  ### Sample initializer: `config/initializers/valkyrie.rb`:
40
-
41
48
  Here is a sample initializer that registers a couple adapters and storage adapters, in each case linking an
42
49
  instance with a short name that can be used to refer to it in your application:
43
50
 
@@ -45,7 +52,11 @@ instance with a short name that can be used to refer to it in your application:
45
52
  ```
46
53
  # frozen_string_literal: true
47
54
  require 'valkyrie'
55
+
56
+
48
57
  Rails.application.config.to_prepare do
58
+
59
+ # To use the postgres adapter you must add `gem 'pg'` to your Gemfile
49
60
  Valkyrie::MetadataAdapter.register(
50
61
  Valkyrie::Persistence::Postgres::MetadataAdapter.new,
51
62
  :postgres
@@ -81,7 +92,8 @@ The initializer registers two `Valkyrie::MetadataAdapter` instances for storing
81
92
 
82
93
  Other adapter options include `Valkyrie::Persistence::BufferedPersister` for buffering in memory before bulk
83
94
  updating another persister, `Valkyrie::Persistence::CompositePersister` for storing in more than one adapter
84
- at once, `Valkyrie::Persistence::Solr` for storing in Solr, and `Valkyrie::Persistence::Fedora` for storing in Fedora.
95
+ at once, `Valkyrie::Persistence::Solr` for storing in Solr, and `Valkyrie::Persistence::Fedora` for storing
96
+ in Fedora.
85
97
 
86
98
  The initializer also registers three `Valkyrie::StorageAdapter` instances for storing files:
87
99
  * `:disk` which stores files on disk
@@ -89,8 +101,17 @@ The initializer also registers three `Valkyrie::StorageAdapter` instances for st
89
101
  * `:memory` which stores files in an in-memory cache (again, not persistent, so this is only appropriate for
90
102
  testing)
91
103
 
92
- ### Sample configuration: `config/valkyrie.yml`:
104
+ ### Sample configuration with custom `Valkyrie.config.resource_class_resolver`:
105
+ ```
106
+ require 'valkyrie'
107
+ Rails.application.config.to_prepare do
108
+ Valkyrie.config.resource_class_resolver = lambda do |resource_klass_name|
109
+ # Do complicated lookup based on the string
110
+ end
111
+ end
112
+ ```
93
113
 
114
+ ### Sample configuration: `config/valkyrie.yml`:
94
115
  A sample configuration file that configures your application to use different adapters:
95
116
 
96
117
  ```
@@ -113,26 +134,12 @@ For each environment, you must set two values:
113
134
 
114
135
  The values are the short names used in your initializer.
115
136
 
116
- Further details can be found on the [the Wiki](https://github.com/samvera-labs/valkyrie/wiki/Persistence).
137
+ Further details can be found on the [Persistence Wiki
138
+ page](https://github.com/samvera-labs/valkyrie/wiki/Persistence).
117
139
 
118
140
  ## Usage
119
141
 
120
- ### The Public API
121
-
122
- Valkyrie's public API is defined by the shared specs that are used to test each of its core classes.
123
- This include change sets, resources, persisters, adapters, and queries. When creating your own kinds of
124
- these kinds of classes, you should use these shared specs to test your classes for conformance to
125
- Valkyrie's API.
126
-
127
- When breaking changes are introduced, necessitating a major version change, the shared specs will reflect
128
- this. When new features are added and a minor version is released there will be no change to the existing shared
129
- specs, but there may be new ones. These new shared specs will fail in your
130
- application if you have custom adapters, but your application will still work.
131
-
132
- Using the shared specs in your own models is described in more [detail](https://github.com/samvera-labs/valkyrie/wiki/Shared-Specs).
133
-
134
142
  ### Define a Custom Work
135
-
136
143
  Define a custom work class:
137
144
 
138
145
  ```
@@ -151,7 +158,8 @@ order of multiple values.
151
158
  attribute :authors, Valkyrie::Types::Array.meta(ordered: true)
152
159
  ```
153
160
 
154
- Defining resource attributes is explained in greater detail within the [Wiki](https://github.com/samvera-labs/valkyrie/wiki/Using-Types).
161
+ Defining resource attributes is explained in greater detail on the [Using Types Wiki
162
+ page](https://github.com/samvera-labs/valkyrie/wiki/Using-Types).
155
163
 
156
164
  #### Work Types Generator
157
165
 
@@ -169,7 +177,6 @@ rails generate valkyrie:resource Foo/Bar title member_ids:array
169
177
  ```
170
178
 
171
179
  ### Read and Write Data
172
-
173
180
  ```
174
181
  # initialize a metadata adapter
175
182
  adapter = Valkyrie::MetadataAdapter.find(:postgres)
@@ -188,44 +195,64 @@ objects = adapter.query_service.find_all
188
195
  Valkyrie.config.metadata_adapter.query_service.find_all_of_model(model: MyModel)
189
196
  ```
190
197
 
191
- The usage of `ChangeSets` in writing data are further documented [here](https://github.com/samvera-labs/valkyrie/wiki/ChangeSets-and-Dirty-Tracking).
198
+ The Wiki documents the usage of [Queries](https://github.com/samvera-labs/valkyrie/wiki/Queries),
199
+ [Persistence](https://github.com/samvera-labs/valkyrie/wiki/Persistence), and
200
+ [ChangeSets and Dirty Tracking](https://github.com/samvera-labs/valkyrie/wiki/ChangeSets-and-Dirty-Tracking).
192
201
 
193
- ### Concurrency Support (Optimistic Locking)
194
- By default, it is assumed that a Valkyrie repository implementation shall use a solution supporting concurrent updates for resources (multiple resources can be updated simultaneously using a Gem such as [Sidekiq](https://github.com/mperham/sidekiq)). In order to handle the possibility of multiple updates applied to the same resource corrupting data, Valkyrie supports optimistic locking. For further details, please reference the [overview of optimistic locking for Valkyrie resources](https://github.com/samvera-labs/valkyrie/wiki/Optimistic-Locking).
202
+ ### Concurrency Support
203
+ A Valkyrie repository may have concurrent updates, for example, from a load-balanced Rails application, or
204
+ from multiple [Sidekiq](https://github.com/mperham/sidekiq) background workers). In order to prevent multiple
205
+ simultaneous updates applied to the same resource from losing or corrupting data, Valkyrie supports optimistic
206
+ locking. How to use optimistic locking with Valkyrie is documented on the [Optimistic Locking Wiki
207
+ page](https://github.com/samvera-labs/valkyrie/wiki/Optimistic-Locking).
195
208
 
196
- ## Installing a Development environment
209
+ ### The Public API
210
+ Valkyrie's public API is defined by the shared specs that are used to test each of its core classes.
211
+ This include change sets, resources, persisters, adapters, and queries. When creating your own kinds of
212
+ these kinds of classes, you should use these shared specs to test your classes for conformance to
213
+ Valkyrie's API.
197
214
 
198
- ### Without Docker
215
+ When breaking changes are introduced, necessitating a major version change, the shared specs will reflect
216
+ this. When new features are added and a minor version is released there will be no change to the existing
217
+ shared specs, but there may be new ones. These new shared specs will fail in your application if you have
218
+ custom adapters, but your application will still work.
199
219
 
200
- #### External Requirements
201
- * PostgreSQL with the uuid-ossp extension.
202
- * Note: Enabling uuid-ossp requires database superuser privileges.
203
- * From `psql`: `alter user [username] with superuser;`
220
+ Using the shared specs in your own models is described in more detail on the [Shared Specs Wiki
221
+ page](https://github.com/samvera-labs/valkyrie/wiki/Shared-Specs).
204
222
 
205
- #### To run the test suite
206
- 1. Start Solr and Fedora servers for testing with `rake server:test`
207
- 1. Run `rake db:create` (First time only)
208
- 1. Run `rake db:migrate`
223
+ ### Fedora 5 Compatibility
224
+ When configuring your adapter, include the `fedora_version` parameter in your metadata or storage adapter
225
+ config. If Fedora requires auth, you can also include that in the URL, e.g.:
226
+
227
+ ```
228
+ Valkyrie::Storage::Fedora.new(
229
+ connection: Ldp::Client.new("http://fedoraAdmin:fedoraAdmin@localhost:8988/rest"),
230
+ fedora_version: 5
231
+ )
232
+ ```
233
+
234
+ ## Installing a Development environment
209
235
 
210
236
  ### With Docker
237
+ The development and test stacks use fully contained virtual volumes and bind all services to different ports,
238
+ so they can be running at the same time without issue.
211
239
 
212
240
  #### External Requirements
213
241
  * [Docker](https://store.docker.com/search?offering=community&type=edition) version >= 17.09.0
214
- *
215
- ### Dependency Setup (Mac OSX)
216
242
 
243
+ ### Dependency Setup (Mac OSX)
217
244
  1. `brew install docker`
218
245
  1. `brew install docker-machine`
219
246
  1. `brew install docker-compose`
220
247
 
221
248
  ### Starting Docker (Mac OSX)
222
-
223
249
  1. `docker-machine create default`
224
250
  1. `docker-machine start default`
225
251
  1. `eval "$(docker-machine env)"`
226
252
 
227
253
  #### Starting the development mode dependencies
228
- 1. Start Solr, Fedora, and PostgreSQL with `rake docker:dev:daemon` (or `rake docker:dev:up` in a separate shell to run them in the foreground)
254
+ 1. Start Solr, Fedora, and PostgreSQL with `rake docker:dev:daemon` (or `rake docker:dev:up` in a separate
255
+ shell to run them in the foreground)
229
256
  1. Run `rake db:create db:migrate` to initialize the database
230
257
  1. Develop!
231
258
  1. Run `rake docker:dev:down` to stop the server stack
@@ -235,31 +262,31 @@ By default, it is assumed that a Valkyrie repository implementation shall use a
235
262
  1. `rake docker:spec`
236
263
 
237
264
  #### To run the test suite manually
238
- 1. Start Solr, Fedora, and PostgreSQL with `rake docker:test:daemon` (or `rake docker:test:up` in a separate shell to run them in the foreground)
265
+ 1. Start Solr, Fedora, and PostgreSQL with `rake docker:test:daemon` (or `rake docker:test:up` in a separate
266
+ shell to run them in the foreground)
239
267
  1. Run `rake db:create db:migrate` to initialize the database
240
268
  1. Run the gem's RSpec test suite with `rspec spec` or `rake`
241
269
  1. Run `rake docker:test:down` to stop the server stack
242
270
  * The test stack cleans up after itself on exit.
243
271
 
244
- ## Fedora 5 Compatibility
245
- When configuring your adapter, include the `fedora_version` parameter in your metadata or storage adapter config. If Fedora requires auth, you can also include that in the URL, e.g.:
246
- ```
247
- Valkyrie::Storage::Fedora.new(connection: Ldp::Client.new("http://fedoraAdmin:fedoraAdmin@localhost:8988/rest"), fedora_version: 5)
248
- ```
249
-
250
- The development and test stacks use fully contained virtual volumes and bind all services to different ports, so they can be running at the same time without issue.
272
+ ### Without Docker
251
273
 
252
- ## Get Help
274
+ #### External Requirements
275
+ * PostgreSQL with the uuid-ossp extension.
276
+ * Note: Enabling uuid-ossp requires database superuser privileges.
277
+ * From `psql`: `alter user [username] with superuser;`
253
278
 
254
- If you have any questions regarding Valkyrie you can send a message to [the
255
- Samvera community tech list](mailto:samvera-tech@googlegroups.com) or the `#valkyrie`
256
- channel in the [Samvera community Slack
257
- team](https://wiki.duraspace.org/pages/viewpage.action?pageId=87460391#Getintouch!-Slack).
279
+ #### To run the test suite
280
+ 1. Start Solr and Fedora servers for testing with `rake server:test`
281
+ 1. Run `rake db:create` (First time only)
282
+ 1. Run `rake db:migrate`
258
283
 
259
- ## License
284
+ ## Acknowledgments
260
285
 
261
- Valkyrie is available under [the Apache 2.0 license](../LICENSE).
286
+ This software has been developed by and is brought to you by the Samvera community. Learn more at the
287
+ [Samvera website](http://samvera.org/).
262
288
 
289
+ ![Samvera Logo](https://wiki.duraspace.org/download/thumbnails/87459292/samvera-fall-font2-200w.png?version=1&modificationDate=1498550535816&api=v2)
263
290
 
264
291
  ## Contributing
265
292
 
data/SUPPORT.md ADDED
@@ -0,0 +1,5 @@
1
+ If you would like to report an issue, first search [the list of issues](https://github.com/samvera-labs/valkyrie/issues/) to see if someone else has already reported it, and then feel free to [create a new issue](https://github.com/samvera-labs/valkyrie/issues/new).
2
+
3
+ If you have questions or need help, please email [the Samvera community tech list](https://groups.google.com/forum/#!forum/samvera-tech) or stop by the #dev channel in [the Samvera community Slack team](https://wiki.duraspace.org/pages/viewpage.action?pageId=87460391#Getintouch!-Slack).
4
+
5
+ You can learn more about the various Samvera communication channels on the [Get in touch!](https://wiki.duraspace.org/pages/viewpage.action?pageId=87460391) wiki page.
@@ -488,9 +488,10 @@ module Valkyrie::Persistence::Fedora
488
488
  # @return [Valkyrie::Persistence::Fedora::Persister::ModelConverter::Property]
489
489
  def result
490
490
  # cast it to datetime for storage, to preserve milliseconds and date
491
+ # @todo Remove strftime when https://github.com/ruby-rdf/rdf/issues/394 is closed.
491
492
  map_value(converted_value:
492
493
  RDF::Literal.new(
493
- value.value.to_datetime,
494
+ value.value.to_datetime.strftime("%Y-%m-%dT%H:%M:%S.%N%z"),
494
495
  datatype: PermissiveSchema.valkyrie_time
495
496
  ))
496
497
  end
@@ -17,7 +17,7 @@ module Valkyrie::Persistence::Fedora
17
17
  initialize_repository
18
18
  internal_resource = resource.dup
19
19
  internal_resource.created_at ||= Time.current
20
- internal_resource.updated_at ||= Time.current
20
+ internal_resource.updated_at = Time.current
21
21
  validate_lock_token(internal_resource)
22
22
  native_lock = native_lock_token(internal_resource)
23
23
  generate_lock_token(internal_resource)
@@ -111,8 +111,10 @@ module Valkyrie::Persistence::Fedora
111
111
  # Find all resources referencing a given resource (e. g. parents)
112
112
  # *This is done by iterating through the ID of each resource referencing the resource in the query, and requesting each resource over the HTTP*
113
113
  # *Also, an initial request is made to find the URIs of the resources referencing the resource in the query*
114
- def find_inverse_references_by(resource:, property:)
115
- ensure_persisted(resource)
114
+ def find_inverse_references_by(resource: nil, id: nil, property:)
115
+ raise ArgumentError, "Provide resource or id" unless resource || id
116
+ ensure_persisted(resource) if resource
117
+ resource ||= find_by(id: id)
116
118
  if ordered_property?(resource: resource, property: property)
117
119
  find_inverse_references_by_ordered(resource: resource, property: property)
118
120
  else
@@ -36,7 +36,10 @@ module Valkyrie::Persistence::Memory
36
36
  def find_by_alternate_identifier(alternate_identifier:)
37
37
  alternate_identifier = Valkyrie::ID.new(alternate_identifier.to_s) if alternate_identifier.is_a?(String)
38
38
  validate_id(alternate_identifier)
39
- cache.select { |_key, resource| resource[:alternate_ids].include?(alternate_identifier) }.values.first || raise(::Valkyrie::Persistence::ObjectNotFoundError)
39
+ cache.select do |_key, resource|
40
+ next unless resource[:alternate_ids]
41
+ resource[:alternate_ids].include?(alternate_identifier)
42
+ end.values.first || raise(::Valkyrie::Persistence::ObjectNotFoundError)
40
43
  end
41
44
 
42
45
  # Get a batch of resources by ID.
@@ -110,10 +113,12 @@ module Valkyrie::Persistence::Memory
110
113
  # @return [Array<Valkyrie::Resource>] All resources in the persistence backend
111
114
  # which have the ID of the given `resource` in their `property` property. Not
112
115
  # in order.
113
- def find_inverse_references_by(resource:, property:)
114
- ensure_persisted(resource)
116
+ def find_inverse_references_by(resource: nil, id: nil, property:)
117
+ raise ArgumentError, "Provide resource or id" unless resource || id
118
+ ensure_persisted(resource) if resource
119
+ id ||= resource.id
115
120
  find_all.select do |obj|
116
- Array.wrap(obj[property]).include?(resource.id)
121
+ Array.wrap(obj[property]).include?(id)
117
122
  end
118
123
  end
119
124
 
@@ -56,7 +56,7 @@ module Valkyrie::Persistence::Postgres
56
56
  # Retrieve the Class used to construct the Valkyrie Resource
57
57
  # @return [Class]
58
58
  def resource_klass
59
- internal_resource.constantize
59
+ Valkyrie.config.resource_class_resolver.call(internal_resource)
60
60
  end
61
61
 
62
62
  # Access the String for the Valkyrie Resource type within the attributes
@@ -19,7 +19,15 @@ module Valkyrie::Persistence::Postgres
19
19
  # was modified in the database between been read into memory and persisted
20
20
  def save(resource:)
21
21
  orm_object = resource_factory.from_resource(resource: resource)
22
- orm_object.save!
22
+ orm_object.transaction do
23
+ orm_object.save!
24
+ if resource.id && resource.id.to_s != orm_object.id
25
+ raise Valkyrie::Persistence::UnsupportedDatatype,
26
+ "Postgres' primary key column can not save with the given ID #{resource.id}. " \
27
+ "To avoid this error, set the ID to be nil via `resource.id = nil` before you save it. \n" \
28
+ "Called from #{Gem.location_of_caller.join(':')}"
29
+ end
30
+ end
23
31
  resource_factory.to_resource(object: orm_object)
24
32
  rescue ActiveRecord::StaleObjectError
25
33
  raise Valkyrie::Persistence::StaleObjectError, "The object #{resource.id} has been updated by another process."
@@ -112,9 +112,11 @@ module Valkyrie::Persistence::Postgres
112
112
  # @param [Valkyrie::Resource] resource
113
113
  # @param [String] property
114
114
  # @return [Array<Valkyrie::Resource>]
115
- def find_inverse_references_by(resource:, property:)
116
- ensure_persisted(resource)
117
- internal_array = "{\"#{property}\": [{\"id\": \"#{resource.id}\"}]}"
115
+ def find_inverse_references_by(resource: nil, id: nil, property:)
116
+ raise ArgumentError, "Provide resource or id" unless resource || id
117
+ ensure_persisted(resource) if resource
118
+ id ||= resource.id
119
+ internal_array = "{\"#{property}\": [{\"id\": \"#{id}\"}]}"
118
120
  run_query(find_inverse_references_query, internal_array)
119
121
  end
120
122
 
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
- #
2
+ begin
3
+ gem 'pg'
4
+ rescue Gem::LoadError => e
5
+ raise Gem::LoadError,
6
+ "You are using the Postgres adapter without installing the #{e.name} gem. "\
7
+ "Add `gem '#{e.name}'` to your Gemfile."
8
+ end
3
9
  module Valkyrie::Persistence
4
10
  # Implements the DataMapper Pattern to store metadata into Postgres
5
11
  module Postgres
@@ -41,16 +41,25 @@ module Valkyrie::Persistence::Solr
41
41
  if resource_attributes[:created_at]
42
42
  DateTime.parse(resource_attributes[:created_at].to_s).utc.iso8601
43
43
  else
44
- Time.current.utc.iso8601
44
+ Time.current.utc.iso8601(6)
45
45
  end
46
46
  end
47
47
 
48
+ # @return [String] ISO-8601 timestamp in UTC of the updated_at for solr
49
+ # @note Solr stores its own updated_at timestamp, but for performance
50
+ # reasons we're generating our own. Without doing so, every time we add a
51
+ # new document we'd have to do a GET to find out the timestamp.
52
+ def updated_at
53
+ Time.current.utc.iso8601(6)
54
+ end
55
+
48
56
  # @return [Hash] Solr document to index.
49
57
  def to_h
50
58
  {
51
59
  "id": id,
52
60
  "join_id_ssi": "id-#{id}",
53
- "created_at_dtsi": created_at
61
+ "created_at_dtsi": created_at,
62
+ "updated_at_dtsi": updated_at
54
63
  }.merge(add_single_values(attribute_hash)).merge(lock_hash)
55
64
  end
56
65
 
@@ -26,7 +26,7 @@ module Valkyrie::Persistence::Solr
26
26
  # Access the Class for the Valkyrie Resource
27
27
  # @return [Class]
28
28
  def resource_klass
29
- internal_resource.constantize
29
+ Valkyrie.config.resource_class_resolver.call(internal_resource)
30
30
  end
31
31
 
32
32
  # Access the String specifying the Valkyrie Resource type in the Solr Document
@@ -54,7 +54,7 @@ module Valkyrie::Persistence::Solr
54
54
  # Construct a Time object from the datestamp for the date of the last resource update indexed in Solr
55
55
  # @return [Time]
56
56
  def updated_at
57
- DateTime.parse(solr_document["timestamp"] || solr_document.fetch("created_at_dtsi").to_s).utc
57
+ DateTime.parse((solr_document["updated_at_dtsi"] || solr_document["timestamp"] || solr_document["created_at_dtsi"]).to_s).utc
58
58
  end
59
59
 
60
60
  # Construct the OptimisticLockToken object using the "_version_" field value in the Solr Document
@@ -3,14 +3,14 @@ module Valkyrie::Persistence::Solr::Queries
3
3
  # Responsible for efficiently returning all {Valkyrie::Resource}s which
4
4
  # reference a {Valkyrie::Resource} in a given property.
5
5
  class FindInverseReferencesQuery
6
- attr_reader :resource, :property, :connection, :resource_factory
6
+ attr_reader :id, :property, :connection, :resource_factory
7
7
 
8
8
  # @param [Valkyrie::Resource] resource
9
9
  # @param [String] property
10
10
  # @param [RSolr::Client] connection
11
11
  # @param [ResourceFactory] resource_factory
12
- def initialize(resource:, property:, connection:, resource_factory:)
13
- @resource = resource
12
+ def initialize(resource: nil, id: nil, property:, connection:, resource_factory:)
13
+ @id = id ? id : resource.id
14
14
  @property = property
15
15
  @connection = connection
16
16
  @resource_factory = resource_factory
@@ -39,7 +39,7 @@ module Valkyrie::Persistence::Solr::Queries
39
39
  # @note the field used here is a _ssim dynamic field and the value is prefixed by "id-"
40
40
  # @return [Hash]
41
41
  def query
42
- "#{property}_ssim:id-#{resource.id}"
42
+ "#{property}_ssim:id-#{id}"
43
43
  end
44
44
  end
45
45
  end
@@ -91,9 +91,11 @@ module Valkyrie::Persistence::Solr
91
91
  # @param [Valkyrie::Resource] referenced resource
92
92
  # @param [Symbol, String] property
93
93
  # @return [Array<Valkyrie::Resource>] related resources
94
- def find_inverse_references_by(resource:, property:)
95
- ensure_persisted(resource)
96
- Valkyrie::Persistence::Solr::Queries::FindInverseReferencesQuery.new(resource: resource, property: property, connection: connection, resource_factory: resource_factory).run
94
+ def find_inverse_references_by(resource: nil, id: nil, property:)
95
+ raise ArgumentError, "Provide resource or id" unless resource || id
96
+ ensure_persisted(resource) if resource
97
+ id ||= resource.id
98
+ Valkyrie::Persistence::Solr::Queries::FindInverseReferencesQuery.new(id: id, property: property, connection: connection, resource_factory: resource_factory).run
97
99
  end
98
100
 
99
101
  # Construct the Valkyrie::Persistence::CustomQueryContainer object using this query service
@@ -2,6 +2,7 @@
2
2
  RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
3
3
  before do
4
4
  raise 'persister must be set with `let(:persister)`' unless defined? persister
5
+ raise 'query_service must be set with `let(:query_service)`' unless defined? query_service
5
6
  class CustomResource < Valkyrie::Resource
6
7
  include Valkyrie::Resource::AccessControls
7
8
  attribute :title
@@ -92,6 +93,7 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
92
93
  expect(book.updated_at).not_to be_blank
93
94
  expect(book.created_at).not_to be_kind_of Array
94
95
  expect(book.updated_at).not_to be_kind_of Array
96
+ expect(book.updated_at > book.created_at).to eq true
95
97
  end
96
98
 
97
99
  it "can handle Boolean RDF properties" do
@@ -235,7 +237,7 @@ RSpec.shared_examples 'a Valkyrie::Persister' do |*flags|
235
237
  end
236
238
 
237
239
  it "can store Valkyrie::IDs" do
238
- shared_title = persister.save(resource: resource_class.new(id: "test"))
240
+ shared_title = persister.save(resource: resource_class.new)
239
241
  book = persister.save(resource: resource_class.new(title: [shared_title.id, Valkyrie::ID.new("adapter://1"), "test"]))
240
242
  reloaded = query_service.find_by(id: book.id)
241
243
  expect(reloaded.title).to contain_exactly(shared_title.id, Valkyrie::ID.new("adapter://1"), "test")
@@ -4,7 +4,7 @@ RSpec.shared_examples 'a Valkyrie query provider' do
4
4
  raise 'adapter must be set with `let(:adapter)`' unless
5
5
  defined? adapter
6
6
  class CustomResource < Valkyrie::Resource
7
- attribute :alternate_ids, Valkyrie::Types::Array
7
+ attribute :alternate_ids, Valkyrie::Types::Set.of(Valkyrie::Types::ID)
8
8
  attribute :title
9
9
  attribute :member_ids, Valkyrie::Types::Array
10
10
  attribute :a_member_of, Valkyrie::Types::Array
@@ -30,6 +30,7 @@ RSpec.shared_examples 'a Valkyrie query provider' do
30
30
  it { is_expected.to respond_to(:find_members).with_keywords(:resource, :model) }
31
31
  it { is_expected.to respond_to(:find_references_by).with_keywords(:resource, :property) }
32
32
  it { is_expected.to respond_to(:find_inverse_references_by).with_keywords(:resource, :property) }
33
+ it { is_expected.to respond_to(:find_inverse_references_by).with_keywords(:id, :property) }
33
34
  it { is_expected.to respond_to(:find_parents).with_keywords(:resource) }
34
35
 
35
36
  describe ".find_all" do
@@ -90,7 +91,12 @@ RSpec.shared_examples 'a Valkyrie query provider' do
90
91
  expect(found).to be_persisted
91
92
  end
92
93
 
93
- it "returns a Valkyrie::Persistence::ObjectNotFoundError for a non-found alternate identifier" do
94
+ it 'raises a Valkyrie::Persistence::ObjectNotFoundError when persisted objects do not have alternate_ids' do
95
+ persister.save(resource: SecondResource.new)
96
+ expect { query_service.find_by_alternate_identifier(alternate_identifier: Valkyrie::ID.new("123123123")) }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
97
+ end
98
+
99
+ it "raises a Valkyrie::Persistence::ObjectNotFoundError for a non-found alternate identifier" do
94
100
  expect { query_service.find_by_alternate_identifier(alternate_identifier: Valkyrie::ID.new("123123123")) }.to raise_error ::Valkyrie::Persistence::ObjectNotFoundError
95
101
  end
96
102
 
@@ -302,6 +308,26 @@ RSpec.shared_examples 'a Valkyrie query provider' do
302
308
  end
303
309
  end
304
310
  end
311
+
312
+ context "when id is passed instead of resource" do
313
+ it "returns everything which references the given resource by the given property" do
314
+ parent = persister.save(resource: resource_class.new)
315
+ parent2 = persister.save(resource: resource_class.new)
316
+ child = persister.save(resource: resource_class.new(a_member_of: [parent.id]))
317
+ child2 = persister.save(resource: resource_class.new(a_member_of: [parent.id, parent2.id, parent.id]))
318
+ persister.save(resource: resource_class.new)
319
+ persister.save(resource: SecondResource.new)
320
+
321
+ expect(query_service.find_inverse_references_by(id: parent.id, property: :a_member_of).map(&:id).to_a).to contain_exactly child.id, child2.id
322
+ end
323
+ end
324
+
325
+ context "when neither id nor resource is passed" do
326
+ it "raises an error" do
327
+ expect { query_service.find_inverse_references_by(property: :a_member_of) }.to raise_error ArgumentError
328
+ end
329
+ end
330
+
305
331
  context "when the resource is not saved" do
306
332
  it "raises an error" do
307
333
  parent = resource_class.new
@@ -70,7 +70,7 @@ RSpec.shared_examples 'a Valkyrie::Resource' do
70
70
 
71
71
  describe "#[]" do
72
72
  it "allows access to properties which are set" do
73
- resource_klass.attribute :my_property
73
+ resource_klass.attribute :my_property unless resource_klass.schema.key?(:my_property)
74
74
  resource = resource_klass.new
75
75
 
76
76
  resource.my_property = "test"
@@ -84,7 +84,7 @@ RSpec.shared_examples 'a Valkyrie::Resource' do
84
84
  expect(resource[:bad_property]).to eq nil
85
85
  end
86
86
  it "can be accessed via a string" do
87
- resource_klass.attribute :other_property
87
+ resource_klass.attribute :other_property unless resource_klass.schema.key?(:other_property)
88
88
  resource = resource_klass.new
89
89
 
90
90
  resource.other_property = "test"
@@ -96,7 +96,7 @@ RSpec.shared_examples 'a Valkyrie::Resource' do
96
96
 
97
97
  describe "#set_value" do
98
98
  it "can set a value" do
99
- resource_klass.attribute :set_value_property
99
+ resource_klass.attribute :set_value_property unless resource_klass.schema.key?(:set_value_property)
100
100
  resource = resource_klass.new
101
101
 
102
102
  resource.set_value(:set_value_property, "test")
@@ -110,7 +110,7 @@ RSpec.shared_examples 'a Valkyrie::Resource' do
110
110
 
111
111
  describe ".new" do
112
112
  it "can set values with symbols" do
113
- resource_klass.attribute :symbol_property
113
+ resource_klass.attribute :symbol_property unless resource_klass.schema.key?(:symbol_property)
114
114
 
115
115
  resource = resource_klass.new(symbol_property: "bla")
116
116
 
@@ -118,16 +118,17 @@ RSpec.shared_examples 'a Valkyrie::Resource' do
118
118
  resource_klass.schema.delete(:symbol_property)
119
119
  end
120
120
  it "can not set values with string properties" do
121
- resource_klass.attribute :string_property
121
+ resource_klass.attribute :string_property unless resource_klass.schema.key?(:string_property)
122
122
 
123
123
  resource = nil
124
124
  expect(resource).not_to respond_to :string_property
125
+ resource_klass.schema.delete(:string_property)
125
126
  end
126
127
  end
127
128
 
128
129
  describe "#attributes" do
129
130
  it "returns all defined attributs, including nil keys" do
130
- resource_klass.attribute :bla
131
+ resource_klass.attribute :bla unless resource_klass.schema.key?(:bla)
131
132
 
132
133
  resource = resource_klass.new
133
134
 
@@ -61,7 +61,8 @@ module Valkyrie
61
61
  # Used for casting {Valkyrie::Resources} if possible.
62
62
  Anything = Valkyrie::Types::Any.constructor do |value|
63
63
  if value.respond_to?(:fetch) && value.fetch(:internal_resource, nil)
64
- value.fetch(:internal_resource).constantize.new(value)
64
+ resource_klass = Valkyrie.config.resource_class_resolver.call(value.fetch(:internal_resource))
65
+ resource_klass.new(value)
65
66
  else
66
67
  value
67
68
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Valkyrie
3
- VERSION = "2.0.0.RC1"
3
+ VERSION = "2.0.0.RC3"
4
4
  end
data/lib/valkyrie.rb CHANGED
@@ -81,12 +81,38 @@ module Valkyrie
81
81
  Valkyrie::StorageAdapter.find(super.to_sym)
82
82
  end
83
83
 
84
+ # @api public
85
+ #
86
+ # The returned anonymous method (e.g. responds to #call) has a signature of
87
+ # an unamed parameter that is a string. Calling the anonymous method should
88
+ # return a Valkyrie::Resource from which Valkyrie will map the persisted
89
+ # data into.
90
+ #
91
+ # @return [#call] with method signature of 1
92
+ #
93
+ # @see #default_resource_class_resolver for full interface
94
+ def resource_class_resolver
95
+ super
96
+ end
97
+
98
+ # @!attribute [w] resource_class_resolver=
99
+ # The setter for #resource_class_resolver; see it's implementation
100
+
84
101
  private
85
102
 
86
103
  def defaults
87
104
  {
105
+ resource_class_resolver: method(:default_resource_class_resolver)
88
106
  }
89
107
  end
108
+
109
+ # String constantize is a "by convention" factory. This works, but assumes
110
+ # the ruby class once used to persist is the model used to now reify.
111
+ #
112
+ # @param [String] class_name
113
+ def default_resource_class_resolver(class_name)
114
+ class_name.constantize
115
+ end
90
116
  end
91
117
 
92
118
  module_function :config, :logger, :logger=, :config_root_path, :environment, :config_file, :config_hash
data/valkyrie.gemspec CHANGED
@@ -29,14 +29,13 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency 'railties' # To use generators and engines
30
30
  spec.add_dependency 'reform'
31
31
  spec.add_dependency 'reform-rails'
32
- spec.add_dependency 'pg'
33
32
  spec.add_dependency 'json-ld'
34
33
  spec.add_dependency 'json'
35
34
  spec.add_dependency 'active-triples'
36
35
  spec.add_dependency 'ldp'
37
36
  spec.add_dependency 'rsolr'
38
37
 
39
- spec.add_development_dependency "bundler", "~> 1.13"
38
+ spec.add_development_dependency "bundler", "~> 1.16"
40
39
  spec.add_development_dependency "rake", "~> 10.0"
41
40
  spec.add_development_dependency "rspec", "~> 3.0"
42
41
  spec.add_development_dependency "pry"
@@ -51,4 +50,5 @@ Gem::Specification.new do |spec|
51
50
  spec.add_development_dependency 'fcrepo_wrapper'
52
51
  spec.add_development_dependency 'docker-stack', '~> 0.2.6'
53
52
  spec.add_development_dependency 'activerecord', '~> 5.1.0'
53
+ spec.add_development_dependency 'timecop'
54
54
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valkyrie
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.RC1
4
+ version: 2.0.0.RC3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Trey Pendragon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-29 00:00:00.000000000 Z
11
+ date: 2019-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-struct
@@ -150,20 +150,6 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: pg
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :runtime
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
153
  - !ruby/object:Gem::Dependency
168
154
  name: json-ld
169
155
  requirement: !ruby/object:Gem::Requirement
@@ -240,14 +226,14 @@ dependencies:
240
226
  requirements:
241
227
  - - "~>"
242
228
  - !ruby/object:Gem::Version
243
- version: '1.13'
229
+ version: '1.16'
244
230
  type: :development
245
231
  prerelease: false
246
232
  version_requirements: !ruby/object:Gem::Requirement
247
233
  requirements:
248
234
  - - "~>"
249
235
  - !ruby/object:Gem::Version
250
- version: '1.13'
236
+ version: '1.16'
251
237
  - !ruby/object:Gem::Dependency
252
238
  name: rake
253
239
  requirement: !ruby/object:Gem::Requirement
@@ -444,6 +430,20 @@ dependencies:
444
430
  - - "~>"
445
431
  - !ruby/object:Gem::Version
446
432
  version: 5.1.0
433
+ - !ruby/object:Gem::Dependency
434
+ name: timecop
435
+ requirement: !ruby/object:Gem::Requirement
436
+ requirements:
437
+ - - ">="
438
+ - !ruby/object:Gem::Version
439
+ version: '0'
440
+ type: :development
441
+ prerelease: false
442
+ version_requirements: !ruby/object:Gem::Requirement
443
+ requirements:
444
+ - - ">="
445
+ - !ruby/object:Gem::Version
446
+ version: '0'
447
447
  description:
448
448
  email:
449
449
  - tpendragon@princeton.edu
@@ -460,10 +460,13 @@ files:
460
460
  - ".rubocop.yml"
461
461
  - ".rubocop_todo.yml"
462
462
  - CHANGELOG.md
463
+ - CODE_OF_CONDUCT.md
464
+ - CONTRIBUTING.md
463
465
  - Gemfile
464
466
  - LICENSE
465
467
  - README.md
466
468
  - Rakefile
469
+ - SUPPORT.md
467
470
  - bin/console
468
471
  - bin/jetty_wait
469
472
  - bin/rspec
@@ -604,7 +607,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
604
607
  version: 1.3.1
605
608
  requirements: []
606
609
  rubyforge_project:
607
- rubygems_version: 2.7.6
610
+ rubygems_version: 2.7.7
608
611
  signing_key:
609
612
  specification_version: 4
610
613
  summary: An ORM using the Data Mapper pattern, specifically built to solve Digital