mirror of
https://github.com/BradNut/graphbrainz
synced 2025-09-08 17:40:32 +00:00
Internal renames, update dependencies, add Travis config
This commit is contained in:
parent
3dbbf54161
commit
6cb41e1ce0
15 changed files with 240 additions and 217 deletions
16
.travis.yml
Normal file
16
.travis.yml
Normal 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
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { GraphQLObjectType } from 'graphql'
|
||||
import { forwardConnectionArgs } from 'graphql-relay'
|
||||
import { browseResolver } from '../resolvers'
|
||||
import { resolveBrowse } from '../resolvers'
|
||||
import {
|
||||
MBID,
|
||||
URLString,
|
||||
|
|
@ -42,7 +42,7 @@ const releaseGroup = {
|
|||
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))
|
||||
return {
|
||||
type: connectionType,
|
||||
|
|
@ -51,7 +51,7 @@ function browseQuery (connectionType, args) {
|
|||
...forwardConnectionArgs,
|
||||
...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
|
||||
entity.`,
|
||||
fields: {
|
||||
areas: browseQuery(AreaConnection, {
|
||||
areas: createBrowseField(AreaConnection, {
|
||||
collection
|
||||
}),
|
||||
artists: browseQuery(ArtistConnection, {
|
||||
artists: createBrowseField(ArtistConnection, {
|
||||
area,
|
||||
collection,
|
||||
recording,
|
||||
|
|
@ -74,7 +74,7 @@ entity.`,
|
|||
description: 'The MBID of a work to which the artist is linked.'
|
||||
}
|
||||
}),
|
||||
events: browseQuery(EventConnection, {
|
||||
events: createBrowseField(EventConnection, {
|
||||
area,
|
||||
artist,
|
||||
collection,
|
||||
|
|
@ -83,21 +83,21 @@ entity.`,
|
|||
description: 'The MBID of a place to which the event is linked.'
|
||||
}
|
||||
}),
|
||||
labels: browseQuery(LabelConnection, {
|
||||
labels: createBrowseField(LabelConnection, {
|
||||
area,
|
||||
collection,
|
||||
release
|
||||
}),
|
||||
places: browseQuery(PlaceConnection, {
|
||||
places: createBrowseField(PlaceConnection, {
|
||||
area,
|
||||
collection
|
||||
}),
|
||||
recordings: browseQuery(RecordingConnection, {
|
||||
recordings: createBrowseField(RecordingConnection, {
|
||||
artist,
|
||||
collection,
|
||||
release
|
||||
}),
|
||||
releases: browseQuery(ReleaseConnection, {
|
||||
releases: createBrowseField(ReleaseConnection, {
|
||||
area,
|
||||
artist,
|
||||
collection,
|
||||
|
|
@ -117,16 +117,16 @@ release, but is not included in the credits for the release itself.`
|
|||
recording,
|
||||
releaseGroup
|
||||
}),
|
||||
releaseGroups: browseQuery(ReleaseGroupConnection, {
|
||||
releaseGroups: createBrowseField(ReleaseGroupConnection, {
|
||||
artist,
|
||||
collection,
|
||||
release
|
||||
}),
|
||||
works: browseQuery(WorkConnection, {
|
||||
works: createBrowseField(WorkConnection, {
|
||||
artist,
|
||||
collection
|
||||
}),
|
||||
urls: browseQuery(URLConnection, {
|
||||
urls: createBrowseField(URLConnection, {
|
||||
resource: {
|
||||
type: URLString,
|
||||
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,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export { LookupQuery, lookupField } from './lookup'
|
||||
export { BrowseQuery, browseField } from './browse'
|
||||
export { SearchQuery, searchField } from './search'
|
||||
export { LookupQuery, lookup } from './lookup'
|
||||
export { BrowseQuery, browse } from './browse'
|
||||
export { SearchQuery, search } from './search'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { GraphQLObjectType } from 'graphql'
|
||||
import { lookupResolver } from '../resolvers'
|
||||
import { resolveLookup } from '../resolvers'
|
||||
import { mbid, toWords } from '../types/helpers'
|
||||
import {
|
||||
Area,
|
||||
|
|
@ -16,13 +16,13 @@ import {
|
|||
Work
|
||||
} from '../types'
|
||||
|
||||
function lookupQuery (entity) {
|
||||
function createLookupField (entity) {
|
||||
const typeName = toWords(entity.name)
|
||||
return {
|
||||
type: entity,
|
||||
description: `Look up a specific ${typeName} by its MBID.`,
|
||||
args: { mbid },
|
||||
resolve: lookupResolver()
|
||||
resolve: resolveLookup
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,22 +30,22 @@ export const LookupQuery = new GraphQLObjectType({
|
|||
name: 'LookupQuery',
|
||||
description: 'A lookup of an individual MusicBrainz entity by its MBID.',
|
||||
fields: {
|
||||
area: lookupQuery(Area),
|
||||
artist: lookupQuery(Artist),
|
||||
event: lookupQuery(Event),
|
||||
instrument: lookupQuery(Instrument),
|
||||
label: lookupQuery(Label),
|
||||
place: lookupQuery(Place),
|
||||
recording: lookupQuery(Recording),
|
||||
release: lookupQuery(Release),
|
||||
releaseGroup: lookupQuery(ReleaseGroup),
|
||||
series: lookupQuery(Series),
|
||||
url: lookupQuery(URL),
|
||||
work: lookupQuery(Work)
|
||||
area: createLookupField(Area),
|
||||
artist: createLookupField(Artist),
|
||||
event: createLookupField(Event),
|
||||
instrument: createLookupField(Instrument),
|
||||
label: createLookupField(Label),
|
||||
place: createLookupField(Place),
|
||||
recording: createLookupField(Recording),
|
||||
release: createLookupField(Release),
|
||||
releaseGroup: createLookupField(ReleaseGroup),
|
||||
series: createLookupField(Series),
|
||||
url: createLookupField(URL),
|
||||
work: createLookupField(Work)
|
||||
}
|
||||
})
|
||||
|
||||
export const lookupField = {
|
||||
export const lookup = {
|
||||
type: LookupQuery,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql'
|
||||
import { forwardConnectionArgs } from 'graphql-relay'
|
||||
import { searchResolver } from '../resolvers'
|
||||
import { resolveSearch } from '../resolvers'
|
||||
import {
|
||||
AreaConnection,
|
||||
ArtistConnection,
|
||||
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '../types'
|
||||
import { toWords } from '../types/helpers'
|
||||
|
||||
function searchQuery (connectionType) {
|
||||
function createSearchField (connectionType) {
|
||||
const typeName = toWords(connectionType.name.slice(0, -10))
|
||||
return {
|
||||
type: connectionType,
|
||||
|
|
@ -29,7 +29,7 @@ and search fields](https://musicbrainz.org/doc/Development/XML_Web_Service/Versi
|
|||
},
|
||||
...forwardConnectionArgs
|
||||
},
|
||||
resolve: searchResolver()
|
||||
resolve: resolveSearch
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,21 +37,21 @@ export const SearchQuery = new GraphQLObjectType({
|
|||
name: 'SearchQuery',
|
||||
description: 'A search for MusicBrainz entities using Lucene query syntax.',
|
||||
fields: {
|
||||
areas: searchQuery(AreaConnection),
|
||||
artists: searchQuery(ArtistConnection),
|
||||
events: searchQuery(EventConnection),
|
||||
instruments: searchQuery(InstrumentConnection),
|
||||
labels: searchQuery(LabelConnection),
|
||||
places: searchQuery(PlaceConnection),
|
||||
recordings: searchQuery(RecordingConnection),
|
||||
releases: searchQuery(ReleaseConnection),
|
||||
releaseGroups: searchQuery(ReleaseGroupConnection),
|
||||
series: searchQuery(SeriesConnection),
|
||||
works: searchQuery(WorkConnection)
|
||||
areas: createSearchField(AreaConnection),
|
||||
artists: createSearchField(ArtistConnection),
|
||||
events: createSearchField(EventConnection),
|
||||
instruments: createSearchField(InstrumentConnection),
|
||||
labels: createSearchField(LabelConnection),
|
||||
places: createSearchField(PlaceConnection),
|
||||
recordings: createSearchField(RecordingConnection),
|
||||
releases: createSearchField(ReleaseConnection),
|
||||
releaseGroups: createSearchField(ReleaseGroupConnection),
|
||||
series: createSearchField(SeriesConnection),
|
||||
works: createSearchField(WorkConnection)
|
||||
}
|
||||
})
|
||||
|
||||
export const searchField = {
|
||||
export const search = {
|
||||
type: SearchQuery,
|
||||
description: 'Search for MusicBrainz entities using Lucene query syntax.',
|
||||
// We only have work to do once we know what entity types are being requested,
|
||||
|
|
|
|||
209
src/resolvers.js
209
src/resolvers.js
|
|
@ -63,111 +63,110 @@ export function includeSubqueries (params, info, fragments = info.fragments) {
|
|||
return params
|
||||
}
|
||||
|
||||
export function lookupResolver () {
|
||||
return (root, { mbid }, { loaders }, info) => {
|
||||
const entityType = toDashed(info.fieldName)
|
||||
let params = includeSubqueries({}, info)
|
||||
params = includeRelationships(params, info)
|
||||
return loaders.lookup.load([entityType, mbid, params])
|
||||
}
|
||||
export function resolveLookup (root, { mbid }, { loaders }, info) {
|
||||
const entityType = toDashed(info.fieldName)
|
||||
let params = includeSubqueries({}, info)
|
||||
params = includeRelationships(params, info)
|
||||
return loaders.lookup.load([entityType, mbid, params])
|
||||
}
|
||||
|
||||
export function browseResolver () {
|
||||
return (source, { first = 25, after, type = [], status = [], ...args }, { loaders }, info) => {
|
||||
const pluralName = toDashed(info.fieldName)
|
||||
const singularName = toSingular(pluralName)
|
||||
let params = {
|
||||
...args,
|
||||
type,
|
||||
status,
|
||||
limit: first,
|
||||
offset: getOffsetWithDefault(after, -1) + 1
|
||||
}
|
||||
params = includeSubqueries(params, info)
|
||||
params = includeRelationships(params, info, info.fragments)
|
||||
const formatValue = value => value.toLowerCase().replace(/ /g, '')
|
||||
params.type = params.type.map(formatValue)
|
||||
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)
|
||||
}
|
||||
})
|
||||
export function resolveBrowse (root, {
|
||||
first,
|
||||
after,
|
||||
type = [],
|
||||
status = [],
|
||||
...args
|
||||
}, { loaders }, info) {
|
||||
const pluralName = toDashed(info.fieldName)
|
||||
const singularName = toSingular(pluralName)
|
||||
let params = {
|
||||
...args,
|
||||
type,
|
||||
status,
|
||||
limit: first,
|
||||
offset: getOffsetWithDefault(after, -1) + 1 || undefined
|
||||
}
|
||||
}
|
||||
|
||||
export function searchResolver () {
|
||||
return (source, { first = 25, after, query, ...args }, { loaders }, info) => {
|
||||
const pluralName = toDashed(info.fieldName)
|
||||
const singularName = toSingular(pluralName)
|
||||
let params = {
|
||||
...args,
|
||||
limit: first,
|
||||
offset: getOffsetWithDefault(after, -1) + 1
|
||||
}
|
||||
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 = 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
|
||||
})
|
||||
params = includeSubqueries(params, info)
|
||||
params = includeRelationships(params, info, info.fragments)
|
||||
const formatParam = value => value.toLowerCase().replace(/ /g, '')
|
||||
params.type = params.type.map(formatParam)
|
||||
params.status = params.status.map(formatParam)
|
||||
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: relationships.length,
|
||||
...connectionFromArray(relationships, args)
|
||||
totalCount: arrayLength,
|
||||
...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 () {
|
||||
return (source, args, context, info) => {
|
||||
const parentEntity = toDashed(info.parentType.name)
|
||||
args = { ...args, [parentEntity]: source.id }
|
||||
return browseResolver()(source, args, context, info)
|
||||
}
|
||||
export function resolveLinked (entity, args, context, info) {
|
||||
const parentEntity = toDashed(info.parentType.name)
|
||||
args = { ...args, [parentEntity]: entity.id }
|
||||
return resolveBrowse(entity, args, context, info)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -175,17 +174,17 @@ export function linkedResolver () {
|
|||
* for a particular field that's being requested, make another request to grab
|
||||
* it (after making sure it isn't already available).
|
||||
*/
|
||||
export function subqueryResolver (includeValue, handler = value => value) {
|
||||
return (source, args, { loaders }, info) => {
|
||||
export function createSubqueryResolver (includeValue, handler = value => value) {
|
||||
return (entity, args, { loaders }, info) => {
|
||||
const key = toDashed(info.fieldName)
|
||||
if (key in source || (source._inc && source._inc.indexOf(key) !== -1)) {
|
||||
return handler(source[key], args)
|
||||
let promise
|
||||
if (key in entity || (entity._inc && entity._inc.indexOf(key) >= 0)) {
|
||||
promise = Promise.resolve(entity)
|
||||
} else {
|
||||
const { _type: entityType, id } = source
|
||||
const { _type: entityType, id } = entity
|
||||
const params = { inc: [includeValue || key] }
|
||||
return loaders.lookup.load([entityType, id, params]).then(entity => {
|
||||
return handler(entity[key], args)
|
||||
})
|
||||
promise = loaders.lookup.load([entityType, id, params])
|
||||
}
|
||||
return promise.then(entity => handler(entity[key], args))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { GraphQLSchema, GraphQLObjectType } from 'graphql'
|
||||
import { lookupField, browseField, searchField } from './queries'
|
||||
import { lookup, browse, search } from './queries'
|
||||
import { nodeField } from './types/node'
|
||||
|
||||
export default new GraphQLSchema({
|
||||
|
|
@ -8,10 +8,10 @@ export default new GraphQLSchema({
|
|||
description: `The query root, from which multiple types of MusicBrainz
|
||||
requests can be made.`,
|
||||
fields: () => ({
|
||||
node: nodeField,
|
||||
lookup: lookupField,
|
||||
browse: browseField,
|
||||
search: searchField
|
||||
lookup,
|
||||
browse,
|
||||
search,
|
||||
node: nodeField
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import Node from './node'
|
|||
import Entity from './entity'
|
||||
import Area from './area'
|
||||
import {
|
||||
getFallback,
|
||||
resolveWithFallback,
|
||||
fieldWithID,
|
||||
id,
|
||||
mbid,
|
||||
|
|
@ -50,13 +50,13 @@ is often, but not always, its birth/formation country.`
|
|||
type: Area,
|
||||
description: `The area in which an artist began their career (or where
|
||||
were born, if the artist is a person).`,
|
||||
resolve: getFallback(['begin-area', 'begin_area'])
|
||||
resolve: resolveWithFallback(['begin-area', 'begin_area'])
|
||||
},
|
||||
endArea: {
|
||||
type: Area,
|
||||
description: `The area in which an artist ended their career (or where
|
||||
they died, if the artist is a person).`,
|
||||
resolve: getFallback(['end-area', 'end_area'])
|
||||
resolve: resolveWithFallback(['end-area', 'end_area'])
|
||||
},
|
||||
lifeSpan,
|
||||
...fieldWithID('gender', {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { GraphQLInterfaceType } from 'graphql'
|
||||
import { mbid } from './helpers'
|
||||
import { mbid, connectionWithExtras } from './helpers'
|
||||
|
||||
export default new GraphQLInterfaceType({
|
||||
const Entity = new GraphQLInterfaceType({
|
||||
name: 'Entity',
|
||||
description: 'An entity in the MusicBrainz schema.',
|
||||
resolveType (value) {
|
||||
|
|
@ -11,3 +11,6 @@ export default new GraphQLInterfaceType({
|
|||
},
|
||||
fields: () => ({ mbid })
|
||||
})
|
||||
|
||||
export const EntityConnection = connectionWithExtras(Entity)
|
||||
export default Entity
|
||||
|
|
|
|||
|
|
@ -30,9 +30,9 @@ import { ReleaseGroupConnection } from './release-group'
|
|||
import { TagConnection } from './tag'
|
||||
import { WorkConnection } from './work'
|
||||
import {
|
||||
linkedResolver,
|
||||
relationshipResolver,
|
||||
subqueryResolver,
|
||||
resolveLinked,
|
||||
resolveRelationship,
|
||||
createSubqueryResolver,
|
||||
includeRelationships
|
||||
} from '../resolvers'
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ export function toWords (name) {
|
|||
export function fieldWithID (name, config = {}) {
|
||||
config = {
|
||||
type: GraphQLString,
|
||||
resolve: getHyphenated,
|
||||
resolve: resolveHyphenated,
|
||||
...config
|
||||
}
|
||||
const isPlural = config.type instanceof GraphQLList
|
||||
|
|
@ -69,7 +69,7 @@ export function fieldWithID (name, config = {}) {
|
|||
type: isPlural ? new GraphQLList(MBID) : MBID,
|
||||
description: `The MBID${s} associated with the value${s} of the \`${name}\`
|
||||
field.`,
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
}
|
||||
return {
|
||||
[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)
|
||||
return source[name]
|
||||
return obj[name]
|
||||
}
|
||||
|
||||
export function getFallback (keys) {
|
||||
return (source) => {
|
||||
export function resolveWithFallback (keys) {
|
||||
return (obj) => {
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i]
|
||||
if (key in source) {
|
||||
return source[key]
|
||||
if (key in obj) {
|
||||
return obj[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ export const id = globalIdField()
|
|||
export const mbid = {
|
||||
type: new GraphQLNonNull(MBID),
|
||||
description: 'The MBID of the entity.',
|
||||
resolve: source => source.id
|
||||
resolve: entity => entity.id
|
||||
}
|
||||
export const name = {
|
||||
type: GraphQLString,
|
||||
|
|
@ -108,7 +108,7 @@ export const sortName = {
|
|||
description: `The string to use for the purpose of ordering by name (for
|
||||
example, by moving articles like ‘the’ to the end or a person’s last name to
|
||||
the front).`,
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
}
|
||||
export const title = {
|
||||
type: GraphQLString,
|
||||
|
|
@ -122,7 +122,7 @@ export const lifeSpan = {
|
|||
type: LifeSpan,
|
||||
description: `The begin and end dates of the entity’s existence. Its exact
|
||||
meaning depends on the type of entity.`,
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
}
|
||||
|
||||
function linkedQuery (connectionType, { args, ...config } = {}) {
|
||||
|
|
@ -134,7 +134,7 @@ function linkedQuery (connectionType, { args, ...config } = {}) {
|
|||
...forwardConnectionArgs,
|
||||
...args
|
||||
},
|
||||
resolve: linkedResolver(),
|
||||
resolve: resolveLinked,
|
||||
...config
|
||||
}
|
||||
}
|
||||
|
|
@ -152,7 +152,7 @@ export const relationship = {
|
|||
description: 'Filter by the relationship type.'
|
||||
})
|
||||
},
|
||||
resolve: relationshipResolver()
|
||||
resolve: resolveRelationship
|
||||
}
|
||||
|
||||
export const relationships = {
|
||||
|
|
@ -175,16 +175,17 @@ export const relationships = {
|
|||
})
|
||||
}),
|
||||
description: 'Relationships between this entity and other entitites.',
|
||||
resolve: (source, args, { loaders }, info) => {
|
||||
if (source.relations != null) {
|
||||
return source.relations
|
||||
resolve: (entity, args, { loaders }, info) => {
|
||||
let promise
|
||||
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)
|
||||
const id = source.id
|
||||
const params = includeRelationships({}, info)
|
||||
return loaders.lookup.load([entityType, id, params]).then(entity => {
|
||||
return entity.relations
|
||||
})
|
||||
return promise.then(entity => entity.relations)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,13 +193,13 @@ export const aliases = {
|
|||
type: new GraphQLList(Alias),
|
||||
description: `[Aliases](https://musicbrainz.org/doc/Aliases) are used to store
|
||||
alternate names or misspellings.`,
|
||||
resolve: subqueryResolver()
|
||||
resolve: createSubqueryResolver()
|
||||
}
|
||||
|
||||
export const artistCredit = {
|
||||
type: new GraphQLList(ArtistCredit),
|
||||
description: 'The main credited artist(s).',
|
||||
resolve: subqueryResolver()
|
||||
resolve: createSubqueryResolver()
|
||||
}
|
||||
|
||||
export const artists = linkedQuery(ArtistConnection)
|
||||
|
|
@ -227,7 +228,7 @@ export const releaseGroups = linkedQuery(ReleaseGroupConnection, {
|
|||
}
|
||||
})
|
||||
export const tags = linkedQuery(TagConnection, {
|
||||
resolve: subqueryResolver('tags', (value = [], args) => ({
|
||||
resolve: createSubqueryResolver('tags', (value = [], args) => ({
|
||||
totalCount: value.length,
|
||||
...connectionFromArray(value, args)
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export { MBID, DateType, IPI, URLString } from './scalars'
|
||||
export { ReleaseGroupType, ReleaseStatus } from './enums'
|
||||
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 Artist, ArtistConnection } from './artist'
|
||||
export { default as Event, EventConnection } from './event'
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
import { DateType } from './scalars'
|
||||
import Entity from './entity'
|
||||
import {
|
||||
getHyphenated,
|
||||
resolveHyphenated,
|
||||
fieldWithID,
|
||||
connectionWithExtras
|
||||
} from './helpers'
|
||||
|
|
@ -36,19 +36,19 @@ other and to URLs outside MusicBrainz.`,
|
|||
targetType: {
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
description: 'The type of entity on the receiving end of the relationship.',
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
},
|
||||
sourceCredit: {
|
||||
type: GraphQLString,
|
||||
description: `How the source entity was actually credited, if different
|
||||
from its main (performance) name.`,
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
},
|
||||
targetCredit: {
|
||||
type: GraphQLString,
|
||||
description: `How the target entity was actually credited, if different
|
||||
from its main (performance) name.`,
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
},
|
||||
begin: {
|
||||
type: DateType,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import {
|
|||
relationships,
|
||||
tags,
|
||||
fieldWithID,
|
||||
getHyphenated,
|
||||
resolveHyphenated,
|
||||
connectionWithExtras
|
||||
} from './helpers'
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ album – it doesn’t matter how many CDs or editions/versions it had.`,
|
|||
firstReleaseDate: {
|
||||
type: DateType,
|
||||
description: 'The date of the earliest release in the group.',
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
},
|
||||
...fieldWithID('primaryType', {
|
||||
type: ReleaseGroupType,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
relationships,
|
||||
tags,
|
||||
fieldWithID,
|
||||
getHyphenated,
|
||||
resolveHyphenated,
|
||||
connectionWithExtras
|
||||
} from './helpers'
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ MusicBrainz as one release.`,
|
|||
releaseEvents: {
|
||||
type: new GraphQLList(ReleaseEvent),
|
||||
description: 'The release events for this release.',
|
||||
resolve: getHyphenated
|
||||
resolve: resolveHyphenated
|
||||
},
|
||||
date: {
|
||||
type: DateType,
|
||||
|
|
|
|||
38
yarn.lock
38
yarn.lock
|
|
@ -1733,7 +1733,7 @@ has-color@^0.1.7:
|
|||
|
||||
has-flag@^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:
|
||||
version "2.0.1"
|
||||
|
|
@ -1968,7 +1968,7 @@ is-path-inside@^1.0.0:
|
|||
|
||||
is-posix-bracket@^0.1.0:
|
||||
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:
|
||||
version "2.0.0"
|
||||
|
|
@ -2066,8 +2066,8 @@ json3@3.3.2:
|
|||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
|
||||
|
||||
json5@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.0.tgz#9b20715b026cbe3778fd769edccd822d8332a5b2"
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
|
||||
|
||||
jsonify@~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"
|
||||
|
||||
lru-cache@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.1.tgz#1343955edaf2e37d9b9e7ee7241e27c4b9fb72be"
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e"
|
||||
dependencies:
|
||||
pseudomap "^1.0.1"
|
||||
yallist "^2.0.0"
|
||||
|
|
@ -2248,6 +2248,10 @@ markdown-to-ast@~3.2.3:
|
|||
structured-source "^3.0.2"
|
||||
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:
|
||||
version "0.3.0"
|
||||
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"
|
||||
|
||||
node-pre-gyp@^0.6.29:
|
||||
version "0.6.31"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.31.tgz#d8a00ddaa301a940615dbcc8caad4024d58f6017"
|
||||
version "0.6.32"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5"
|
||||
dependencies:
|
||||
mkdirp "~0.5.1"
|
||||
nopt "~3.0.6"
|
||||
npmlog "^4.0.0"
|
||||
npmlog "^4.0.1"
|
||||
rc "~1.1.6"
|
||||
request "^2.75.0"
|
||||
request "^2.79.0"
|
||||
rimraf "~2.5.4"
|
||||
semver "~5.3.0"
|
||||
tar "~2.2.1"
|
||||
|
|
@ -2415,7 +2419,7 @@ npm-prefix@^1.0.1:
|
|||
shellsubstitute "^1.1.0"
|
||||
untildify "^2.1.0"
|
||||
|
||||
npmlog@^4.0.0:
|
||||
npmlog@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.1.tgz#d14f503b4cd79710375553004ba96e6662fbc0b8"
|
||||
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"
|
||||
|
||||
randomatic@^1.1.3:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.5.tgz#5e9ef5f2d573c67bd2b8124ae90b5156e457840b"
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb"
|
||||
dependencies:
|
||||
is-number "^2.0.2"
|
||||
kind-of "^3.0.2"
|
||||
|
|
@ -2758,7 +2762,7 @@ regenerator-runtime@^0.9.5:
|
|||
|
||||
regex-cache@^0.4.2:
|
||||
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:
|
||||
is-equal-shallow "^0.1.3"
|
||||
is-primitive "^2.0.0"
|
||||
|
|
@ -2844,7 +2848,7 @@ repeating@^2.0.0:
|
|||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
request@^2.75.0, request@^2.79.0:
|
||||
request@^2.79.0:
|
||||
version "2.79.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
|
||||
dependencies:
|
||||
|
|
@ -3365,8 +3369,8 @@ uuid@^2.0.1:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
|
||||
|
||||
uuid@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.0.tgz#6728fc0459c450d796a99c31837569bdf672d728"
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1"
|
||||
|
||||
v8flags@^2.0.10:
|
||||
version "2.0.11"
|
||||
|
|
|
|||
Loading…
Reference in a new issue