{"id":13879612,"url":"https://github.com/samvera/valkyrie","last_synced_at":"2025-04-04T07:03:53.007Z","repository":{"id":34724632,"uuid":"66685502","full_name":"samvera/valkyrie","owner":"samvera","description":"A Data Mapper library to enable multiple backends for storage of files and metadata in Samvera","archived":false,"fork":false,"pushed_at":"2025-03-03T18:57:49.000Z","size":2188,"stargazers_count":34,"open_issues_count":72,"forks_count":21,"subscribers_count":73,"default_branch":"main","last_synced_at":"2025-03-28T06:08:51.016Z","etag":null,"topics":["core-components","samvera-community"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/samvera.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-26T23:37:15.000Z","updated_at":"2025-03-03T18:57:53.000Z","dependencies_parsed_at":"2023-02-15T11:31:13.265Z","dependency_job_id":"db643820-6e95-49d8-93af-16ec3eb3c8a2","html_url":"https://github.com/samvera/valkyrie","commit_stats":{"total_commits":834,"total_committers":51,"mean_commits":"16.352941176470587","dds":"0.48081534772182255","last_synced_commit":"4aeffacb4bf3422652b99301ed3820f3dab3b52d"},"previous_names":[],"tags_count":58,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samvera%2Fvalkyrie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samvera%2Fvalkyrie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samvera%2Fvalkyrie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/samvera%2Fvalkyrie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/samvera","download_url":"https://codeload.github.com/samvera/valkyrie/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247135138,"owners_count":20889420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["core-components","samvera-community"],"created_at":"2024-08-06T08:02:26.782Z","updated_at":"2025-04-04T07:03:52.989Z","avatar_url":"https://github.com/samvera.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Valkyrie\n\nValkyrie is a gem for enabling multiple backends for storage of files and metadata in Samvera.\n\n![Valkyrie Logo](valkyrie_logo.png)\n\nCode: [![Gem Version](https://badge.fury.io/rb/valkyrie.svg)](https://badge.fury.io/rb/valkyrie)\n[![Build Status](https://circleci.com/gh/samvera/valkyrie.svg?style=svg)](https://circleci.com/gh/samvera/valkyrie)\n![Coverage Status](https://img.shields.io/badge/Coverage-100-brightgreen.svg)\n\nDocs: [![Contribution Guidelines](http://img.shields.io/badge/CONTRIBUTING-Guidelines-blue.svg)](./CONTRIBUTING.md)\n[![Apache 2.0 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)\n[![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://rubydoc.info/gems/valkyrie)\n\nJump in: [![Slack Status](http://slack.samvera.org/badge.svg)](http://slack.samvera.org/)\n\n## Primary Contacts\n\n### Product Owner\n[Alexandra Dunn](https://github.com/dunn)\n\n### Technical Lead\n[Trey Pendragon](https://github.com/tpendragon)\n\n## Help\n\nThe Samvera community is here to help. Please see our [support guide](./SUPPORT.md).\n\n## Getting Started\n\nAdd this line to your application's Gemfile:\n\n```\ngem 'valkyrie'\n```\n\nAnd then execute:\n\n    $ bundle\n\n## Configuration\n\nValkyrie is configured in two places: an initializer that registers the persistence options and a YAML\nconfiguration file that sets which options are used by default in which environments.\n\n### Sample initializer: `config/initializers/valkyrie.rb`:\nHere is a sample initializer that registers a couple adapters and storage adapters, in each case linking an\ninstance with a short name that can be used to refer to it in your application:\n\n\n```\n# frozen_string_literal: true\nrequire 'valkyrie'\n\n\nRails.application.config.to_prepare do\n\n  # To use the postgres adapter you must add `gem 'pg'` to your Gemfile\n  Valkyrie::MetadataAdapter.register(\n    Valkyrie::Persistence::Postgres::MetadataAdapter.new,\n    :postgres\n  )\n\n  # To use the solr adapter you must add gem 'rsolr' to your Gemfile\n  Valkyrie::MetadataAdapter.register(\n    Valkyrie::Persistence::Solr::MetadataAdapter.new(\n      connection: Blacklight.default_index.connection\n    ),\n    :solr\n  )\n\n  # To use the fedora adapter you must add `gem 'ldp'` to your Gemfile\n  Valkyrie::MetadataAdapter.register(\n    Valkyrie::Persistence::Fedora::MetadataAdapter.new(\n      connection: ::Ldp::Client.new(\"http://localhost:8988/rest\"),\n      base_path: \"test_fed\",\n      schema: Valkyrie::Persistence::Fedora::PermissiveSchema.new(title: RDF::URI(\"http://bad.com/title\"))\n    ),\n    :fedora\n  )\n\n  Valkyrie::MetadataAdapter.register(\n    Valkyrie::Persistence::Memory::MetadataAdapter.new,\n    :memory\n  )\n\n  Valkyrie::StorageAdapter.register(\n    Valkyrie::Storage::Disk.new(base_path: Rails.root.join(\"tmp\", \"files\")),\n    :disk\n  )\n\n  Valkyrie::StorageAdapter.register(\n    Valkyrie::Storage::Fedora.new(connection: Ldp::Client.new(\"http://localhost:8988/rest\")),\n    :fedora\n  )\n\n\n  Valkyrie::StorageAdapter.register(\n    Valkyrie::Storage::Memory.new,\n    :memory\n  )\nend\n```\n\nThe initializer registers four `Valkyrie::MetadataAdapter` instances for storing metadata:\n* `:fedora` which stores metadata in a Fedora server.\n* `:memory` which stores metadata in an in-memory cache (this cache is not persistent, so it is only\n  appropriate for testing).\n* `:postgres` which stores metadata in a PostgreSQL database.\n* `:solr` which stores metadata in a Solr Index (Solr Persister issues a warning if it has to generate an ID for a new resource because it is intended to be used as a secondary persister).\n\nOther adapter options include `Valkyrie::Persistence::BufferedPersister` for buffering in memory before bulk\nupdating another persister, `Valkyrie::Persistence::CompositePersister` for storing in more than one adapter\nat once, `Valkyrie::Persistence::Solr` for storing in Solr, and `Valkyrie::Persistence::Fedora` for storing\nin Fedora.\n\nThe initializer also registers three `Valkyrie::StorageAdapter` instances for storing files:\n* `:disk` which stores files on disk\n* `:fedora` which stores files in Fedora\n* `:memory` which stores files in an in-memory cache (again, not persistent, so this is only appropriate for\n  testing)\n\n### Sample configuration with custom `Valkyrie.config.resource_class_resolver`:\n```\nrequire 'valkyrie'\nRails.application.config.to_prepare do\n  Valkyrie.config.resource_class_resolver = lambda do |resource_klass_name|\n    # Do complicated lookup based on the string\n  end\nend\n```\n\n### Sample configuration: `config/valkyrie.yml`:\nA sample configuration file that configures your application to use different adapters:\n\n```\ndevelopment:\n  metadata_adapter: postgres\n  storage_adapter: disk\n\ntest:\n  metadata_adapter: memory\n  storage_adapter: memory\n\nproduction:\n  metadata_adapter: postgres\n  storage_adapter: fedora\n```\n\nFor each environment, you must set two values:\n* `metadata_adapter` is the store where Valkyrie will put the metadata\n* `storage_adapter` is the store where Valkyrie will put the files\n\nThe values are the short names used in your initializer.\n\nFurther details can be found on the [Persistence Wiki\npage](https://github.com/samvera/valkyrie/wiki/Persistence).\n\n## Usage\n\n### Define a Custom Work\nDefine a custom work class:\n\n```\n# frozen_string_literal: true\nclass MyModel \u003c Valkyrie::Resource\n  include Valkyrie::Resource::AccessControls\n  attribute :title, Valkyrie::Types::Set    # Sets deduplicate values\n  attribute :date, Valkyrie::Types::Array   # Arrays can contain duplicate values\nend\n```\n\nAttributes are unordered by default.  Adding `ordered: true` to an attribute definition will preserve the\norder of multiple values.\n\n```\nattribute :authors, Valkyrie::Types::Array.meta(ordered: true)\n```\n\nDefining resource attributes is explained in greater detail on the [Using Types Wiki\npage](https://github.com/samvera/valkyrie/wiki/Using-Types).\n\n### Read and Write Data\n```\n# initialize a metadata adapter\nadapter = Valkyrie::MetadataAdapter.find(:postgres)\n\n# create an object\nobject1 = MyModel.new title: 'My Cool Object', authors: ['Jones, Alice', 'Smith, Bob']\nobject1 = adapter.persister.save(resource: object1)\n\n# load an object from the database\nobject2 = adapter.query_service.find_by(id: object1.id)\n\n# load all objects\nobjects = adapter.query_service.find_all\n\n# load all MyModel objects\nValkyrie.config.metadata_adapter.query_service.find_all_of_model(model: MyModel)\n```\n\nThe Wiki documents the usage of [Queries](https://github.com/samvera/valkyrie/wiki/Queries),\n[Persistence](https://github.com/samvera/valkyrie/wiki/Persistence), and\n[ChangeSets and Dirty Tracking](https://github.com/samvera/valkyrie/wiki/ChangeSets-and-Dirty-Tracking).\n\n### Concurrency Support\nA Valkyrie repository may have concurrent updates, for example, from a load-balanced Rails application, or\nfrom multiple [Sidekiq](https://github.com/mperham/sidekiq) background workers).  In order to prevent multiple\nsimultaneous updates applied to the same resource from losing or corrupting data, Valkyrie supports optimistic\nlocking.  How to use optimistic locking with Valkyrie is documented on the [Optimistic Locking Wiki\npage](https://github.com/samvera/valkyrie/wiki/Optimistic-Locking).\n\n### The Public API\nValkyrie's public API is defined by the shared specs that are used to test each of its core classes.\nThis include change sets, resources, persisters, adapters, and queries. When creating your own kinds of\nthese kinds of classes, you should use these shared specs to test your classes for conformance to\nValkyrie's API.\n\nWhen breaking changes are introduced, necessitating a major version change, the shared specs will reflect\nthis. When new features are added and a minor version is released there will be no change to the existing\nshared specs, but there may be new ones. These new shared specs will fail in your application if you have\ncustom adapters, but your application will still work.\n\nUsing the shared specs in your own models is described in more detail on the [Shared Specs Wiki\npage](https://github.com/samvera/valkyrie/wiki/Shared-Specs).\n\n### Fedora 5/6 Compatibility\nWhen configuring your adapter, include the `fedora_version` parameter in your metadata or storage adapter\nconfig.  If Fedora requires auth, you can also include that in the URL, e.g.:\n\n   ```\n   Valkyrie::Storage::Fedora.new(\n     connection: Ldp::Client.new(\"http://fedoraAdmin:fedoraAdmin@localhost:8988/rest\"),\n     fedora_version: 5\n   )\n   ```\n#### Pairtree paths in Fedora 4/6\nFedora 4 and 6.5+ support automatic creation of \"pairtree\" paths, which means that identifiers are stored in\na hashed directory structure to avoid excessive child nodes directly in the root node.\n\nUnlike Fedora 4 where this is the default behavior, it has to be enabled via options in Fedora 6.5. This is \ndone by configuring both the count and length of the pairtree algorithm, so it needs to be configured\nin the Fedora adapters so that both sides match.\n\nIn the following example, Fedora 6.5 is being started with options to create pairtree paths consisting of \n4 segments, 2 characters in length:  \n\n```angular2html\nCATALINA_OPTS=-Dfcrepo.home=/fcrepo-home ...\n...\n-Dfcrepo.pid.minter.length=2 -Dfcrepo.pid.minter.count=4\n```\nFor the Fedora metadata/storage adapters to correctly translate identifiers into URI's, they should be initialized\nlike:\n\n```angular2html\nValkyrie::Persistence::Fedora::MetadataAdapter.new(\n    connection: ::Ldp::Client.new(\"http://localhost:8080/fcrepo/rest\"),\n    fedora_version: 6.5,\n    fedora_pairtree_count: 4,\n    fedora_pairtree_length: 2\n  )\n```\n\nIn the configuration above, an ID of `AaBbCcDd` will be created in Fedora under the root node as `/Aa/Bb/Cc/Dd/AaBbCcDd`. \nIf count and length correctly match in the Fedora adapters, that same path will be calculated and returned.\n\nNote that the configuration above is not required for pairtree paths to work correctly in Fedora 4, and automatic\npairtree creation is not supported under Fedora 5 or Fedora 6 \u003c 6.5. \n\n## Installing a Development environment\n\nFor ease of development we use Lando to abstract away some complications of\nusing Docker containers for development.\n\n### Running Tests\n\n1. Install the latest released \u003e 3.0 version of Lando from [here](https://github.com/lando/lando/releases).\n2. `bundle install`(Ruby 2.6+ required)\n3. `bundle exec rake server:start`\n4. `bundle exec rspec spec`\n\n### Cleaning Data\n\n1. `bundle exec rake server:clean`\n\n### Stopping Servers\n\n1. `bundle exec rake server:stop`\n\nYou can also run `lando poweroff` from anywhere.\n\n## Acknowledgments\n\nThis software has been developed by and is brought to you by the Samvera community.  Learn more at the\n[Samvera website](http://samvera.org/).\n\n![Samvera Logo](https://wiki.duraspace.org/download/thumbnails/87459292/samvera-fall-font2-200w.png?version=1\u0026modificationDate=1498550535816\u0026api=v2)\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/samvera/valkyrie/.\n\nIf you're working on PR for this project, create a feature branch off of `main`.\n\nIf you’re developing an application that uses Valkyrie, consider adding it to\nthe [list of Valkyrie apps](https://github.com/samvera/valkyrie/wiki/Valkyrie-Apps)!\n\nThis repository follows the [Samvera Community Code of Conduct](https://samvera.atlassian.net/wiki/spaces/samvera/pages/405212316/Code+of+Conduct) and [language recommendations](https://github.com/samvera/maintenance/blob/master/templates/CONTRIBUTING.md#language).  Please ***do not*** create a branch called `master` for this repository or as part of your pull request; the branch will either need to be removed or renamed before it can be considered for inclusion in the code base and history of this repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamvera%2Fvalkyrie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamvera%2Fvalkyrie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamvera%2Fvalkyrie/lists"}