This commit is contained in:
Brian Beck 2016-08-30 23:33:29 -07:00
parent d67e6433b4
commit 8759943638
20 changed files with 504 additions and 108 deletions

View file

@ -43,6 +43,8 @@
"express": "^4.14.0", "express": "^4.14.0",
"express-graphql": "^0.5.3", "express-graphql": "^0.5.3",
"graphql": "^0.6.2", "graphql": "^0.6.2",
"graphql-relay": "^0.4.2",
"pascalcase": "^0.1.1",
"qs": "^6.2.1", "qs": "^6.2.1",
"request": "^2.74.0", "request": "^2.74.0",
"retry": "^0.9.0" "retry": "^0.9.0"

View file

@ -65,13 +65,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -92,13 +92,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -119,13 +119,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -146,13 +146,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -173,13 +173,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -200,13 +200,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -227,13 +227,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -254,13 +254,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -281,13 +281,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -308,13 +308,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -335,13 +335,13 @@
"args": [ "args": [
{ {
"name": "id", "name": "id",
"description": null, "description": "The ID of an object",
"type": { "type": {
"kind": "NON_NULL", "kind": "NON_NULL",
"name": null, "name": null,
"ofType": { "ofType": {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"ofType": null "ofType": null
} }
}, },
@ -364,8 +364,8 @@
}, },
{ {
"kind": "SCALAR", "kind": "SCALAR",
"name": "MBID", "name": "ID",
"description": "The `MBID` scalar represents MusicBrainz identifiers, which are 36-character UUIDs.", "description": "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.",
"fields": null, "fields": null,
"inputFields": null, "inputFields": null,
"interfaces": null, "interfaces": null,
@ -379,6 +379,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -681,6 +697,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -690,13 +711,96 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "INTERFACE",
"name": "Node",
"description": "An object with an ID",
"fields": [
{
"name": "id",
"description": "The id of the object.",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": [
{
"kind": "OBJECT",
"name": "Area",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Artist",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Recording",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Release",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Label",
"ofType": null
},
{
"kind": "OBJECT",
"name": "ReleaseGroup",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Work",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Event",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Place",
"ofType": null
},
{
"kind": "OBJECT",
"name": "Instrument",
"ofType": null
},
{
"kind": "OBJECT",
"name": "URL",
"ofType": null
}
]
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
"description": "An entity in the MusicBrainz schema.", "description": "An entity in the MusicBrainz schema.",
"fields": [ "fields": [
{ {
"name": "id", "name": "mbid",
"description": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -773,6 +877,16 @@
} }
] ]
}, },
{
"kind": "SCALAR",
"name": "MBID",
"description": "The `MBID` scalar represents MusicBrainz identifiers, which are 36-character UUIDs.",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "SCALAR", "kind": "SCALAR",
"name": "String", "name": "String",
@ -800,6 +914,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -1209,6 +1339,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -1375,6 +1510,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -1590,6 +1741,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -1795,6 +1951,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -2148,6 +2320,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -2199,6 +2376,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -2425,6 +2618,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -2451,6 +2649,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -2710,6 +2924,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -3700,6 +3919,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -3842,6 +4077,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -3858,6 +4098,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -3971,6 +4227,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -3997,6 +4258,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -4147,6 +4424,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -4208,6 +4490,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -4285,6 +4583,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",
@ -4301,6 +4604,22 @@
"fields": [ "fields": [
{ {
"name": "id", "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": null, "description": null,
"args": [], "args": [],
"type": { "type": {
@ -4346,6 +4665,11 @@
], ],
"inputFields": null, "inputFields": null,
"interfaces": [ "interfaces": [
{
"kind": "INTERFACE",
"name": "Node",
"ofType": null
},
{ {
"kind": "INTERFACE", "kind": "INTERFACE",
"name": "Entity", "name": "Entity",

View file

@ -40,8 +40,8 @@ export default class MusicBrainz {
// we then wait a few seconds before making more. In practice this can // we then wait a few seconds before making more. In practice this can
// seemingly be set to about 5 requests every 5 seconds before we're // seemingly be set to about 5 requests every 5 seconds before we're
// considered to exceed the rate limit. // considered to exceed the rate limit.
limit: 3, limit: 5,
limitPeriod: 3000, limitPeriod: 5000,
concurrency: 10, concurrency: 10,
retries: 10, retries: 10,
// It's OK for `retryDelayMin` to be less than one second, even 0, because // It's OK for `retryDelayMin` to be less than one second, even 0, because

View file

@ -1,10 +1,12 @@
import { GraphQLSchema, GraphQLObjectType } from 'graphql' import { GraphQLSchema, GraphQLObjectType } from 'graphql'
import { LookupQuery, BrowseQuery, SearchQuery } from './queries' import { LookupQuery, BrowseQuery, SearchQuery } from './queries'
import { nodeField } from './types/node'
export default new GraphQLSchema({ export default new GraphQLSchema({
query: new GraphQLObjectType({ query: new GraphQLObjectType({
name: 'RootQuery', name: 'RootQuery',
fields: () => ({ fields: () => ({
node: nodeField,
lookup: { type: LookupQuery, resolve: () => ({}) }, lookup: { type: LookupQuery, resolve: () => ({}) },
browse: { type: BrowseQuery, resolve: () => ({}) }, browse: { type: BrowseQuery, resolve: () => ({}) },
search: { type: SearchQuery, resolve: () => ({}) } search: { type: SearchQuery, resolve: () => ({}) }

View file

@ -1,7 +1,10 @@
import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type' import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { import {
id, id,
mbid,
name, name,
sortName, sortName,
disambiguation, disambiguation,
@ -9,16 +12,16 @@ import {
events, events,
labels, labels,
places, places,
releases, releases
createPageType
} from './helpers' } from './helpers'
const Area = new GraphQLObjectType({ const Area = new GraphQLObjectType({
name: 'Area', name: 'Area',
description: 'A country, region, city or the like.', description: 'A country, region, city or the like.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
name, name,
sortName, sortName,
disambiguation, disambiguation,
@ -34,5 +37,6 @@ const Area = new GraphQLObjectType({
}) })
}) })
export const AreaPage = createPageType(Area) const { connectionType: AreaConnection } = connectionDefinitions({ nodeType: Area })
export { AreaConnection }
export default Area export default Area

View file

@ -1,4 +1,6 @@
import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type' import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import Alias from './alias' import Alias from './alias'
import Area from './area' import Area from './area'
@ -6,6 +8,7 @@ import {
getFallback, getFallback,
fieldWithID, fieldWithID,
id, id,
mbid,
name, name,
sortName, sortName,
disambiguation, disambiguation,
@ -14,8 +17,7 @@ import {
releases, releases,
releaseGroups, releaseGroups,
works, works,
relations, relations
createPageType
} from './helpers' } from './helpers'
const Artist = new GraphQLObjectType({ const Artist = new GraphQLObjectType({
@ -23,9 +25,10 @@ const Artist = new GraphQLObjectType({
description: description:
'An artist is generally a musician, a group of musicians, or another ' + 'An artist is generally a musician, a group of musicians, or another ' +
'music professional (composer, engineer, illustrator, producer, etc.)', 'music professional (composer, engineer, illustrator, producer, etc.)',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
name, name,
sortName, sortName,
disambiguation, disambiguation,
@ -65,5 +68,6 @@ const Artist = new GraphQLObjectType({
}) })
}) })
export const ArtistPage = createPageType(Artist) const { connectionType: ArtistConnection } = connectionDefinitions({ nodeType: Artist })
export { ArtistConnection }
export default Artist export default Artist

View file

@ -1,5 +1,5 @@
import { GraphQLInterfaceType } from 'graphql/type' import { GraphQLInterfaceType } from 'graphql'
import { id } from './helpers' import { mbid } from './helpers'
export default new GraphQLInterfaceType({ export default new GraphQLInterfaceType({
name: 'Entity', name: 'Entity',
@ -10,6 +10,6 @@ export default new GraphQLInterfaceType({
} }
}, },
fields: () => ({ fields: () => ({
id mbid
}) })
}) })

View file

@ -1,13 +1,15 @@
import { GraphQLObjectType, GraphQLString, GraphQLBoolean } from 'graphql/type' import { GraphQLObjectType, GraphQLString, GraphQLBoolean } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { Time } from './scalars' import { Time } from './scalars'
import { import {
fieldWithID, fieldWithID,
id, id,
mbid,
name, name,
disambiguation, disambiguation,
lifeSpan, lifeSpan
createPageType
} from './helpers' } from './helpers'
const Event = new GraphQLObjectType({ const Event = new GraphQLObjectType({
@ -15,9 +17,10 @@ const Event = new GraphQLObjectType({
description: description:
'An organized event which people can attend, usually live performances ' + 'An organized event which people can attend, usually live performances ' +
'like concerts and festivals.', 'like concerts and festivals.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
name, name,
disambiguation, disambiguation,
lifeSpan, lifeSpan,
@ -28,5 +31,6 @@ const Event = new GraphQLObjectType({
}) })
}) })
export const EventPage = createPageType(Event) const { connectionType: EventConnection } = connectionDefinitions({ nodeType: Event })
export { EventConnection }
export default Event export default Event

View file

@ -1,12 +1,14 @@
import dashify from 'dashify' import dashify from 'dashify'
import pascalCase from 'pascalcase'
import { import {
GraphQLObjectType, GraphQLObjectType,
GraphQLString, GraphQLString,
GraphQLInt, GraphQLInt,
GraphQLList, GraphQLList,
GraphQLNonNull GraphQLNonNull
} from 'graphql/type' } from 'graphql'
import { MBID, DateType } from './scalars' import { globalIdField } from 'graphql-relay'
import { MBID } from './scalars'
import { ReleaseGroupType, ReleaseStatus } from './enums' import { ReleaseGroupType, ReleaseStatus } from './enums'
import ArtistCredit from './artist-credit' import ArtistCredit from './artist-credit'
import Artist from './artist' import Artist from './artist'
@ -27,6 +29,9 @@ import {
includeRelations includeRelations
} from '../resolvers' } from '../resolvers'
export const toNodeType = pascalCase
export const toEntityType = dashify
export function getByline (data) { export function getByline (data) {
const credit = data['artist-credit'] const credit = data['artist-credit']
if (credit && credit.length) { if (credit && credit.length) {
@ -94,41 +99,8 @@ export function searchQuery (entityPage) {
} }
} }
export function createPageType (type) { export const id = globalIdField()
const singularName = dashify(type.name) export const mbid = { type: new GraphQLNonNull(MBID) }
const pluralName = singularName + (singularName.endsWith('s') ? '' : 's')
return new GraphQLObjectType({
name: `${type.name}Page`,
description: `A page of ${type.name} results from browsing or searching.`,
fields: {
count: {
type: new GraphQLNonNull(GraphQLInt),
resolve: list => {
if (list.count != null) {
return list.count
}
return list[`${singularName}-count`]
}
},
offset: {
type: new GraphQLNonNull(GraphQLInt),
resolve: list => {
if (list.offset != null) {
return list.offset
}
return list[`${singularName}-offset`]
}
},
created: { type: DateType },
results: {
type: new GraphQLNonNull(new GraphQLList(type)),
resolve: list => list[pluralName]
}
}
})
}
export const id = { type: new GraphQLNonNull(MBID) }
export const name = { type: GraphQLString } export const name = { type: GraphQLString }
export const sortName = { type: GraphQLString, resolve: getHyphenated } export const sortName = { type: GraphQLString, resolve: getHyphenated }
export const title = { type: GraphQLString } export const title = { type: GraphQLString }

View file

@ -1,5 +1,6 @@
export { MBID, DateType, IPI, URLString } from './scalars' export { MBID, DateType, IPI, URLString } from './scalars'
export { ReleaseGroupType, ReleaseStatus } from './enums' export { ReleaseGroupType, ReleaseStatus } from './enums'
export { default as Node } from './node'
export { default as Entity } from './entity' export { default as Entity } from './entity'
export { default as Area, AreaPage } from './area' export { default as Area, AreaPage } from './area'
export { default as Artist, ArtistPage } from './artist' export { default as Artist, ArtistPage } from './artist'
@ -10,5 +11,6 @@ export { default as Place, PlacePage } from './place'
export { default as Recording, RecordingPage } from './recording' export { default as Recording, RecordingPage } from './recording'
export { default as Release, ReleasePage } from './release' export { default as Release, ReleasePage } from './release'
export { default as ReleaseGroup, ReleaseGroupPage } from './release-group' export { default as ReleaseGroup, ReleaseGroupPage } from './release-group'
export { default as Series, SeriesPage } from './series'
export { default as URL, URLPage } from './url' export { default as URL, URLPage } from './url'
export { default as Work, WorkPage } from './work' export { default as Work, WorkPage } from './work'

View file

@ -1,8 +1,10 @@
import { GraphQLObjectType, GraphQLString } from 'graphql/type' import { GraphQLObjectType, GraphQLString } from 'graphql/type'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { import {
fieldWithID, fieldWithID,
id, id,
mbid,
name, name,
disambiguation disambiguation
} from './helpers' } from './helpers'
@ -11,9 +13,10 @@ const Instrument = new GraphQLObjectType({
name: 'Instrument', name: 'Instrument',
description: description:
'Instruments are devices created or adapted to make musical sounds.', 'Instruments are devices created or adapted to make musical sounds.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
name, name,
disambiguation, disambiguation,
description: { type: GraphQLString }, description: { type: GraphQLString },

View file

@ -4,26 +4,29 @@ import {
GraphQLString, GraphQLString,
GraphQLInt GraphQLInt
} from 'graphql/type' } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { IPI } from './scalars' import { IPI } from './scalars'
import Area from './area' import Area from './area'
import { import {
id, id,
mbid,
name, name,
sortName, sortName,
disambiguation, disambiguation,
lifeSpan, lifeSpan,
releases, releases,
fieldWithID, fieldWithID
createPageType
} from './helpers' } from './helpers'
const Label = new GraphQLObjectType({ const Label = new GraphQLObjectType({
name: 'Label', name: 'Label',
description: 'Labels represent mostly (but not only) imprints.', description: 'Labels represent mostly (but not only) imprints.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
name, name,
sortName, sortName,
disambiguation, disambiguation,
@ -37,5 +40,6 @@ const Label = new GraphQLObjectType({
}) })
}) })
export const LabelPage = createPageType(Label) const { connectionType: LabelConnection } = connectionDefinitions({ nodeType: Label })
export { LabelConnection }
export default Label export default Label

21
src/types/node.js Normal file
View file

@ -0,0 +1,21 @@
import { nodeDefinitions, fromGlobalId } from 'graphql-relay'
import { lookupLoader } from '../loaders'
import { toEntityType } from './helpers'
const { nodeInterface, nodeField } = nodeDefinitions(
(globalID) => {
const { type, id } = fromGlobalId(globalID)
const entityType = toEntityType(type)
return lookupLoader.load([entityType, id])
},
(obj) => {
try {
return require(`./${obj.entityType}`)
} catch (err) {
return null
}
}
)
export default nodeInterface
export { nodeInterface, nodeField }

View file

@ -1,15 +1,17 @@
import { GraphQLObjectType, GraphQLString } from 'graphql/type' import { GraphQLObjectType, GraphQLString } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { Degrees } from './scalars' import { Degrees } from './scalars'
import Area from './area' import Area from './area'
import { import {
id, id,
mbid,
name, name,
disambiguation, disambiguation,
lifeSpan, lifeSpan,
events, events,
fieldWithID, fieldWithID
createPageType
} from './helpers' } from './helpers'
export const Coordinates = new GraphQLObjectType({ export const Coordinates = new GraphQLObjectType({
@ -26,9 +28,10 @@ const Place = new GraphQLObjectType({
description: description:
'A venue, studio or other place where music is performed, recorded, ' + 'A venue, studio or other place where music is performed, recorded, ' +
'engineered, etc.', 'engineered, etc.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
name, name,
disambiguation, disambiguation,
address: { type: GraphQLString }, address: { type: GraphQLString },
@ -40,5 +43,6 @@ const Place = new GraphQLObjectType({
}) })
}) })
export const PlacePage = createPageType(Place) const { connectionType: PlaceConnection } = connectionDefinitions({ nodeType: Place })
export { PlaceConnection }
export default Place export default Place

View file

@ -1,14 +1,16 @@
import { GraphQLObjectType, GraphQLInt, GraphQLBoolean } from 'graphql/type' import { GraphQLObjectType, GraphQLInt, GraphQLBoolean } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { import {
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artistCredit, artistCredit,
artists, artists,
releases, releases,
relations, relations
createPageType
} from './helpers' } from './helpers'
const Recording = new GraphQLObjectType({ const Recording = new GraphQLObjectType({
@ -16,9 +18,10 @@ const Recording = new GraphQLObjectType({
description: description:
'Represents a unique mix or edit. Has title, artist credit, duration, ' + 'Represents a unique mix or edit. Has title, artist credit, duration, ' +
'list of PUIDs and ISRCs.', 'list of PUIDs and ISRCs.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artistCredit, artistCredit,
@ -30,5 +33,6 @@ const Recording = new GraphQLObjectType({
}) })
}) })
export const RecordingPage = createPageType(Recording) const { connectionType: RecordingConnection } = connectionDefinitions({ nodeType: Recording })
export { RecordingConnection }
export default Recording export default Recording

View file

@ -1,8 +1,11 @@
import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type' import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { DateType } from './scalars' import { DateType } from './scalars'
import { import {
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artistCredit, artistCredit,
@ -10,8 +13,7 @@ import {
releases, releases,
relations, relations,
getHyphenated, getHyphenated,
fieldWithID, fieldWithID
createPageType
} from './helpers' } from './helpers'
const ReleaseGroup = new GraphQLObjectType({ const ReleaseGroup = new GraphQLObjectType({
@ -19,9 +21,10 @@ const ReleaseGroup = new GraphQLObjectType({
description: description:
'Represents an abstract "album" (or "single", or "EP") entity. ' + 'Represents an abstract "album" (or "single", or "EP") entity. ' +
'Technically its a group of releases, with a specified type.', 'Technically its a group of releases, with a specified type.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artistCredit, artistCredit,
@ -34,5 +37,6 @@ const ReleaseGroup = new GraphQLObjectType({
}) })
}) })
export const ReleaseGroupPage = createPageType(ReleaseGroup) const { connectionType: ReleaseGroupConnection } = connectionDefinitions({ nodeType: ReleaseGroup })
export { ReleaseGroupConnection }
export default ReleaseGroup export default ReleaseGroup

View file

@ -1,9 +1,12 @@
import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type' import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { DateType } from './scalars' import { DateType } from './scalars'
import ReleaseEvent from './release-event' import ReleaseEvent from './release-event'
import { import {
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artistCredit, artistCredit,
@ -13,8 +16,7 @@ import {
releaseGroups, releaseGroups,
relations, relations,
getHyphenated, getHyphenated,
fieldWithID, fieldWithID
createPageType
} from './helpers' } from './helpers'
const Release = new GraphQLObjectType({ const Release = new GraphQLObjectType({
@ -23,9 +25,10 @@ const Release = new GraphQLObjectType({
'Real-world release object you can buy in your music store. It has ' + 'Real-world release object you can buy in your music store. It has ' +
'release date and country, list of catalog number and label pairs, ' + 'release date and country, list of catalog number and label pairs, ' +
'packaging type and release status.', 'packaging type and release status.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artistCredit, artistCredit,
@ -47,5 +50,6 @@ const Release = new GraphQLObjectType({
}) })
}) })
export const ReleasePage = createPageType(Release) const { connectionType: ReleaseConnection } = connectionDefinitions({ nodeType: Release })
export { ReleaseConnection }
export default Release export default Release

View file

@ -0,0 +1,30 @@
import { GraphQLObjectType } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity'
import {
id,
mbid,
name,
disambiguation,
fieldWithID
} from './helpers'
const Series = new GraphQLObjectType({
name: 'Series',
description:
'A series is a sequence of separate release groups, releases, ' +
'recordings, works or events with a common theme.',
interfaces: () => [Node, Entity],
fields: () => ({
id,
mbid,
name,
disambiguation,
...fieldWithID('type')
})
})
const { connectionType: SeriesConnection } = connectionDefinitions({ nodeType: Series })
export { SeriesConnection }
export default Series

View file

@ -1,7 +1,9 @@
import { GraphQLObjectType, GraphQLNonNull } from 'graphql/type' import { GraphQLObjectType, GraphQLNonNull } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { URLString } from './scalars' import { URLString } from './scalars'
import { id, relations, createPageType } from './helpers' import { id, mbid, relations } from './helpers'
const URL = new GraphQLObjectType({ const URL = new GraphQLObjectType({
name: 'URL', name: 'URL',
@ -9,13 +11,15 @@ const URL = new GraphQLObjectType({
'A URL pointing to a resource external to MusicBrainz, i.e. an official ' + 'A URL pointing to a resource external to MusicBrainz, i.e. an official ' +
'homepage, a site where music can be acquired, an entry in another ' + 'homepage, a site where music can be acquired, an entry in another ' +
'database, etc.', 'database, etc.',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
resource: { type: new GraphQLNonNull(URLString) }, resource: { type: new GraphQLNonNull(URLString) },
relations relations
}) })
}) })
export const URLPage = createPageType(URL) const { connectionType: URLConnection } = connectionDefinitions({ nodeType: URL })
export { URLConnection }
export default URL export default URL

View file

@ -1,13 +1,15 @@
import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type' import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql/type'
import { connectionDefinitions } from 'graphql-relay'
import Node from './node'
import Entity from './entity' import Entity from './entity'
import { import {
id, id,
mbid,
title, title,
disambiguation, disambiguation,
artists, artists,
relations, relations,
fieldWithID, fieldWithID
createPageType
} from './helpers' } from './helpers'
const Work = new GraphQLObjectType({ const Work = new GraphQLObjectType({
@ -15,9 +17,10 @@ const Work = new GraphQLObjectType({
description: description:
'A distinct intellectual or artistic creation, which can be expressed in ' + 'A distinct intellectual or artistic creation, which can be expressed in ' +
'the form of one or more audio recordings', 'the form of one or more audio recordings',
interfaces: () => [Entity], interfaces: () => [Node, Entity],
fields: () => ({ fields: () => ({
id, id,
mbid,
title, title,
disambiguation, disambiguation,
iswcs: { type: new GraphQLList(GraphQLString) }, iswcs: { type: new GraphQLList(GraphQLString) },
@ -28,5 +31,6 @@ const Work = new GraphQLObjectType({
}) })
}) })
export const WorkPage = createPageType(Work) const { connectionType: WorkConnection } = connectionDefinitions({ nodeType: Work })
export { WorkConnection }
export default Work export default Work