diff --git a/docs/schema.md b/docs/schema.md index 8723359..f1a5b2e 100644 --- a/docs/schema.md +++ b/docs/schema.md @@ -301,10 +301,46 @@ type BrowseQuery { # The MBID of a release group to which the entity is linked. releaseGroup: MBID - # The MBID of a work to which the artist is linked. + # The MBID of a work to which the entity is linked. work: MBID ): ArtistConnection + # Browse collection entities linked to the given arguments. + collections( + after: String + first: Int + + # The MBID of an area to which the entity is linked. + area: MBID + + # The MBID of an artist to which the entity is linked. + artist: MBID + + # The username of the editor who created the collection. + editor: String + + # The MBID of an event to which the entity is linked. + event: MBID + + # The MBID of a label to which the entity is linked. + label: MBID + + # The MBID of a place to which the entity is linked. + place: MBID + + # The MBID of a recording to which the entity is linked. + recording: MBID + + # The MBID of a release to which the entity is linked. + release: MBID + + # The MBID of a release group to which the entity is linked. + releaseGroup: MBID + + # The MBID of a work to which the entity is linked. + work: MBID + ): CollectionConnection + # Browse event entities linked to the given arguments. events( after: String @@ -319,7 +355,7 @@ type BrowseQuery { # The MBID of a collection in which the entity is found. collection: MBID - # The MBID of a place to which the event is linked. + # The MBID of a place to which the entity is linked. place: MBID ): EventConnection @@ -383,7 +419,7 @@ type BrowseQuery { # The MBID of a collection in which the entity is found. collection: MBID - # The MBID of a label to which the release is linked. + # The MBID of a label to which the entity is linked. label: MBID # The MBID of a track that is included in the release. @@ -445,6 +481,100 @@ type BrowseQuery { ): WorkConnection } +# [Collections](https://musicbrainz.org/doc/Collections) are +# lists of entities that users can create. +type Collection implements Node, Entity { + # The ID of an object + id: ID! + + # The MBID of the entity. + mbid: MBID! + + # The official name of the entity. + name: String + + # The username of the editor who created the collection. + editor: String! + + # The type of entity listed in the collection. + entityType: String! + + # The type of collection. + type: String + + # The MBID associated with the value of the `type` + # field. + typeID: MBID + + # A list of areas linked to this entity. + areas(after: String, first: Int): AreaConnection + + # A list of artists linked to this entity. + artists(after: String, first: Int): ArtistConnection + + # A list of events linked to this entity. + events(after: String, first: Int): EventConnection + + # A list of labels linked to this entity. + labels(after: String, first: Int): LabelConnection + + # A list of places linked to this entity. + places(after: String, first: Int): PlaceConnection + + # A list of recordings linked to this entity. + recordings(after: String, first: Int): RecordingConnection + + # A list of releases linked to this entity. + releases( + after: String + first: Int + + # Filter by one or more release group types. + type: [ReleaseGroupType] + + # Filter by one or more release statuses. + status: [ReleaseStatus] + ): ReleaseConnection + + # A list of release groups linked to this entity. + releaseGroups( + after: String + first: Int + + # Filter by one or more release group types. + type: [ReleaseGroupType] + ): ReleaseGroupConnection + + # A list of works linked to this entity. + works(after: String, first: Int): WorkConnection +} + +# A connection to a list of items. +type CollectionConnection { + # Information to aid in pagination. + pageInfo: PageInfo! + + # A list of edges. + edges: [CollectionEdge] + + # A count of the total number of items in this connection, + # ignoring pagination. + totalCount: Int +} + +# An edge in a connection. +type CollectionEdge { + # The item at the end of the edge + node: Collection + + # A cursor for use in pagination + cursor: String! + + # The relevancy score (0–100) assigned by the search engine, if + # these results were found through a search. + score: Int +} + # Geographic coordinates described with latitude and longitude. type Coordinates { # The north–south position of a point on the Earth’s surface. @@ -475,6 +605,9 @@ scalar Degrees # offsets and hence the same disc ID. scalar DiscID +# A length of time, in milliseconds. +scalar Duration + # An entity in the MusicBrainz schema. interface Entity { # The MBID of the entity. @@ -775,6 +908,12 @@ type LookupQuery { mbid: MBID! ): Artist + # Look up a specific collection by its MBID. + collection( + # The MBID of the entity. + mbid: MBID! + ): Collection + # Look up a specific event by its MBID. event( # The MBID of the entity. @@ -1002,7 +1141,7 @@ type Recording implements Node, Entity { # An approximation to the length of the recording, calculated # from the lengths of the tracks using it. - length: Int + length: Duration # Whether this is a video recording. video: Boolean diff --git a/docs/types.md b/docs/types.md index da9f59d..c5787cc 100644 --- a/docs/types.md +++ b/docs/types.md @@ -14,6 +14,9 @@ You may also be interested in reading the [schema in GraphQL syntax](schema.md).
  • [ArtistCredit](#artistcredit)
  • [ArtistEdge](#artistedge)
  • [BrowseQuery](#browsequery)
  • +
  • [Collection](#collection)
  • +
  • [CollectionConnection](#collectionconnection)
  • +
  • [CollectionEdge](#collectionedge)
  • [Coordinates](#coordinates)
  • [Event](#event)
  • [EventConnection](#eventconnection)
  • @@ -66,6 +69,7 @@ You may also be interested in reading the [schema in GraphQL syntax](schema.md).
  • [Date](#date)
  • [Degrees](#degrees)
  • [DiscID](#discid)
  • +
  • [Duration](#duration)
  • [ID](#id)
  • [IPI](#ipi)
  • [ISNI](#isni)
  • @@ -897,7 +901,74 @@ entity. work MBID - The MBID of a work to which the artist is linked. + The MBID of a work to which the entity is linked. + + + collections + CollectionConnection + + Browse collection entities linked to the given arguments. + + + + after + String + + + + first + Int + + + + area + MBID + The MBID of an area to which the entity is linked. + + + artist + MBID + The MBID of an artist to which the entity is linked. + + + editor + String + The username of the editor who created the collection. + + + event + MBID + The MBID of an event to which the entity is linked. + + + label + MBID + The MBID of a label to which the entity is linked. + + + place + MBID + The MBID of a place to which the entity is linked. + + + recording + MBID + The MBID of a recording to which the entity is linked. + + + release + MBID + The MBID of a release to which the entity is linked. + + + releaseGroup + MBID + The MBID of a release group to which the entity is linked. + + + work + MBID + The MBID of a work to which the entity is linked. events @@ -934,7 +1005,7 @@ entity. place MBID - The MBID of a place to which the event is linked. + The MBID of a place to which the entity is linked. labels @@ -1068,7 +1139,7 @@ entity. label MBID - The MBID of a label to which the release is linked. + The MBID of a label to which the entity is linked. track @@ -1179,6 +1250,308 @@ associated with the release. +### Collection + +[Collections](https://musicbrainz.org/doc/Collections) are +lists of entities that users can create. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Field / ArgumentTypeDescription
    id ID! + The ID of an object +
    mbid MBID! + The MBID of the entity. +
    name String + The official name of the entity. +
    editor String! + The username of the editor who created the collection. +
    entityType String! + The type of entity listed in the collection. +
    type String + The type of collection. +
    typeID MBID + The MBID associated with the value of the type +field. +
    areas AreaConnection + A list of areas linked to this entity. +
    afterString
    firstInt
    artists ArtistConnection + A list of artists linked to this entity. +
    afterString
    firstInt
    events EventConnection + A list of events linked to this entity. +
    afterString
    firstInt
    labels LabelConnection + A list of labels linked to this entity. +
    afterString
    firstInt
    places PlaceConnection + A list of places linked to this entity. +
    afterString
    firstInt
    recordings RecordingConnection + A list of recordings linked to this entity. +
    afterString
    firstInt
    releases ReleaseConnection + A list of releases linked to this entity. +
    afterString
    firstInt
    type[ReleaseGroupType]Filter by one or more release group types.
    status[ReleaseStatus]Filter by one or more release statuses.
    releaseGroups ReleaseGroupConnection + A list of release groups linked to this entity. +
    afterString
    firstInt
    type[ReleaseGroupType]Filter by one or more release group types.
    works WorkConnection + A list of works linked to this entity. +
    afterString
    firstInt
    + +### CollectionConnection + +A connection to a list of items. + + + + + + + + + + + + + + + + + + + + + + + +
    Field / ArgumentTypeDescription
    pageInfo PageInfo! + Information to aid in pagination. +
    edges [CollectionEdge] + A list of edges. +
    totalCount Int + A count of the total number of items in this connection, +ignoring pagination. +
    + +### CollectionEdge + +An edge in a connection. + + + + + + + + + + + + + + + + + + + + + + + +
    Field / ArgumentTypeDescription
    node Collection + The item at the end of the edge +
    cursor String! + A cursor for use in pagination +
    score Int + The relevancy score (0–100) assigned by the search engine, if +these results were found through a search. +
    + ### Coordinates Geographic coordinates described with latitude and longitude. @@ -1872,6 +2245,18 @@ A lookup of an individual MusicBrainz entity by its MBID. MBID! The MBID of the entity. + + collection + Collection + + Look up a specific collection by its MBID. + + + + mbid + MBID! + The MBID of the entity. + event Event @@ -2336,7 +2721,7 @@ and will be removed in a major release in the future. Use the equivalent length - Int + Duration An approximation to the length of the recording, calculated from the lengths of the tracks using it. @@ -4760,6 +5145,10 @@ hence different disc IDs. Conversely, two different CDs may happen to have exactly the same set of frame offsets and hence the same disc ID. +### Duration + +A length of time, in milliseconds. + ### ID The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID. diff --git a/schema.json b/schema.json index c6e6ac2..9619465 100644 --- a/schema.json +++ b/schema.json @@ -140,6 +140,33 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "collection", + "description": "Look up a specific collection by its MBID.", + "args": [ + { + "name": "mbid", + "description": "The MBID of the entity.", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "Collection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "event", "description": "Look up a specific event by its MBID.", @@ -863,6 +890,11 @@ "name": "Place", "ofType": null }, + { + "kind": "OBJECT", + "name": "Collection", + "ofType": null + }, { "kind": "OBJECT", "name": "Instrument", @@ -961,6 +993,11 @@ "name": "Place", "ofType": null }, + { + "kind": "OBJECT", + "name": "Collection", + "ofType": null + }, { "kind": "OBJECT", "name": "Instrument", @@ -2053,7 +2090,7 @@ "args": [], "type": { "kind": "SCALAR", - "name": "Int", + "name": "Duration", "ofType": null }, "isDeprecated": false, @@ -2284,6 +2321,16 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "SCALAR", + "name": "Duration", + "description": "A length of time, in milliseconds.", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, { "kind": "ENUM", "name": "ReleaseGroupType", @@ -6332,6 +6379,573 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "Collection", + "description": "[Collections](https://musicbrainz.org/doc/Collections) are\nlists of entities that users can create.", + "fields": [ + { + "name": "id", + "description": "The ID of an object", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "mbid", + "description": "The MBID of the entity.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The official name of the entity.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "editor", + "description": "The username of the editor who created the collection.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "entityType", + "description": "The type of entity listed in the collection.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "type", + "description": "The type of collection.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "typeID", + "description": "The MBID associated with the value of the `type`\nfield.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "areas", + "description": "A list of areas linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "AreaConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "artists", + "description": "A list of artists linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "ArtistConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "events", + "description": "A list of events linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "EventConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "labels", + "description": "A list of labels linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "LabelConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "places", + "description": "A list of places linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "PlaceConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "recordings", + "description": "A list of recordings linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "RecordingConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "releases", + "description": "A list of releases linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "type", + "description": "Filter by one or more release group types.", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "ReleaseGroupType", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "status", + "description": "Filter by one or more release statuses.", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "ReleaseStatus", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "ReleaseConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "releaseGroups", + "description": "A list of release groups linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "type", + "description": "Filter by one or more release group types.", + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "ReleaseGroupType", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "ReleaseGroupConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "works", + "description": "A list of works linked to this entity.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "WorkConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + { + "kind": "INTERFACE", + "name": "Node", + "ofType": null + }, + { + "kind": "INTERFACE", + "name": "Entity", + "ofType": null + } + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AreaConnection", + "description": "A connection to a list of items.", + "fields": [ + { + "name": "pageInfo", + "description": "Information to aid in pagination.", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PageInfo", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "edges", + "description": "A list of edges.", + "args": [], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "AreaEdge", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "totalCount", + "description": "A count of the total number of items in this connection,\nignoring pagination.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "AreaEdge", + "description": "An edge in a connection.", + "fields": [ + { + "name": "node", + "description": "The item at the end of the edge", + "args": [], + "type": { + "kind": "OBJECT", + "name": "Area", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "cursor", + "description": "A cursor for use in pagination", + "args": [], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "score", + "description": "The relevancy score (0–100) assigned by the search engine, if\nthese results were found through a search.", + "args": [], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "Instrument", @@ -6870,7 +7484,7 @@ }, { "name": "work", - "description": "The MBID of a work to which the artist is linked.", + "description": "The MBID of a work to which the entity is linked.", "type": { "kind": "SCALAR", "name": "MBID", @@ -6887,6 +7501,139 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "collections", + "description": "Browse collection entities linked to the given arguments.", + "args": [ + { + "name": "after", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "area", + "description": "The MBID of an area to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "artist", + "description": "The MBID of an artist to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "editor", + "description": "The username of the editor who created the collection.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "event", + "description": "The MBID of an event to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "label", + "description": "The MBID of a label to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "place", + "description": "The MBID of a place to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "recording", + "description": "The MBID of a recording to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "release", + "description": "The MBID of a release to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "releaseGroup", + "description": "The MBID of a release group to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "work", + "description": "The MBID of a work to which the entity is linked.", + "type": { + "kind": "SCALAR", + "name": "MBID", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CollectionConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "events", "description": "Browse event entities linked to the given arguments.", @@ -6943,7 +7690,7 @@ }, { "name": "place", - "description": "The MBID of a place to which the event is linked.", + "description": "The MBID of a place to which the entity is linked.", "type": { "kind": "SCALAR", "name": "MBID", @@ -7205,7 +7952,7 @@ }, { "name": "label", - "description": "The MBID of a label to which the release is linked.", + "description": "The MBID of a label to which the entity is linked.", "type": { "kind": "SCALAR", "name": "MBID", @@ -7448,7 +8195,7 @@ }, { "kind": "OBJECT", - "name": "AreaConnection", + "name": "CollectionConnection", "description": "A connection to a list of items.", "fields": [ { @@ -7476,7 +8223,7 @@ "name": null, "ofType": { "kind": "OBJECT", - "name": "AreaEdge", + "name": "CollectionEdge", "ofType": null } }, @@ -7503,7 +8250,7 @@ }, { "kind": "OBJECT", - "name": "AreaEdge", + "name": "CollectionEdge", "description": "An edge in a connection.", "fields": [ { @@ -7512,7 +8259,7 @@ "args": [], "type": { "kind": "OBJECT", - "name": "Area", + "name": "Collection", "ofType": null }, "isDeprecated": false, diff --git a/src/queries/browse.js b/src/queries/browse.js index 85ff3cb..dc87941 100644 --- a/src/queries/browse.js +++ b/src/queries/browse.js @@ -1,10 +1,11 @@ -import { GraphQLObjectType } from 'graphql' +import { GraphQLObjectType, GraphQLString } from 'graphql' import { forwardConnectionArgs } from 'graphql-relay' import { resolveBrowse } from '../resolvers' import { MBID, AreaConnection, ArtistConnection, + CollectionConnection, EventConnection, DiscID, ISRC, @@ -30,6 +31,18 @@ const collection = { type: MBID, description: 'The MBID of a collection in which the entity is found.' } +const event = { + type: MBID, + description: 'The MBID of an event to which the entity is linked.' +} +const label = { + type: MBID, + description: 'The MBID of a label to which the entity is linked.' +} +const place = { + type: MBID, + description: 'The MBID of a place to which the entity is linked.' +} const recording = { type: MBID, description: 'The MBID of a recording to which the entity is linked.' @@ -42,6 +55,10 @@ const releaseGroup = { type: MBID, description: 'The MBID of a release group to which the entity is linked.' } +const work = { + type: MBID, + description: 'The MBID of a work to which the entity is linked.' +} function createBrowseField (connectionType, args) { const typeName = toWords(connectionType.name.slice(0, -10)) @@ -70,19 +87,28 @@ entity.`, recording, release, releaseGroup, - work: { - type: MBID, - description: 'The MBID of a work to which the artist is linked.' - } + work + }), + collections: createBrowseField(CollectionConnection, { + area, + artist, + editor: { + type: GraphQLString, + description: 'The username of the editor who created the collection.' + }, + event, + label, + place, + recording, + release, + releaseGroup, + work }), events: createBrowseField(EventConnection, { area, artist, collection, - place: { - type: MBID, - description: 'The MBID of a place to which the event is linked.' - } + place }), labels: createBrowseField(LabelConnection, { area, @@ -107,10 +133,7 @@ entity.`, area, artist, collection, - label: { - type: MBID, - description: 'The MBID of a label to which the release is linked.' - }, + label, track: { type: MBID, description: 'The MBID of a track that is included in the release.' diff --git a/src/queries/lookup.js b/src/queries/lookup.js index cf5085e..4f01819 100644 --- a/src/queries/lookup.js +++ b/src/queries/lookup.js @@ -4,6 +4,7 @@ import { mbid, toWords } from '../types/helpers' import { Area, Artist, + Collection, Event, Instrument, Label, @@ -34,6 +35,7 @@ export const LookupQuery = new GraphQLObjectType({ fields: { area: createLookupField(Area), artist: createLookupField(Artist), + collection: createLookupField(Collection), event: createLookupField(Event), instrument: createLookupField(Instrument), label: createLookupField(Label), diff --git a/src/types/collection.js b/src/types/collection.js new file mode 100644 index 0000000..d4d2bba --- /dev/null +++ b/src/types/collection.js @@ -0,0 +1,60 @@ +import { + GraphQLObjectType, + GraphQLNonNull, + GraphQLString +} from 'graphql/type' +import Node from './node' +import Entity from './entity' +import { + id, + mbid, + name, + areas, + artists, + events, + labels, + places, + recordings, + releases, + releaseGroups, + works, + fieldWithID, + resolveHyphenated, + connectionWithExtras +} from './helpers' + +const Collection = new GraphQLObjectType({ + name: 'Collection', + description: `[Collections](https://musicbrainz.org/doc/Collections) are +lists of entities that users can create.`, + interfaces: () => [Node, Entity], + fields: () => ({ + id, + mbid, + name, + editor: { + type: new GraphQLNonNull(GraphQLString), + description: 'The username of the editor who created the collection.' + }, + entityType: { + type: new GraphQLNonNull(GraphQLString), + description: 'The type of entity listed in the collection.', + resolve: resolveHyphenated + }, + ...fieldWithID('type', { + description: 'The type of collection.' + }), + areas, + artists, + events, + labels, + places, + recordings, + releases, + releaseGroups, + works + }) +}) + +export const CollectionConnection = connectionWithExtras(Collection) +export default Collection diff --git a/src/types/helpers.js b/src/types/helpers.js index 2c8423d..4d13852 100644 --- a/src/types/helpers.js +++ b/src/types/helpers.js @@ -18,6 +18,7 @@ import { MBID } from './scalars' import { ReleaseGroupType, ReleaseStatus } from './enums' import Alias from './alias' import ArtistCredit from './artist-credit' +import { AreaConnection } from './area' import { ArtistConnection } from './artist' import { EventConnection } from './event' import { LabelConnection } from './label' @@ -221,6 +222,7 @@ export const releaseStatus = { description: 'Filter by one or more release statuses.' } +export const areas = linkedQuery(AreaConnection) export const artists = linkedQuery(ArtistConnection) export const events = linkedQuery(EventConnection) export const labels = linkedQuery(LabelConnection) diff --git a/src/types/index.js b/src/types/index.js index d6e9ca4..5a9dbe2 100644 --- a/src/types/index.js +++ b/src/types/index.js @@ -4,6 +4,7 @@ export { default as Node } from './node' export { default as Entity, EntityConnection } from './entity' export { default as Area, AreaConnection } from './area' export { default as Artist, ArtistConnection } from './artist' +export { default as Collection, CollectionConnection } from './collection' export { default as Event, EventConnection } from './event' export { default as Instrument, InstrumentConnection } from './instrument' export { default as Label, LabelConnection } from './label' diff --git a/test/fixtures/3d2ee72516840ca0816bd567f766b32a b/test/fixtures/3d2ee72516840ca0816bd567f766b32a new file mode 100644 index 0000000..c11e816 --- /dev/null +++ b/test/fixtures/3d2ee72516840ca0816bd567f766b32a @@ -0,0 +1 @@ +{"editor":"offbeatadam","type-id":"d94659b2-4ce5-3a98-b4b8-da1131cf33ee","id":"85da782d-2ec0-41ec-a97f-9be464bba309","type":"Release","release-count":579,"name":"Beets Music Collection","entity-type":"release"} \ No newline at end of file diff --git a/test/fixtures/3d2ee72516840ca0816bd567f766b32a.headers b/test/fixtures/3d2ee72516840ca0816bd567f766b32a.headers new file mode 100644 index 0000000..5d9d380 --- /dev/null +++ b/test/fixtures/3d2ee72516840ca0816bd567f766b32a.headers @@ -0,0 +1,27 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 03:50:32 GMT", + "content-type": "application/json; charset=utf-8", + "content-length": "210", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "240", + "x-ratelimit-reset": "1481514632", + "server": "Plack::Handler::Starlet", + "etag": "\"a56ef76b83ccc2d2620ac3f66c7ead50\"", + "access-control-allow-origin": "*" + }, + "url": "http://musicbrainz.org:80/ws/2/collection/85da782d-2ec0-41ec-a97f-9be464bba309?fmt=json", + "time": 404, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.2.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/6f51f7057a8ad55969f83563724a58d9 b/test/fixtures/6f51f7057a8ad55969f83563724a58d9 new file mode 100644 index 0000000..db45e08 Binary files /dev/null and b/test/fixtures/6f51f7057a8ad55969f83563724a58d9 differ diff --git a/test/fixtures/6f51f7057a8ad55969f83563724a58d9.headers b/test/fixtures/6f51f7057a8ad55969f83563724a58d9.headers new file mode 100644 index 0000000..c99bdc2 --- /dev/null +++ b/test/fixtures/6f51f7057a8ad55969f83563724a58d9.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 02:59:37 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "433", + "x-ratelimit-reset": "1481511578", + "server": "Plack::Handler::Starlet", + "etag": "W/\"732418d1bfab7578b6e228d91a40da59\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/artist?collection=06535ef2-adc9-4c50-ad19-ab607d143485&fmt=json", + "time": 483, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.2.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/77bf843f88aa61a66ec61a238b892956 b/test/fixtures/77bf843f88aa61a66ec61a238b892956 new file mode 100644 index 0000000..9e60e4d Binary files /dev/null and b/test/fixtures/77bf843f88aa61a66ec61a238b892956 differ diff --git a/test/fixtures/77bf843f88aa61a66ec61a238b892956.headers b/test/fixtures/77bf843f88aa61a66ec61a238b892956.headers new file mode 100644 index 0000000..9d30e81 --- /dev/null +++ b/test/fixtures/77bf843f88aa61a66ec61a238b892956.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 03:50:33 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "619", + "x-ratelimit-reset": "1481514634", + "server": "Plack::Handler::Starlet", + "etag": "W/\"97326a717e48b9b3aa03b6455ba690bc\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/release?collection=85da782d-2ec0-41ec-a97f-9be464bba309&fmt=json", + "time": 656, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.2.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/83ae719cb34d0210568c345deed9cfff b/test/fixtures/83ae719cb34d0210568c345deed9cfff new file mode 100644 index 0000000..7c3f685 Binary files /dev/null and b/test/fixtures/83ae719cb34d0210568c345deed9cfff differ diff --git a/test/fixtures/83ae719cb34d0210568c345deed9cfff.headers b/test/fixtures/83ae719cb34d0210568c345deed9cfff.headers new file mode 100644 index 0000000..1fc707c --- /dev/null +++ b/test/fixtures/83ae719cb34d0210568c345deed9cfff.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 02:59:36 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "547", + "x-ratelimit-reset": "1481511578", + "server": "Plack::Handler::Starlet", + "etag": "W/\"c9830e30ce33960f506234d5af63ad79\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/collection?artist=24f1766e-9635-4d58-a4d4-9413f9f98a4c&fmt=json", + "time": 516, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.2.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/b8876a6891538843bd4c95e0fc301d39 b/test/fixtures/b8876a6891538843bd4c95e0fc301d39 new file mode 100644 index 0000000..57d0d09 Binary files /dev/null and b/test/fixtures/b8876a6891538843bd4c95e0fc301d39 differ diff --git a/test/fixtures/b8876a6891538843bd4c95e0fc301d39.headers b/test/fixtures/b8876a6891538843bd4c95e0fc301d39.headers new file mode 100644 index 0000000..508c274 --- /dev/null +++ b/test/fixtures/b8876a6891538843bd4c95e0fc301d39.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 02:59:37 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "435", + "x-ratelimit-reset": "1481511578", + "server": "Plack::Handler::Starlet", + "etag": "W/\"ab16e83e578aff3fc917a4a296e76557\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/artist?collection=974fcec4-eca0-4bfe-9a3a-e61aa93c186b&fmt=json", + "time": 579, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.2.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/schema.js b/test/schema.js index 8fd3f0c..27ed87f 100644 --- a/test/schema.js +++ b/test/schema.js @@ -83,7 +83,7 @@ test('schema has a search query', testData, ` test('schema has a browse query', testData, ` { browse { - releaseGroups (artist: "c8da2e40-bd28-4d4e-813a-bd2f51958ba8") { + releaseGroups(artist: "c8da2e40-bd28-4d4e-813a-bd2f51958ba8") { totalCount edges { node { @@ -592,3 +592,62 @@ test('Recordings have a length in milliseconds', testData, ` const { recording } = data.lookup t.is(recording.length, 383493) }) + +test('Collections can be browsed by the entities they contain', testData, ` + { + browse { + collections(artist: "24f1766e-9635-4d58-a4d4-9413f9f98a4c") { + totalCount + edges { + node { + name + editor + entityType + type + artists { + totalCount + edges { + node { + mbid + name + } + } + } + } + } + } + } + } +`, (t, data) => { + const collections = data.browse.collections.edges.map(edge => edge.node) + t.true(collections.length >= 2) + t.true(collections.some(collection => collection.editor === 'arist.on')) + t.true(collections.some(collection => collection.editor === 'ListMyCDs.com')) + collections.forEach(collection => { + t.is(collection.entityType, 'artist') + t.is(collection.type, 'Artist') + t.true(collection.artists.totalCount > 0) + t.true(collection.artists.edges.length > 0) + }) +}) + +test('Collections can be looked up by MBID', testData, ` + { + lookup { + collection(mbid: "85da782d-2ec0-41ec-a97f-9be464bba309") { + name + releases { + edges { + node { + title + } + } + } + } + } + } +`, (t, data) => { + const { collection } = data.lookup + t.is(collection.name, 'Beets Music Collection') + t.is(collection.releases.edges.length, 25) +})