Internal renames, update dependencies, add Travis config

This commit is contained in:
Brian Beck 2016-12-02 00:21:10 -08:00
parent 3dbbf54161
commit 6cb41e1ce0
15 changed files with 240 additions and 217 deletions

16
.travis.yml Normal file
View file

@ -0,0 +1,16 @@
language: node_js
node_js:
- "4"
- "5"
- "6"
# Use container-based Travis infrastructure.
sudo: false
branches:
only:
- master
script:
- yarn run check

View file

@ -1,6 +1,6 @@
import { GraphQLObjectType } from 'graphql' import { GraphQLObjectType } from 'graphql'
import { forwardConnectionArgs } from 'graphql-relay' import { forwardConnectionArgs } from 'graphql-relay'
import { browseResolver } from '../resolvers' import { resolveBrowse } from '../resolvers'
import { import {
MBID, MBID,
URLString, URLString,
@ -42,7 +42,7 @@ const releaseGroup = {
description: 'The MBID of a release group to which the entity is linked.' description: 'The MBID of a release group to which the entity is linked.'
} }
function browseQuery (connectionType, args) { function createBrowseField (connectionType, args) {
const typeName = toWords(connectionType.name.slice(0, -10)) const typeName = toWords(connectionType.name.slice(0, -10))
return { return {
type: connectionType, type: connectionType,
@ -51,7 +51,7 @@ function browseQuery (connectionType, args) {
...forwardConnectionArgs, ...forwardConnectionArgs,
...args ...args
}, },
resolve: browseResolver() resolve: resolveBrowse
} }
} }
@ -60,10 +60,10 @@ export const BrowseQuery = new GraphQLObjectType({
description: `A query for all MusicBrainz entities directly linked to another description: `A query for all MusicBrainz entities directly linked to another
entity.`, entity.`,
fields: { fields: {
areas: browseQuery(AreaConnection, { areas: createBrowseField(AreaConnection, {
collection collection
}), }),
artists: browseQuery(ArtistConnection, { artists: createBrowseField(ArtistConnection, {
area, area,
collection, collection,
recording, recording,
@ -74,7 +74,7 @@ entity.`,
description: 'The MBID of a work to which the artist is linked.' description: 'The MBID of a work to which the artist is linked.'
} }
}), }),
events: browseQuery(EventConnection, { events: createBrowseField(EventConnection, {
area, area,
artist, artist,
collection, collection,
@ -83,21 +83,21 @@ entity.`,
description: 'The MBID of a place to which the event is linked.' description: 'The MBID of a place to which the event is linked.'
} }
}), }),
labels: browseQuery(LabelConnection, { labels: createBrowseField(LabelConnection, {
area, area,
collection, collection,
release release
}), }),
places: browseQuery(PlaceConnection, { places: createBrowseField(PlaceConnection, {
area, area,
collection collection
}), }),
recordings: browseQuery(RecordingConnection, { recordings: createBrowseField(RecordingConnection, {
artist, artist,
collection, collection,
release release
}), }),
releases: browseQuery(ReleaseConnection, { releases: createBrowseField(ReleaseConnection, {
area, area,
artist, artist,
collection, collection,
@ -117,16 +117,16 @@ release, but is not included in the credits for the release itself.`
recording, recording,
releaseGroup releaseGroup
}), }),
releaseGroups: browseQuery(ReleaseGroupConnection, { releaseGroups: createBrowseField(ReleaseGroupConnection, {
artist, artist,
collection, collection,
release release
}), }),
works: browseQuery(WorkConnection, { works: createBrowseField(WorkConnection, {
artist, artist,
collection collection
}), }),
urls: browseQuery(URLConnection, { urls: createBrowseField(URLConnection, {
resource: { resource: {
type: URLString, type: URLString,
description: 'The web address for which to browse URL entities.' description: 'The web address for which to browse URL entities.'
@ -135,7 +135,7 @@ release, but is not included in the credits for the release itself.`
} }
}) })
export const browseField = { export const browse = {
type: BrowseQuery, type: BrowseQuery,
description: 'Browse all MusicBrainz entities directly linked to another entity.', description: 'Browse all MusicBrainz entities directly linked to another entity.',
// We only have work to do once we know what entity types are being requested, // We only have work to do once we know what entity types are being requested,

View file

@ -1,3 +1,3 @@
export { LookupQuery, lookupField } from './lookup' export { LookupQuery, lookup } from './lookup'
export { BrowseQuery, browseField } from './browse' export { BrowseQuery, browse } from './browse'
export { SearchQuery, searchField } from './search' export { SearchQuery, search } from './search'

View file

@ -1,5 +1,5 @@
import { GraphQLObjectType } from 'graphql' import { GraphQLObjectType } from 'graphql'
import { lookupResolver } from '../resolvers' import { resolveLookup } from '../resolvers'
import { mbid, toWords } from '../types/helpers' import { mbid, toWords } from '../types/helpers'
import { import {
Area, Area,
@ -16,13 +16,13 @@ import {
Work Work
} from '../types' } from '../types'
function lookupQuery (entity) { function createLookupField (entity) {
const typeName = toWords(entity.name) const typeName = toWords(entity.name)
return { return {
type: entity, type: entity,
description: `Look up a specific ${typeName} by its MBID.`, description: `Look up a specific ${typeName} by its MBID.`,
args: { mbid }, args: { mbid },
resolve: lookupResolver() resolve: resolveLookup
} }
} }
@ -30,22 +30,22 @@ export const LookupQuery = new GraphQLObjectType({
name: 'LookupQuery', name: 'LookupQuery',
description: 'A lookup of an individual MusicBrainz entity by its MBID.', description: 'A lookup of an individual MusicBrainz entity by its MBID.',
fields: { fields: {
area: lookupQuery(Area), area: createLookupField(Area),
artist: lookupQuery(Artist), artist: createLookupField(Artist),
event: lookupQuery(Event), event: createLookupField(Event),
instrument: lookupQuery(Instrument), instrument: createLookupField(Instrument),
label: lookupQuery(Label), label: createLookupField(Label),
place: lookupQuery(Place), place: createLookupField(Place),
recording: lookupQuery(Recording), recording: createLookupField(Recording),
release: lookupQuery(Release), release: createLookupField(Release),
releaseGroup: lookupQuery(ReleaseGroup), releaseGroup: createLookupField(ReleaseGroup),
series: lookupQuery(Series), series: createLookupField(Series),
url: lookupQuery(URL), url: createLookupField(URL),
work: lookupQuery(Work) work: createLookupField(Work)
} }
}) })
export const lookupField = { export const lookup = {
type: LookupQuery, type: LookupQuery,
description: 'Perform a lookup of a MusicBrainz entity by its MBID.', description: 'Perform a lookup of a MusicBrainz entity by its MBID.',
// We only have work to do once we know what entity types are being requested, // We only have work to do once we know what entity types are being requested,

View file

@ -1,6 +1,6 @@
import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql' import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql'
import { forwardConnectionArgs } from 'graphql-relay' import { forwardConnectionArgs } from 'graphql-relay'
import { searchResolver } from '../resolvers' import { resolveSearch } from '../resolvers'
import { import {
AreaConnection, AreaConnection,
ArtistConnection, ArtistConnection,
@ -16,7 +16,7 @@ import {
} from '../types' } from '../types'
import { toWords } from '../types/helpers' import { toWords } from '../types/helpers'
function searchQuery (connectionType) { function createSearchField (connectionType) {
const typeName = toWords(connectionType.name.slice(0, -10)) const typeName = toWords(connectionType.name.slice(0, -10))
return { return {
type: connectionType, type: connectionType,
@ -29,7 +29,7 @@ and search fields](https://musicbrainz.org/doc/Development/XML_Web_Service/Versi
}, },
...forwardConnectionArgs ...forwardConnectionArgs
}, },
resolve: searchResolver() resolve: resolveSearch
} }
} }
@ -37,21 +37,21 @@ export const SearchQuery = new GraphQLObjectType({
name: 'SearchQuery', name: 'SearchQuery',
description: 'A search for MusicBrainz entities using Lucene query syntax.', description: 'A search for MusicBrainz entities using Lucene query syntax.',
fields: { fields: {
areas: searchQuery(AreaConnection), areas: createSearchField(AreaConnection),
artists: searchQuery(ArtistConnection), artists: createSearchField(ArtistConnection),
events: searchQuery(EventConnection), events: createSearchField(EventConnection),
instruments: searchQuery(InstrumentConnection), instruments: createSearchField(InstrumentConnection),
labels: searchQuery(LabelConnection), labels: createSearchField(LabelConnection),
places: searchQuery(PlaceConnection), places: createSearchField(PlaceConnection),
recordings: searchQuery(RecordingConnection), recordings: createSearchField(RecordingConnection),
releases: searchQuery(ReleaseConnection), releases: createSearchField(ReleaseConnection),
releaseGroups: searchQuery(ReleaseGroupConnection), releaseGroups: createSearchField(ReleaseGroupConnection),
series: searchQuery(SeriesConnection), series: createSearchField(SeriesConnection),
works: searchQuery(WorkConnection) works: createSearchField(WorkConnection)
} }
}) })
export const searchField = { export const search = {
type: SearchQuery, type: SearchQuery,
description: 'Search for MusicBrainz entities using Lucene query syntax.', description: 'Search for MusicBrainz entities using Lucene query syntax.',
// We only have work to do once we know what entity types are being requested, // We only have work to do once we know what entity types are being requested,

View file

@ -63,111 +63,110 @@ export function includeSubqueries (params, info, fragments = info.fragments) {
return params return params
} }
export function lookupResolver () { export function resolveLookup (root, { mbid }, { loaders }, info) {
return (root, { mbid }, { loaders }, info) => { const entityType = toDashed(info.fieldName)
const entityType = toDashed(info.fieldName) let params = includeSubqueries({}, info)
let params = includeSubqueries({}, info) params = includeRelationships(params, info)
params = includeRelationships(params, info) return loaders.lookup.load([entityType, mbid, params])
return loaders.lookup.load([entityType, mbid, params])
}
} }
export function browseResolver () { export function resolveBrowse (root, {
return (source, { first = 25, after, type = [], status = [], ...args }, { loaders }, info) => { first,
const pluralName = toDashed(info.fieldName) after,
const singularName = toSingular(pluralName) type = [],
let params = { status = [],
...args, ...args
type, }, { loaders }, info) {
status, const pluralName = toDashed(info.fieldName)
limit: first, const singularName = toSingular(pluralName)
offset: getOffsetWithDefault(after, -1) + 1 let params = {
} ...args,
params = includeSubqueries(params, info) type,
params = includeRelationships(params, info, info.fragments) status,
const formatValue = value => value.toLowerCase().replace(/ /g, '') limit: first,
params.type = params.type.map(formatValue) offset: getOffsetWithDefault(after, -1) + 1 || undefined
params.status = params.status.map(formatValue)
return loaders.browse.load([singularName, params]).then(list => {
// Grab the list, offet, and count from the response and use them to build
// a Relay connection object.
const {
[pluralName]: arraySlice,
[`${singularName}-offset`]: sliceStart,
[`${singularName}-count`]: arrayLength
} = list
const meta = { sliceStart, arrayLength }
return {
totalCount: arrayLength,
...connectionFromArraySlice(arraySlice, { first, after }, meta)
}
})
} }
} params = includeSubqueries(params, info)
params = includeRelationships(params, info, info.fragments)
export function searchResolver () { const formatParam = value => value.toLowerCase().replace(/ /g, '')
return (source, { first = 25, after, query, ...args }, { loaders }, info) => { params.type = params.type.map(formatParam)
const pluralName = toDashed(info.fieldName) params.status = params.status.map(formatParam)
const singularName = toSingular(pluralName) return loaders.browse.load([singularName, params]).then(list => {
let params = { // Grab the list, offet, and count from the response and use them to build
...args, // a Relay connection object.
limit: first, const {
offset: getOffsetWithDefault(after, -1) + 1 [pluralName]: arraySlice,
} [`${singularName}-offset`]: sliceStart,
params = includeSubqueries(params, info) [`${singularName}-count`]: arrayLength
return loaders.search.load([singularName, query, params]).then(list => { } = list
const { const meta = { sliceStart, arrayLength }
[pluralName]: arraySlice,
offset: sliceStart,
count: arrayLength
} = list
const meta = { sliceStart, arrayLength }
const connection = {
totalCount: arrayLength,
...connectionFromArraySlice(arraySlice, { first, after }, meta)
}
// Move the `score` field up to the edge object and make sure it's a
// number (MusicBrainz returns a string).
connection.edges.forEach(edge => {
edge.score = parseInt(edge.node.score, 10)
})
return connection
})
}
}
export function relationshipResolver () {
return (source, args, context, info) => {
const targetType = toDashed(toSingular(info.fieldName)).replace('-', '_')
// There's no way to filter these at the API level, so do it here.
const relationships = source.filter(rel => {
if (rel['target-type'] !== targetType) {
return false
}
if (args.direction != null && rel.direction !== args.direction) {
return false
}
if (args.type != null && rel.type !== args.type) {
return false
}
if (args.typeID != null && rel['type-id'] !== args.typeID) {
return false
}
return true
})
return { return {
totalCount: relationships.length, totalCount: arrayLength,
...connectionFromArray(relationships, args) ...connectionFromArraySlice(arraySlice, { first, after }, meta)
} }
})
}
export function resolveSearch (root, {
after,
first,
query,
...args
}, { loaders }, info) {
const pluralName = toDashed(info.fieldName)
const singularName = toSingular(pluralName)
let params = {
...args,
limit: first,
offset: getOffsetWithDefault(after, -1) + 1 || undefined
}
params = includeSubqueries(params, info)
return loaders.search.load([singularName, query, params]).then(list => {
const {
[pluralName]: arraySlice,
offset: sliceStart,
count: arrayLength
} = list
const meta = { sliceStart, arrayLength }
const connection = {
totalCount: arrayLength,
...connectionFromArraySlice(arraySlice, { first, after }, meta)
}
// Move the `score` field up to the edge object and make sure it's a
// number (MusicBrainz returns a string).
connection.edges.forEach(edge => { edge.score = +edge.node.score })
return connection
})
}
export function resolveRelationship (rels, args, context, info) {
const targetType = toDashed(toSingular(info.fieldName)).replace('-', '_')
// There's no way to filter these at the API level, so do it here.
const matches = rels.filter(rel => {
if (rel['target-type'] !== targetType) {
return false
}
if (args.direction != null && rel.direction !== args.direction) {
return false
}
if (args.type != null && rel.type !== args.type) {
return false
}
if (args.typeID != null && rel['type-id'] !== args.typeID) {
return false
}
return true
})
return {
totalCount: matches.length,
...connectionFromArray(matches, args)
} }
} }
export function linkedResolver () { export function resolveLinked (entity, args, context, info) {
return (source, args, context, info) => { const parentEntity = toDashed(info.parentType.name)
const parentEntity = toDashed(info.parentType.name) args = { ...args, [parentEntity]: entity.id }
args = { ...args, [parentEntity]: source.id } return resolveBrowse(entity, args, context, info)
return browseResolver()(source, args, context, info)
}
} }
/** /**
@ -175,17 +174,17 @@ export function linkedResolver () {
* for a particular field that's being requested, make another request to grab * for a particular field that's being requested, make another request to grab
* it (after making sure it isn't already available). * it (after making sure it isn't already available).
*/ */
export function subqueryResolver (includeValue, handler = value => value) { export function createSubqueryResolver (includeValue, handler = value => value) {
return (source, args, { loaders }, info) => { return (entity, args, { loaders }, info) => {
const key = toDashed(info.fieldName) const key = toDashed(info.fieldName)
if (key in source || (source._inc && source._inc.indexOf(key) !== -1)) { let promise
return handler(source[key], args) if (key in entity || (entity._inc && entity._inc.indexOf(key) >= 0)) {
promise = Promise.resolve(entity)
} else { } else {
const { _type: entityType, id } = source const { _type: entityType, id } = entity
const params = { inc: [includeValue || key] } const params = { inc: [includeValue || key] }
return loaders.lookup.load([entityType, id, params]).then(entity => { promise = loaders.lookup.load([entityType, id, params])
return handler(entity[key], args)
})
} }
return promise.then(entity => handler(entity[key], args))
} }
} }

View file

@ -1,5 +1,5 @@
import { GraphQLSchema, GraphQLObjectType } from 'graphql' import { GraphQLSchema, GraphQLObjectType } from 'graphql'
import { lookupField, browseField, searchField } from './queries' import { lookup, browse, search } from './queries'
import { nodeField } from './types/node' import { nodeField } from './types/node'
export default new GraphQLSchema({ export default new GraphQLSchema({
@ -8,10 +8,10 @@ export default new GraphQLSchema({
description: `The query root, from which multiple types of MusicBrainz description: `The query root, from which multiple types of MusicBrainz
requests can be made.`, requests can be made.`,
fields: () => ({ fields: () => ({
node: nodeField, lookup,
lookup: lookupField, browse,
browse: browseField, search,
search: searchField node: nodeField
}) })
}) })
}) })

View file

@ -3,7 +3,7 @@ import Node from './node'
import Entity from './entity' import Entity from './entity'
import Area from './area' import Area from './area'
import { import {
getFallback, resolveWithFallback,
fieldWithID, fieldWithID,
id, id,
mbid, mbid,
@ -50,13 +50,13 @@ is often, but not always, its birth/formation country.`
type: Area, type: Area,
description: `The area in which an artist began their career (or where description: `The area in which an artist began their career (or where
were born, if the artist is a person).`, were born, if the artist is a person).`,
resolve: getFallback(['begin-area', 'begin_area']) resolve: resolveWithFallback(['begin-area', 'begin_area'])
}, },
endArea: { endArea: {
type: Area, type: Area,
description: `The area in which an artist ended their career (or where description: `The area in which an artist ended their career (or where
they died, if the artist is a person).`, they died, if the artist is a person).`,
resolve: getFallback(['end-area', 'end_area']) resolve: resolveWithFallback(['end-area', 'end_area'])
}, },
lifeSpan, lifeSpan,
...fieldWithID('gender', { ...fieldWithID('gender', {

View file

@ -1,7 +1,7 @@
import { GraphQLInterfaceType } from 'graphql' import { GraphQLInterfaceType } from 'graphql'
import { mbid } from './helpers' import { mbid, connectionWithExtras } from './helpers'
export default new GraphQLInterfaceType({ const Entity = new GraphQLInterfaceType({
name: 'Entity', name: 'Entity',
description: 'An entity in the MusicBrainz schema.', description: 'An entity in the MusicBrainz schema.',
resolveType (value) { resolveType (value) {
@ -11,3 +11,6 @@ export default new GraphQLInterfaceType({
}, },
fields: () => ({ mbid }) fields: () => ({ mbid })
}) })
export const EntityConnection = connectionWithExtras(Entity)
export default Entity

View file

@ -30,9 +30,9 @@ import { ReleaseGroupConnection } from './release-group'
import { TagConnection } from './tag' import { TagConnection } from './tag'
import { WorkConnection } from './work' import { WorkConnection } from './work'
import { import {
linkedResolver, resolveLinked,
relationshipResolver, resolveRelationship,
subqueryResolver, createSubqueryResolver,
includeRelationships includeRelationships
} from '../resolvers' } from '../resolvers'
@ -58,7 +58,7 @@ export function toWords (name) {
export function fieldWithID (name, config = {}) { export function fieldWithID (name, config = {}) {
config = { config = {
type: GraphQLString, type: GraphQLString,
resolve: getHyphenated, resolve: resolveHyphenated,
...config ...config
} }
const isPlural = config.type instanceof GraphQLList const isPlural = config.type instanceof GraphQLList
@ -69,7 +69,7 @@ export function fieldWithID (name, config = {}) {
type: isPlural ? new GraphQLList(MBID) : MBID, type: isPlural ? new GraphQLList(MBID) : MBID,
description: `The MBID${s} associated with the value${s} of the \`${name}\` description: `The MBID${s} associated with the value${s} of the \`${name}\`
field.`, field.`,
resolve: getHyphenated resolve: resolveHyphenated
} }
return { return {
[name]: config, [name]: config,
@ -77,17 +77,17 @@ field.`,
} }
} }
export function getHyphenated (source, args, context, info) { export function resolveHyphenated (obj, args, context, info) {
const name = dashify(info.fieldName) const name = dashify(info.fieldName)
return source[name] return obj[name]
} }
export function getFallback (keys) { export function resolveWithFallback (keys) {
return (source) => { return (obj) => {
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const key = keys[i] const key = keys[i]
if (key in source) { if (key in obj) {
return source[key] return obj[key]
} }
} }
} }
@ -97,7 +97,7 @@ export const id = globalIdField()
export const mbid = { export const mbid = {
type: new GraphQLNonNull(MBID), type: new GraphQLNonNull(MBID),
description: 'The MBID of the entity.', description: 'The MBID of the entity.',
resolve: source => source.id resolve: entity => entity.id
} }
export const name = { export const name = {
type: GraphQLString, type: GraphQLString,
@ -108,7 +108,7 @@ export const sortName = {
description: `The string to use for the purpose of ordering by name (for description: `The string to use for the purpose of ordering by name (for
example, by moving articles like the to the end or a persons last name to example, by moving articles like the to the end or a persons last name to
the front).`, the front).`,
resolve: getHyphenated resolve: resolveHyphenated
} }
export const title = { export const title = {
type: GraphQLString, type: GraphQLString,
@ -122,7 +122,7 @@ export const lifeSpan = {
type: LifeSpan, type: LifeSpan,
description: `The begin and end dates of the entitys existence. Its exact description: `The begin and end dates of the entitys existence. Its exact
meaning depends on the type of entity.`, meaning depends on the type of entity.`,
resolve: getHyphenated resolve: resolveHyphenated
} }
function linkedQuery (connectionType, { args, ...config } = {}) { function linkedQuery (connectionType, { args, ...config } = {}) {
@ -134,7 +134,7 @@ function linkedQuery (connectionType, { args, ...config } = {}) {
...forwardConnectionArgs, ...forwardConnectionArgs,
...args ...args
}, },
resolve: linkedResolver(), resolve: resolveLinked,
...config ...config
} }
} }
@ -152,7 +152,7 @@ export const relationship = {
description: 'Filter by the relationship type.' description: 'Filter by the relationship type.'
}) })
}, },
resolve: relationshipResolver() resolve: resolveRelationship
} }
export const relationships = { export const relationships = {
@ -175,16 +175,17 @@ export const relationships = {
}) })
}), }),
description: 'Relationships between this entity and other entitites.', description: 'Relationships between this entity and other entitites.',
resolve: (source, args, { loaders }, info) => { resolve: (entity, args, { loaders }, info) => {
if (source.relations != null) { let promise
return source.relations if (entity.relations != null) {
promise = Promise.resolve(entity)
} else {
const entityType = toDashed(info.parentType.name)
const id = entity.id
const params = includeRelationships({}, info)
promise = loaders.lookup.load([entityType, id, params])
} }
const entityType = toDashed(info.parentType.name) return promise.then(entity => entity.relations)
const id = source.id
const params = includeRelationships({}, info)
return loaders.lookup.load([entityType, id, params]).then(entity => {
return entity.relations
})
} }
} }
@ -192,13 +193,13 @@ export const aliases = {
type: new GraphQLList(Alias), type: new GraphQLList(Alias),
description: `[Aliases](https://musicbrainz.org/doc/Aliases) are used to store description: `[Aliases](https://musicbrainz.org/doc/Aliases) are used to store
alternate names or misspellings.`, alternate names or misspellings.`,
resolve: subqueryResolver() resolve: createSubqueryResolver()
} }
export const artistCredit = { export const artistCredit = {
type: new GraphQLList(ArtistCredit), type: new GraphQLList(ArtistCredit),
description: 'The main credited artist(s).', description: 'The main credited artist(s).',
resolve: subqueryResolver() resolve: createSubqueryResolver()
} }
export const artists = linkedQuery(ArtistConnection) export const artists = linkedQuery(ArtistConnection)
@ -227,7 +228,7 @@ export const releaseGroups = linkedQuery(ReleaseGroupConnection, {
} }
}) })
export const tags = linkedQuery(TagConnection, { export const tags = linkedQuery(TagConnection, {
resolve: subqueryResolver('tags', (value = [], args) => ({ resolve: createSubqueryResolver('tags', (value = [], args) => ({
totalCount: value.length, totalCount: value.length,
...connectionFromArray(value, args) ...connectionFromArray(value, args)
})) }))

View file

@ -1,7 +1,7 @@
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 Node } from './node'
export { default as Entity } from './entity' export { default as Entity, EntityConnection } from './entity'
export { default as Area, AreaConnection } from './area' export { default as Area, AreaConnection } from './area'
export { default as Artist, ArtistConnection } from './artist' export { default as Artist, ArtistConnection } from './artist'
export { default as Event, EventConnection } from './event' export { default as Event, EventConnection } from './event'

View file

@ -8,7 +8,7 @@ import {
import { DateType } from './scalars' import { DateType } from './scalars'
import Entity from './entity' import Entity from './entity'
import { import {
getHyphenated, resolveHyphenated,
fieldWithID, fieldWithID,
connectionWithExtras connectionWithExtras
} from './helpers' } from './helpers'
@ -36,19 +36,19 @@ other and to URLs outside MusicBrainz.`,
targetType: { targetType: {
type: new GraphQLNonNull(GraphQLString), type: new GraphQLNonNull(GraphQLString),
description: 'The type of entity on the receiving end of the relationship.', description: 'The type of entity on the receiving end of the relationship.',
resolve: getHyphenated resolve: resolveHyphenated
}, },
sourceCredit: { sourceCredit: {
type: GraphQLString, type: GraphQLString,
description: `How the source entity was actually credited, if different description: `How the source entity was actually credited, if different
from its main (performance) name.`, from its main (performance) name.`,
resolve: getHyphenated resolve: resolveHyphenated
}, },
targetCredit: { targetCredit: {
type: GraphQLString, type: GraphQLString,
description: `How the target entity was actually credited, if different description: `How the target entity was actually credited, if different
from its main (performance) name.`, from its main (performance) name.`,
resolve: getHyphenated resolve: resolveHyphenated
}, },
begin: { begin: {
type: DateType, type: DateType,

View file

@ -15,7 +15,7 @@ import {
relationships, relationships,
tags, tags,
fieldWithID, fieldWithID,
getHyphenated, resolveHyphenated,
connectionWithExtras connectionWithExtras
} from './helpers' } from './helpers'
@ -40,7 +40,7 @@ album it doesnt matter how many CDs or editions/versions it had.`,
firstReleaseDate: { firstReleaseDate: {
type: DateType, type: DateType,
description: 'The date of the earliest release in the group.', description: 'The date of the earliest release in the group.',
resolve: getHyphenated resolve: resolveHyphenated
}, },
...fieldWithID('primaryType', { ...fieldWithID('primaryType', {
type: ReleaseGroupType, type: ReleaseGroupType,

View file

@ -18,7 +18,7 @@ import {
relationships, relationships,
tags, tags,
fieldWithID, fieldWithID,
getHyphenated, resolveHyphenated,
connectionWithExtras connectionWithExtras
} from './helpers' } from './helpers'
@ -40,7 +40,7 @@ MusicBrainz as one release.`,
releaseEvents: { releaseEvents: {
type: new GraphQLList(ReleaseEvent), type: new GraphQLList(ReleaseEvent),
description: 'The release events for this release.', description: 'The release events for this release.',
resolve: getHyphenated resolve: resolveHyphenated
}, },
date: { date: {
type: DateType, type: DateType,

View file

@ -1733,7 +1733,7 @@ has-color@^0.1.7:
has-flag@^1.0.0: has-flag@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" resolved "http://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
has-unicode@^2.0.0: has-unicode@^2.0.0:
version "2.0.1" version "2.0.1"
@ -1968,7 +1968,7 @@ is-path-inside@^1.0.0:
is-posix-bracket@^0.1.0: is-posix-bracket@^0.1.0:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" resolved "http://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
is-primitive@^2.0.0: is-primitive@^2.0.0:
version "2.0.0" version "2.0.0"
@ -2066,8 +2066,8 @@ json3@3.3.2:
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
json5@^0.5.0: json5@^0.5.0:
version "0.5.0" version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.0.tgz#9b20715b026cbe3778fd769edccd822d8332a5b2" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
jsonify@~0.0.0: jsonify@~0.0.0:
version "0.0.0" version "0.0.0"
@ -2225,8 +2225,8 @@ lowercase-keys@^1.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306"
lru-cache@^4.0.1: lru-cache@^4.0.1:
version "4.0.1" version "4.0.2"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.1.tgz#1343955edaf2e37d9b9e7ee7241e27c4b9fb72be" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e"
dependencies: dependencies:
pseudomap "^1.0.1" pseudomap "^1.0.1"
yallist "^2.0.0" yallist "^2.0.0"
@ -2248,6 +2248,10 @@ markdown-to-ast@~3.2.3:
structured-source "^3.0.2" structured-source "^3.0.2"
traverse "^0.6.6" traverse "^0.6.6"
marked@^0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
media-typer@0.3.0: media-typer@0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -2363,14 +2367,14 @@ nested-error-stacks@^1.0.0:
inherits "~2.0.1" inherits "~2.0.1"
node-pre-gyp@^0.6.29: node-pre-gyp@^0.6.29:
version "0.6.31" version "0.6.32"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.31.tgz#d8a00ddaa301a940615dbcc8caad4024d58f6017" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5"
dependencies: dependencies:
mkdirp "~0.5.1" mkdirp "~0.5.1"
nopt "~3.0.6" nopt "~3.0.6"
npmlog "^4.0.0" npmlog "^4.0.1"
rc "~1.1.6" rc "~1.1.6"
request "^2.75.0" request "^2.79.0"
rimraf "~2.5.4" rimraf "~2.5.4"
semver "~5.3.0" semver "~5.3.0"
tar "~2.2.1" tar "~2.2.1"
@ -2415,7 +2419,7 @@ npm-prefix@^1.0.1:
shellsubstitute "^1.1.0" shellsubstitute "^1.1.0"
untildify "^2.1.0" untildify "^2.1.0"
npmlog@^4.0.0: npmlog@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8"
dependencies: dependencies:
@ -2647,8 +2651,8 @@ qs@^6.3.0, qs@~6.3.0:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442"
randomatic@^1.1.3: randomatic@^1.1.3:
version "1.1.5" version "1.1.6"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
dependencies: dependencies:
is-number "^2.0.2" is-number "^2.0.2"
kind-of "^3.0.2" kind-of "^3.0.2"
@ -2758,7 +2762,7 @@ regenerator-runtime@^0.9.5:
regex-cache@^0.4.2: regex-cache@^0.4.2:
version "0.4.3" version "0.4.3"
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" resolved "http://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145"
dependencies: dependencies:
is-equal-shallow "^0.1.3" is-equal-shallow "^0.1.3"
is-primitive "^2.0.0" is-primitive "^2.0.0"
@ -2844,7 +2848,7 @@ repeating@^2.0.0:
dependencies: dependencies:
is-finite "^1.0.0" is-finite "^1.0.0"
request@^2.75.0, request@^2.79.0: request@^2.79.0:
version "2.79.0" version "2.79.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
dependencies: dependencies:
@ -3365,8 +3369,8 @@ uuid@^2.0.1:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
uuid@^3.0.0: uuid@^3.0.0:
version "3.0.0" version "3.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
v8flags@^2.0.10: v8flags@^2.0.10:
version "2.0.11" version "2.0.11"