graphbrainz/src/types/helpers.js

277 lines
7.9 KiB
JavaScript
Raw Normal View History

2016-08-08 07:54:06 +00:00
import dashify from 'dashify'
2016-08-31 06:33:29 +00:00
import pascalCase from 'pascalcase'
2016-08-20 05:59:32 +00:00
import {
GraphQLObjectType,
GraphQLString,
GraphQLInt,
2016-08-20 05:59:32 +00:00
GraphQLList,
GraphQLNonNull
2016-08-31 06:33:29 +00:00
} from 'graphql'
2016-09-01 08:39:27 +00:00
import {
globalIdField,
connectionArgs,
connectionDefinitions,
connectionFromArray,
2016-09-01 08:39:27 +00:00
forwardConnectionArgs
} from 'graphql-relay'
2016-08-31 06:33:29 +00:00
import { MBID } from './scalars'
2016-08-20 05:59:32 +00:00
import { ReleaseGroupType, ReleaseStatus } from './enums'
import Alias from './alias'
2016-08-20 05:59:32 +00:00
import ArtistCredit from './artist-credit'
import { AreaConnection } from './area'
2016-09-01 08:39:27 +00:00
import { ArtistConnection } from './artist'
import { CollectionConnection } from './collection'
2016-09-01 08:39:27 +00:00
import { EventConnection } from './event'
import { InstrumentConnection } from './instrument'
2016-09-01 08:39:27 +00:00
import { LabelConnection } from './label'
2016-08-20 05:59:32 +00:00
import LifeSpan from './life-span'
2016-09-01 08:39:27 +00:00
import { PlaceConnection } from './place'
import { RecordingConnection } from './recording'
2016-11-26 01:38:32 +00:00
import { RelationshipConnection } from './relationship'
2016-09-01 08:39:27 +00:00
import { ReleaseConnection } from './release'
import { ReleaseGroupConnection } from './release-group'
import { SeriesConnection } from './series'
import { TagConnection } from './tag'
2016-09-01 08:39:27 +00:00
import { WorkConnection } from './work'
2016-08-20 05:59:32 +00:00
import {
resolveLinked,
resolveRelationship,
createSubqueryResolver,
2016-11-26 01:38:32 +00:00
includeRelationships
2016-08-20 05:59:32 +00:00
} from '../resolvers'
2016-11-26 01:38:32 +00:00
export const toPascal = pascalCase
export const toDashed = dashify
export function toPlural (name) {
return name.endsWith('s') ? name : name + 's'
}
export function toSingular (name) {
return name.endsWith('s') && !/series/i.test(name) ? name.slice(0, -1) : name
}
export function toWords (name) {
return toPascal(name).replace(/([^A-Z])?([A-Z]+)/g, (match, tail, head) => {
tail = tail ? tail + ' ' : ''
head = head.length > 1 ? head : head.toLowerCase()
return `${tail}${head}`
})
}
2016-08-31 06:33:29 +00:00
export function resolveHyphenated (obj, args, context, info) {
const name = toDashed(info.fieldName)
return obj[name]
}
export function resolveWithFallback (keys) {
return (obj) => {
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
if (key in obj) {
return obj[key]
}
}
}
}
2016-08-08 07:54:06 +00:00
export function fieldWithID (name, config = {}) {
config = {
type: GraphQLString,
resolve: resolveHyphenated,
2016-08-08 07:54:06 +00:00
...config
}
const isPlural = config.type instanceof GraphQLList
2016-11-26 01:38:32 +00:00
const singularName = isPlural ? toSingular(name) : name
2016-08-08 07:54:06 +00:00
const idName = isPlural ? `${singularName}IDs` : `${name}ID`
2016-11-26 10:37:23 +00:00
const s = isPlural ? 's' : ''
2016-08-08 07:54:06 +00:00
const idConfig = {
type: isPlural ? new GraphQLList(MBID) : MBID,
2016-11-26 10:37:23 +00:00
description: `The MBID${s} associated with the value${s} of the \`${name}\`
field.`,
resolve: resolveHyphenated
2016-08-08 07:54:06 +00:00
}
return {
[name]: config,
[idName]: idConfig
}
}
2016-08-31 06:33:29 +00:00
export const id = globalIdField()
2016-09-01 04:31:48 +00:00
export const mbid = {
type: new GraphQLNonNull(MBID),
2016-09-01 08:39:27 +00:00
description: 'The MBID of the entity.',
resolve: entity => entity.id
2016-09-01 04:31:48 +00:00
}
2016-11-26 01:38:32 +00:00
export const name = {
type: GraphQLString,
description: 'The official name of the entity.'
}
export const sortName = {
type: GraphQLString,
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
the front).`,
resolve: resolveHyphenated
2016-11-26 01:38:32 +00:00
}
export const title = {
type: GraphQLString,
description: 'The official title of the entity.'
}
export const disambiguation = {
type: GraphQLString,
description: 'A comment used to help distinguish identically named entitites.'
}
export const lifeSpan = {
type: LifeSpan,
description: `The begin and end dates of the entitys existence. Its exact
meaning depends on the type of entity.`,
resolve: resolveHyphenated
2016-11-26 01:38:32 +00:00
}
2016-08-20 05:59:32 +00:00
function linkedQuery (connectionType, { args, ...config } = {}) {
const typeName = toPlural(toWords(connectionType.name.slice(0, -10)))
2016-09-01 08:39:27 +00:00
return {
type: connectionType,
description: `A list of ${typeName} linked to this entity.`,
2016-09-01 08:39:27 +00:00
args: {
...args,
...forwardConnectionArgs
2016-09-01 08:39:27 +00:00
},
resolve: resolveLinked,
...config
2016-09-01 08:39:27 +00:00
}
}
2016-11-26 01:38:32 +00:00
export const relationship = {
type: RelationshipConnection,
description: 'A list of relationships between these two entity types.',
2016-08-20 05:59:32 +00:00
args: {
2016-11-26 01:38:32 +00:00
direction: {
type: GraphQLString,
description: 'Filter by the relationship direction.'
},
...fieldWithID('type', {
description: 'Filter by the relationship type.'
}),
...connectionArgs
2016-08-20 05:59:32 +00:00
},
resolve: resolveRelationship
2016-08-20 05:59:32 +00:00
}
2016-11-26 01:38:32 +00:00
export const relationships = {
2016-08-20 05:59:32 +00:00
type: new GraphQLObjectType({
2016-11-26 01:38:32 +00:00
name: 'Relationships',
description: 'Lists of entity relationships for each entity type.',
2016-08-20 05:59:32 +00:00
fields: () => ({
2016-11-26 01:38:32 +00:00
areas: relationship,
artists: relationship,
events: relationship,
instruments: relationship,
labels: relationship,
places: relationship,
recordings: relationship,
releases: relationship,
releaseGroups: relationship,
series: relationship,
urls: relationship,
works: relationship
2016-08-20 05:59:32 +00:00
})
}),
2016-11-26 01:38:32 +00:00
description: 'Relationships between this entity and other entitites.',
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])
2016-08-20 05:59:32 +00:00
}
return promise.then(entity => entity.relations)
2016-08-20 05:59:32 +00:00
}
}
export const aliases = {
type: new GraphQLList(Alias),
description: `[Aliases](https://musicbrainz.org/doc/Aliases) are used to store
alternate names or misspellings.`,
resolve: createSubqueryResolver()
}
export const artistCredits = {
2016-08-20 05:59:32 +00:00
type: new GraphQLList(ArtistCredit),
2016-11-26 01:38:32 +00:00
description: 'The main credited artist(s).',
resolve: createSubqueryResolver({ key: 'artist-credit' })
}
export const artistCredit = {
...artistCredits,
deprecationReason: `The \`artistCredit\` field has been renamed to
\`artistCredits\`, since it is a list of credits and is referred to in the
plural form throughout the MusicBrainz documentation. This field is deprecated
and will be removed in a major release in the future. Use the equivalent
\`artistCredits\` field.`
2016-08-20 05:59:32 +00:00
}
export const releaseGroupType = {
type: new GraphQLList(ReleaseGroupType),
description: 'Filter by one or more release group types.'
}
export const releaseStatus = {
type: new GraphQLList(ReleaseStatus),
description: 'Filter by one or more release statuses.'
}
export const areas = linkedQuery(AreaConnection)
2016-09-01 08:39:27 +00:00
export const artists = linkedQuery(ArtistConnection)
export const collections = linkedQuery(CollectionConnection, {
description: 'A list of collections containing this entity.'
})
2016-09-01 08:39:27 +00:00
export const events = linkedQuery(EventConnection)
export const instruments = linkedQuery(InstrumentConnection)
2016-09-01 08:39:27 +00:00
export const labels = linkedQuery(LabelConnection)
export const places = linkedQuery(PlaceConnection)
export const recordings = linkedQuery(RecordingConnection)
export const releases = linkedQuery(ReleaseConnection, {
args: {
type: releaseGroupType,
status: releaseStatus
}
2016-09-01 08:39:27 +00:00
})
export const releaseGroups = linkedQuery(ReleaseGroupConnection, {
args: {
type: releaseGroupType
}
})
export const series = linkedQuery(SeriesConnection)
export const tags = linkedQuery(TagConnection, {
resolve: createSubqueryResolver({}, (value = [], args) => ({
totalCount: value.length,
...connectionFromArray(value, args)
}))
2016-09-01 08:39:27 +00:00
})
export const works = linkedQuery(WorkConnection)
export const totalCount = {
type: GraphQLInt,
description: `A count of the total number of items in this connection,
ignoring pagination.`
}
2016-11-28 14:43:32 +00:00
export const score = {
type: GraphQLInt,
description: `The relevancy score (0100) assigned by the search engine, if
these results were found through a search.`
}
export function connectionWithExtras (nodeType) {
return connectionDefinitions({
nodeType,
2016-11-28 14:43:32 +00:00
connectionFields: () => ({ totalCount }),
edgeFields: () => ({ score })
}).connectionType
}