From ef8e67c8a61ac9fd7e5dca5d3ac8770bcf8df621 Mon Sep 17 00:00:00 2001 From: Brian Beck Date: Sun, 11 Dec 2016 20:03:05 -0800 Subject: [PATCH] Add support for browsing and looking up collections (#12) Fixes #6. --- docs/schema.md | 147 +++- docs/types.md | 397 ++++++++- schema.json | 763 +++++++++++++++++- src/queries/browse.js | 49 +- src/queries/lookup.js | 2 + src/types/collection.js | 60 ++ src/types/helpers.js | 2 + src/types/index.js | 1 + .../fixtures/3d2ee72516840ca0816bd567f766b32a | 1 + .../3d2ee72516840ca0816bd567f766b32a.headers | 27 + .../fixtures/6f51f7057a8ad55969f83563724a58d9 | Bin 0 -> 2201 bytes .../6f51f7057a8ad55969f83563724a58d9.headers | 29 + .../fixtures/77bf843f88aa61a66ec61a238b892956 | Bin 0 -> 2904 bytes .../77bf843f88aa61a66ec61a238b892956.headers | 29 + .../fixtures/83ae719cb34d0210568c345deed9cfff | Bin 0 -> 287 bytes .../83ae719cb34d0210568c345deed9cfff.headers | 29 + .../fixtures/b8876a6891538843bd4c95e0fc301d39 | Bin 0 -> 4172 bytes .../b8876a6891538843bd4c95e0fc301d39.headers | 29 + test/schema.js | 61 +- 19 files changed, 1596 insertions(+), 30 deletions(-) create mode 100644 src/types/collection.js create mode 100644 test/fixtures/3d2ee72516840ca0816bd567f766b32a create mode 100644 test/fixtures/3d2ee72516840ca0816bd567f766b32a.headers create mode 100644 test/fixtures/6f51f7057a8ad55969f83563724a58d9 create mode 100644 test/fixtures/6f51f7057a8ad55969f83563724a58d9.headers create mode 100644 test/fixtures/77bf843f88aa61a66ec61a238b892956 create mode 100644 test/fixtures/77bf843f88aa61a66ec61a238b892956.headers create mode 100644 test/fixtures/83ae719cb34d0210568c345deed9cfff create mode 100644 test/fixtures/83ae719cb34d0210568c345deed9cfff.headers create mode 100644 test/fixtures/b8876a6891538843bd4c95e0fc301d39 create mode 100644 test/fixtures/b8876a6891538843bd4c95e0fc301d39.headers 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 0000000000000000000000000000000000000000..db45e0855c0fa6b8d035692a442476a8d5f1c452 GIT binary patch literal 2201 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..57d0d09c84b632868e9787b8ddc938bf08136586 GIT binary patch literal 4172 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 W@NT44sQD|yzWyHqv8e_yO8@{HCJv+k literal 0 HcmV?d00001 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) +})