simplified

package module
v0.0.23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 1, 2024 License: BSD-3-Clause Imports: 5 Imported by: 5

README

simplified

simplified is a Go package for bibliographic, software and data metadata. It is used internally by Caltech Library as suitable for mapping one specific metadata form (e.g. EPrints 3.3 EPrint XML) to another (e.g. Invenio-RDM 11 records). It is also used in our feeds system which provides an aggregated view our institutional author, thesis and data repositories. The simple record structure is inspired in part by the DataCite and Invenio RDM metadata models.

Two utilities demonstrate how you might use the simplified package in a Go program.

  • simpleutil will pretty print a JSON record or let you take a diff of two JSON file
  • simple2markdown is a proof of concept of rendering Markdown documents from a simple record (e.g. for a landing pages describing a metadata record).

References

Documentation

Overview

Package simplified is a package targetting intermediate bibliographic, software and data metadata representation at Caltech Library

@author R. S. Doiel, <[email protected]>

Copyright (c) 2023, Caltech All rights not granted herein are expressly reserved by Caltech.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Index

Constants

View Source
const (
	// Version number of release
	Version = "0.0.22"

	// ReleaseDate, the date version.go was generated
	ReleaseDate = "2024-02-26"

	// ReleaseHash, the Git hash when version.go was generated
	ReleaseHash = "718cd0a"

	LicenseText = `` /* 1524-byte string literal not displayed */

)

Variables

This section is empty.

Functions

func FmtHelp added in v0.0.13

func FmtHelp(src string, appName string, version string, releaseDate string, releaseHash string) string

FmtHelp lets you process a text block with simple curly brace markup.

Types

type Access

type Access struct {
	OwnedBy []*User `json:"owned_by,omitempty"`
}

Access is a third level element used by PersistentIdenitifier to describe access ownership of the record.

type Affiliation

type Affiliation struct {
	ID   string `json:"id,omitempty" yaml:"id,omitempty"`     // The organizational or institutional id from the controlled vocabularly
	Name string `json:"name,omitempty" yaml:"name,omitempty"` // The name of the organization or institution
	ROR  string `json:"ror,omitempty" yaml:"ror,omitempty"`
}

Affiliation describes how a person or organization is affialated for the purpose of the record.

type AwardIdentifier added in v0.0.8

type AwardIdentifier struct {
	Scheme       string       `json:"scheme,omitempty"`
	Name         string       `json:"name,omitempty"`
	Title        *TitleDetail `json:"title,omitempty"`
	Number       string       `json:"number,omitempty"`
	Identifier   string       `json:"identifier,omitempty"`
	RelationType *TypeDetail  `json:"relation_type,omitempty"`
	ResourceType *TypeDetail  `json:"resource_type,omitempty"`
}

type Community added in v0.0.22

type Community struct {
	IDs     []string `json:"ids,omitempty"`
	Default string   `json:"default,omitempty"`
}

type Creator

type Creator struct {
	// The person or organization.
	PersonOrOrg *PersonOrOrg `json:"person_or_org,omitempty"`
	// The role of the person or organization selected from a customizable controlled vocabular.
	Role *Role `json:"role,omitempty"`
	// Affiliations if `PersonOrOrg.Type` is personal.
	// NOTE: this is at same level as PersonOrOrg, Role per irdmtools issue #27
	Affiliations []*Affiliation `json:"affiliations,omitempty"`
}

Creator of a record's object

func (*Creator) HasAffiliation added in v0.0.16

func (creator *Creator) HasAffiliation(target *Affiliation) bool

HasAffiliation checks a PersonOrOrg record for a specific affiliation

type DateType

type DateType struct {
	Date        string `json:"date,omitempty"`
	Type        *Type  `json:"type,omitempty"`
	Description string `json:"description,omitempty"`
}

DateType holds Invenio dates used in Metadata element.

type Description

type Description struct {
	Description string `json:"description,omitempty"`
	Type        *Type  `json:"type,omitempty"`
	Lang        *Type  `json:"lang,omitempty"`
}

Description holds additional descriptions in Metadata element. e.g. language versions of Abstract, etc.

type Embargo

type Embargo struct {
	Active bool   `json:"active,omitempty"` // boolean, is the record under an embargo or not.
	Until  string `json:"until,omitempty"`  // Required if active true. ISO date string. When to lift the embargo. e.g. "2100-10-01"
	Reason string `json:"reason,omitempty"` // Explanation for the embargo
}

Embargo is a third level element used by RecordAccess to describe the embargo status of a record.

type Entry

type Entry struct {
	BucketID     string                 `json:"bucket_id,omitempty"`
	VersionID    string                 `json:"version_id,omitempty"`
	FileID       string                 `json:"file_id,omitempty"`
	Backend      string                 `json:"backend,omitempty"`
	StorageClass string                 `json:"storage_class,omitempty"`
	Key          string                 `json:"key,omitempty"`
	MimeType     string                 `json:"mimetype,omitempty"`
	Size         int                    `json:"size,omitempty"`
	CheckSum     string                 `json:"checksum,omitempty"`
	Created      string                 `json:"created,omitempty"`
	Updated      string                 `json:"updated,omitempty"`
	Status       string                 `json:"status,omitempty"`
	Metadata     map[string]interface{} `json:"metadata,omitempty"`
	Links        map[string]interface{} `json:"links,omitempty"`
}

type Feature

type Feature struct {
	Geometry    *Geometry     `json:"geometry,omitempty"`
	Identifiers []*Identifier `json:"identifiers,omitempty"`
	Place       string        `json:"place,omitempty"`
	Description string        `json:"description,omitempty"`
}

type FileListing added in v0.0.19

type FileListing struct {
	Enabled    bool                   `json:"enabled,omitempty"`
	Links      map[string]interface{} `json:"links,omitempty"`
	Entries    []*Entry               `json:"entries,omitempty"`
	TotalBytes int                    `json:"total_bytes,omitempty"`
	Count      int                    `json:"count,omitempty"`
	// FIXME: This fields may not make sense in RDM 11
	Formats        []string  `json:"formats,omitempty"`
	Order          []string  `json:"order,omitempty"`
	Locations      *Location `json:"locations,omitempty"`
	DefaultPreview string    `json:"default_preview,omitempty"`
	Sizes          []string  `json:"sizes,omitempty"`
}

FileListing, used in RDM for the /api/records/{record_id}/files result.

type Files

type Files struct {
	Enabled    bool              `json:"enabled,omitempty"`
	Entries    map[string]*Entry `json:"entries,omitempty"`
	TotalBytes int               `json:"total_bytes,omitempty"`
	Count      int               `json:"count,omitempty"`
	// FIXME: This fields may not make sense in RDM 11
	Formats        []string  `json:"formats,omitempty"`
	Order          []string  `json:"order,omitempty"`
	Locations      *Location `json:"locations,omitempty"`
	DefaultPreview string    `json:"default_preview,omitempty"`
	Sizes          []string  `json:"sizes,omitempty"`
}

Files, used in RDM for posting full record info.

type Funder

type Funder struct {
	Funder    *FunderIdentifier `json:"funder,omitempty"`
	Award     *AwardIdentifier  `json:"award,omitempty"`
	Reference []*Identifier     `json:"references,omitempty"`
}

Funder holds funding information for funding organizations in Metadata

type FunderIdentifier added in v0.0.21

type FunderIdentifier struct {
	Scheme string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
	Name   string `json:"name,omitempty" yaml:"name,omitempty"`
	Title  string `json:"title,omitempty" yaml:"title,omitempty"`
	Number string `json:"number,omitempty" yaml:"number,omitempty"`
	// Identifier, i.e. ROR. NOTE: It's a shame it the JSON doesn't line up with Identifier, it need to use "id" instead of "identiifer" as in .Identifier ...
	Identifier   string      `json:"id,omitempty" yaml:"id,omitempty"`
	RelationType *TypeDetail `json:"relation_type,omitempty" yaml:"relation_type,omitempty"`
	ResourceType *TypeDetail `json:"resource_type,omitempty" yaml:"resource_type,omitempty"`
}

FunderIdentifier holds an Identifier, e.g. ORCID, ROR, ISNI, GND for a person for organization it holds GRID, ROR. etc.

type Geometry

type Geometry struct {
	Type        string    `json:"type,omitempty"`
	Coordinates []float64 `json:"coordinates,omitempty"`
}

type Identifier

type Identifier struct {
	Scheme     string `json:"scheme,omitempty" yaml:"scheme,omitempty"`
	Name       string `json:"name,omitempty" yaml:"name,omitempty"`
	Title      string `json:"title,omitempty" yaml:"title,omitempty"`
	Number     string `json:"number,omitempty" yaml:"number,omitempty"`
	Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"`
	// ID holds an identifier, e.g. ROR in funder ... It's a shame it duplicates Identifier ...
	ID           string      `json:"id,omitempty" yaml:"id,omitempty"`
	RelationType *TypeDetail `json:"relation_type,omitempty" yaml:"relation_type,omitempty"`
	ResourceType *TypeDetail `json:"resource_type,omitempty" yaml:"resource_type,omitempty"`
}

Identifier holds an Identifier, e.g. ORCID, ROR, ISNI, GND for a person for organization it holds GRID, ROR. etc.

func (*Identifier) String added in v0.0.13

func (identifier *Identifier) String() string

type Location

type Location struct {
	Feature []*Feature `json:"feature,omitempty"`
}

type Metadata

type Metadata struct {
	ResourceType           map[string]interface{}   `json:"resource_type,omitempty"` // Resource type id from the controlled vocabulary.
	Creators               []*Creator               `json:"creators,omitempty"`      //list of creator information (person or organization)
	Title                  string                   `json:"title"`
	PublicationDate        string                   `json:"publication_date,omitempty"`
	AdditionalTitles       []*TitleDetail           `json:"additional_titles,omitempty"`
	Description            string                   `json:"description,omitempty"`
	AdditionalDescriptions []*Description           `json:"additional_descriptions,omitempty"`
	Rights                 []*Right                 `json:"rights,omitempty"`
	Contributors           []*Creator               `json:"contributors,omitempty"`
	Subjects               []*Subject               `json:"subjects,omitempty"`
	Languages              []map[string]interface{} `json:"languages,omitempty"`
	Dates                  []*DateType              `json:"dates,omitempty"`
	Version                string                   `json:"version,omitempty"`
	Publisher              string                   `json:"publisher,omitempty"`
	Identifiers            []*Identifier            `json:"identifiers,omitempty"`
	RelatedIdentifiers     []*Identifier            `json:"related_identifiers,omitempty"`

	Funding []*Funder `json:"funding,omitempty"`
}

Metadata holds the primary metadata about the record. This is where most of the EPrints 3.3.x data is mapped into.

func (*Metadata) Diff

func (m *Metadata) Diff(t *Metadata) (*Metadata, *Metadata)

Diff takes a new Metadata struct and compares it with and existing Metadata struct. It rturns two Metadata structs with only the different attributes sets.

```

src, err := os.ReadFile("old-record.json")
// ... handler error ...
oldRecord := new(simplified.Record)
if err = json.Unmarshal(src, &oldRecord) {
    // ... handler error ...
}
src, err = os.ReadFile("new-record.json")
newRecord := new(simplified.Record)
if err = json.Unmarshal(src, &newRecord) {
    // ... handler error ...
}
// Now create to new minimal Metadata structs with Diff.
o, n := oldRecord.Metadata.Diff(newRecord.Metadata)
// Convert to a JSON two cell array of old and new changes
src, err = json.MarshalIndent([]*Metadata{o, n}, "", "     ")
// ... handler error ...
// Print out the formatted JSON
fmt.Printf("%s\n", src)

```

func (*Metadata) DiffAsJSON

func (m *Metadata) DiffAsJSON(t *Metadata) ([]byte, error)

DiffAsJSON takes a diff of two metadata objects and returns a two cell array with the minimal object reflecting the changes from old to new. ```

src, err := os.ReadFile("old-record.json")
// ... handler error ...
oldRecord := new(simplified.Record)
if err = json.Unmarshal(src, &oldRecord) {
    // ... handler error ...
}
src, err = os.ReadFile("new-record.json")
newRecord := new(simplified.Record)
if err = json.Unmarshal(src, &newRecord) {
    // ... handler error ...
}
// Now create our JSON Diff
src, err := := oldRecord.Metadata.DiffAsJSON(newRecord.Metadata)
// ... handler error ...
// Print out the formatted JSON
fmt.Printf("%s\n", src)

```

type PersistentIdentifier

type PersistentIdentifier struct {
	Identifier string `json:"identifier,omitempty"` // The identifier value
	Provider   string `json:"provider,omitempty"`   // The provider idenitifier used internally by the system
	Client     string `json:"client,omitempty"`     // The client identifier used for connecting with an external registration service.
}

PersistentIdentifier holds an Identifier, e.g. ORCID, ROR, ISNI, GND

type Person added in v0.0.12

type Person struct {
	Name        string        `json:"name,omitempty" yaml:"name,omitempty"`
	Sort        string        `json:"sort_name,omitempty" yaml:"sort_name,omitempty"`
	Family      string        `json:"family_name,omitempty" yaml:"family_name,omitempty"`
	Given       string        `json:"given_name,omitempty" yaml:"given_name,omitempty"`
	Identifiers []*Identifier `json:"identifiers,omitempty" yaml:"identifiers,omitempty"`
	// NOTE: Affiliations are captured at the PersonOrOrg level in RDM, this
	// is in Person which is used in our vocabulary generation.
	Affiliations []*Affiliation `json:"affiliations,omitempty" yaml:"affiliations,omitempty"`
}

An individual person record

func (*Person) GetIdentifier added in v0.0.12

func (p *Person) GetIdentifier(scheme string) string

func (*Person) HasAffiliation added in v0.0.16

func (p *Person) HasAffiliation(target *Affiliation) bool

HasAffiliation checks a PersonOrOrg record for a specific affiliation

func (*Person) Resolve added in v0.0.12

func (p *Person) Resolve() error

Resolve takes the person object and resolves missing attributes based on how InvenioRDM handles things.

type PersonOrOrg

type PersonOrOrg struct {
	ID   string `json:"clpid,omitempty" yaml:"clpid,omitempty"` // The Caltech Library internal person or organizational identifier used to cross walk data across library systems. (this is not part of Invenion 3)
	Type string `json:"type,omitempty"`                         // The type of name. Either "personal" or "organizational".

	GivenName  string `json:"given_name,omitempty" xml:"given_name,omitempty" yaml:"given_name,omitempty"`    // GivenName holds a peron's given name, e.g. Jane
	FamilyName string `json:"family_name,omitempty" xml:"family_name,omitempty" yaml:"family_name,omitempty"` // FamilyName holds a person's family name, e.g. Doe
	Name       string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"`                      // Name holds a corporate name, e.g. The Unseen University

	// Identifiers holds a list of unique ID like ORCID, GND, ROR, ISNI
	Identifiers []*Identifier `json:"identifiers,omitempty" yaml:"identifiers,omitempty"`

	// Roles of the person or organization selected from a customizable controlled vocabular.
	Role *Role `json:"role,omitempty"`
}

PersonOrOrg holds either a person or corporate entity information for the creators associated with the record.

type Record

type Record struct {
	// Scheme indicates the schema and version of records
	Schema string `json:"$schema,omitempty"`
	// Interneral persistent identifier for a specific version.
	ID string `json:"id,omitempty"`

	// The internal persistent identifier for ALL versions.
	Parent *RecordIdentifier `json:"parent,omitempty"`
	// System-managed external persistent identifiers (DOI, Handles, OAI-PMH identifiers)
	ExternalPIDs map[string]*PersistentIdentifier `json:"pids,omitempty"`
	// Descriptive metadata for the resource
	Metadata *Metadata `json:"metadata,omitempty"`
	// Associated files information.
	Files *Files `json:"files,omitempty"`
	// Access control for record, if access.status is "restricted" it is NOT a public record.
	RecordAccess *RecordAccess `json:"access,omitempty"`
	// This is the place where RDM custom fields get mapped.
	// Journal article support is done via CustomFields. E.g.
	// “`
	// "custom_fields": {
	//     "journal:journal": {
	//         "issue": "7",
	//         "pages": "15-23",
	//         "title": "Nature",
	//         "volume": "645"
	//     }
	// },
	// “`
	CustomFields map[string]interface{} `json:"custom_fields,omitempty"`
	// Tombstone (deasscession) information.
	Tombstone *Tombstone `json:"tombstone,omitempty"`
	// create time for record
	Created time.Time `json:"created,omitempty"`
	// modified time for record
	Updated time.Time `json:"updated,omitempty"`

	// DEBUGING: Test if string value.
	//Created string `json:"created,omitempty"`
	//Updated string `json:"updated,omitempty"`
	Versions *RecordVersions `json:"versions,omitempty"`
}

Record implements the top level Invenio 3 record structure

func (*Record) AsMarkdown

func (rec *Record) AsMarkdown() []byte

func (*Record) Diff

func (rec *Record) Diff(t *Record) (*Record, *Record)

Diff takes a new Record struct and compares it with and existing Record struct. It rturns two Record structs with only the different attributes sets.

```

src, err := os.ReadFile("old-record.json")
// ... handler error ...
oldRecord := new(simplified.Record)
if err = json.Unmarshal(src, &oldRecord) {
    // ... handler error ...
}
src, err = os.ReadFile("new-record.json")
newRecord := new(simplified.Record)
if err = json.Unmarshal(src, &newRecord) {
    // ... handler error ...
}
// Now create to new minimal Record structs with Diff.
o, n := oldRecord.Diff(newRecord)
// Convert to a JSON two cell array of old and new changes
src, err = json.MarshalIndent([]*Record{o, n}, "", "     ")
// ... handler error ...
// Print out the formatted JSON
fmt.Printf("%s\n", src)

```

func (*Record) DiffAsJSON

func (m *Record) DiffAsJSON(t *Record) ([]byte, error)

DiffAsJSON takes a diff of two Record objects and returns a two cell array with the minimal Record reflecting the changes from old to new. ```

src, err := os.ReadFile("old-record.json")
// ... handler error ...
oldRecord := new(simplified.Record)
if err = json.Unmarshal(src, &oldRecord) {
    // ... handler error ...
}
src, err = os.ReadFile("new-record.json")
newRecord := new(simplified.Record)
if err = json.Unmarshal(src, &newRecord) {
    // ... handler error ...
}
// Now create our JSON Diff
src, err := := oldRecord.DiffAsJSON(newRecord)
// ... handler error ...
// Print out the formatted JSON
fmt.Printf("%s\n", src)

```

func (*Record) ToString

func (rec *Record) ToString() []byte

type RecordAccess

type RecordAccess struct {
	Status  string   `json:"status,omitempty"`  // Status is "open" for public records, not sure other values
	Record  string   `json:"record,omitempty"`  // "public" or "restricted. Read access to the record.
	Files   string   `json:"files,omitempty"`   // "public" or "restricted". Read access to the record's files.
	Embargo *Embargo `json:"embargo,omitempty"` // Embargo options for the record.
}

RecordAccess implements a datastructure used by Invenio 3 to control record level accesss, e.g. in the REST API.

type RecordIdentifier

type RecordIdentifier struct {
	ID          string     `json:"id"`                    // The identifier of the parent record
	Access      *Access    `json:"access,omitempty"`      // Access details for the record as a whole
	Communities *Community `json:"communities,omitempty"` // Holds community identifier(s)
}

RecordIdentifier implements the scheme of "parent", a persistant identifier to the record.

type RecordVersions added in v0.0.23

type RecordVersions struct {
	IsLatest      bool `json:"is_latest,omitempty"`
	IsLatestDraft bool `json:"is_latest_draft,omitempty"`
	Index         int  `json:"index,omitempty"`
}

RecordVersions holds the version states for RDM structured records.

type Right struct {
	ID          string            `json:"id,omitempty"`          // Identifier value
	Title       map[string]string `json:"title,omitempty"`       // Localized human readable title e.g., `{"en": "The ACME Corporation License."}`.
	Description map[string]string `json:"description,omitempty"` // Localized license description text e.g., `{"en":"This license ..."}`.
	Link        string            `json:"link,omitempty"`        // Link to full license.
}

Right holds a specific Rights element for the Metadata's list of Rights.

NOTE: for REST API lookup by ID or Title (but not both) should be supported at the same end point. I.e. they both must be unique with in their set of field values.

type Role

type Role struct {
	ID    string            `json:"id,omitempty"`
	Title map[string]string `json:"title,omitempty"`
	Props map[string]string `json:"props,omitempty"`
}

Role is an object describing a relationship to authorship

type Subject

type Subject struct {
	Subject string `json:"subject,omitempty"`
	ID      string `json:"id,omitempty"`
}

Subject element holds one of a list of subjects in the Metadata element.

type TitleDetail

type TitleDetail struct {
	Title    string `json:"title,omitempty"`
	Encoding string `json:"en,omitempty"`
	Type     *Type  `json:"type,omitempty"`
	Lang     *Type  `json:"lang,omitempty"`
}

TitleDetail is used by AdditionalTitles in Metadata.

type Tombstone

type Tombstone struct {
	Reason    string    `json:"reason,omitempty"`
	Category  string    `json:"category,omitempty"`
	RemovedBy *User     `json:"removed_by,omitempty"`
	Timestamp time.Time `json:"timestamp,omitempty"`
}

Tombstone

type Type

type Type struct {
	ID    string            `json:"id,omitempty"`
	Name  string            `json:"name,omitempty"`
	Title map[string]string `json:"title,omitempty"`
}

Type is an Invenio 3 e.g. ResourceType, title type or language

type TypeDetail

type TypeDetail struct {
	ID    string                 `json:"id,omitempty"`
	Name  string                 `json:"name,omitempty"`
	Title map[string]interface{} `json:"title,omitempty"`
}

Type is an alternate expression of a type where title is map with additional info like language. It is used to describe relationships and resources in Identifiers. It is a variation of Type.

type User

type User struct {
	User        int    `json:"user,omitempty"`         // User (integer) identifier
	DisplayName string `json:"display_name,omitempty"` // This is my field to quickly associate the internal integer user id with a name for reporting and display.
	Email       string `json:"email,omitempty"`        // This is my field to quickly display a concact email associated with the integer user id.
}

User is a data structured used in Access to describe record ownership or user actions.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL