mirror of
https://github.com/BradNut/graphbrainz
synced 2025-09-08 17:40:32 +00:00
wip
This commit is contained in:
parent
ed5339f2e1
commit
116775eaca
5 changed files with 180 additions and 270 deletions
|
|
@ -1,4 +1,6 @@
|
|||
import { GraphQLObjectType, GraphQLInt } from 'graphql'
|
||||
import { GraphQLObjectType } from 'graphql'
|
||||
import { forwardConnectionArgs } from 'graphql-relay'
|
||||
import { browseResolver } from '../resolvers'
|
||||
import {
|
||||
MBID,
|
||||
URLString,
|
||||
|
|
@ -12,7 +14,17 @@ import {
|
|||
URLConnection,
|
||||
WorkConnection
|
||||
} from '../types'
|
||||
import { browseResolver } from '../resolvers'
|
||||
|
||||
function browseQuery (connectionType, args) {
|
||||
return {
|
||||
type: connectionType,
|
||||
args: {
|
||||
...forwardConnectionArgs,
|
||||
...args
|
||||
},
|
||||
resolve: browseResolver()
|
||||
}
|
||||
}
|
||||
|
||||
export default new GraphQLObjectType({
|
||||
name: 'BrowseQuery',
|
||||
|
|
@ -20,101 +32,47 @@ export default new GraphQLObjectType({
|
|||
'Browse requests are a direct lookup of all the entities directly linked ' +
|
||||
'to another entity.',
|
||||
fields: {
|
||||
artists: {
|
||||
type: ArtistConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
area: { type: MBID },
|
||||
recording: { type: MBID },
|
||||
release: { type: MBID },
|
||||
releaseGroup: { type: MBID },
|
||||
work: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
events: {
|
||||
type: EventConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
area: { type: MBID },
|
||||
artist: { type: MBID },
|
||||
place: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
labels: {
|
||||
type: LabelConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
area: { type: MBID },
|
||||
release: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
places: {
|
||||
type: PlaceConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
area: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
recordings: {
|
||||
type: RecordingConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
artist: { type: MBID },
|
||||
release: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
releases: {
|
||||
type: ReleaseConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
area: { type: MBID },
|
||||
artist: { type: MBID },
|
||||
label: { type: MBID },
|
||||
track: { type: MBID },
|
||||
trackArtist: { type: MBID },
|
||||
recording: { type: MBID },
|
||||
releaseGroup: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
releaseGroups: {
|
||||
type: ReleaseGroupConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
artist: { type: MBID },
|
||||
release: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
works: {
|
||||
type: WorkConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
artist: { type: MBID }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
},
|
||||
urls: {
|
||||
type: URLConnection,
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
resource: { type: URLString }
|
||||
},
|
||||
resolve: browseResolver()
|
||||
}
|
||||
artists: browseQuery(ArtistConnection, {
|
||||
area: { type: MBID },
|
||||
recording: { type: MBID },
|
||||
release: { type: MBID },
|
||||
releaseGroup: { type: MBID },
|
||||
work: { type: MBID }
|
||||
}),
|
||||
events: browseQuery(EventConnection, {
|
||||
area: { type: MBID },
|
||||
artist: { type: MBID },
|
||||
place: { type: MBID }
|
||||
}),
|
||||
labels: browseQuery(LabelConnection, {
|
||||
area: { type: MBID },
|
||||
release: { type: MBID }
|
||||
}),
|
||||
places: browseQuery(PlaceConnection, {
|
||||
area: { type: MBID }
|
||||
}),
|
||||
recordings: browseQuery(RecordingConnection, {
|
||||
artist: { type: MBID },
|
||||
release: { type: MBID }
|
||||
}),
|
||||
releases: browseQuery(ReleaseConnection, {
|
||||
area: { type: MBID },
|
||||
artist: { type: MBID },
|
||||
label: { type: MBID },
|
||||
track: { type: MBID },
|
||||
trackArtist: { type: MBID },
|
||||
recording: { type: MBID },
|
||||
releaseGroup: { type: MBID }
|
||||
}),
|
||||
releaseGroups: browseQuery(ReleaseGroupConnection, {
|
||||
artist: { type: MBID },
|
||||
release: { type: MBID }
|
||||
}),
|
||||
works: browseQuery(WorkConnection, {
|
||||
artist: { type: MBID }
|
||||
}),
|
||||
urls: browseQuery(URLConnection, {
|
||||
resource: { type: URLString }
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { GraphQLObjectType } from 'graphql'
|
||||
import { lookupResolver } from '../resolvers'
|
||||
import { mbid } from '../types/helpers'
|
||||
import {
|
||||
Area,
|
||||
Artist,
|
||||
|
|
@ -9,10 +11,19 @@ import {
|
|||
Recording,
|
||||
Release,
|
||||
ReleaseGroup,
|
||||
Series,
|
||||
URL,
|
||||
Work
|
||||
} from '../types'
|
||||
import { lookupQuery } from '../types/helpers'
|
||||
|
||||
function lookupQuery (entity) {
|
||||
return {
|
||||
type: entity,
|
||||
description: `Look up a specific ${entity.name} by its MBID.`,
|
||||
args: { mbid },
|
||||
resolve: lookupResolver()
|
||||
}
|
||||
}
|
||||
|
||||
export default new GraphQLObjectType({
|
||||
name: 'LookupQuery',
|
||||
|
|
@ -29,6 +40,7 @@ export default new GraphQLObjectType({
|
|||
recording: lookupQuery(Recording),
|
||||
release: lookupQuery(Release),
|
||||
releaseGroup: lookupQuery(ReleaseGroup),
|
||||
series: lookupQuery(Series),
|
||||
url: lookupQuery(URL),
|
||||
work: lookupQuery(Work)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { GraphQLObjectType } from 'graphql'
|
||||
import { GraphQLObjectType, GraphQLNonNull, GraphQLString } from 'graphql'
|
||||
import { forwardConnectionArgs } from 'graphql-relay'
|
||||
import { searchResolver } from '../resolvers'
|
||||
import {
|
||||
AreaConnection,
|
||||
ArtistConnection,
|
||||
|
|
@ -9,7 +11,17 @@ import {
|
|||
ReleaseGroupConnection,
|
||||
WorkConnection
|
||||
} from '../types'
|
||||
import { searchQuery } from '../types/helpers'
|
||||
|
||||
function searchQuery (connectionType) {
|
||||
return {
|
||||
type: connectionType,
|
||||
args: {
|
||||
query: { type: new GraphQLNonNull(GraphQLString) },
|
||||
...forwardConnectionArgs
|
||||
},
|
||||
resolve: searchResolver()
|
||||
}
|
||||
}
|
||||
|
||||
export default new GraphQLObjectType({
|
||||
name: 'SearchQuery',
|
||||
|
|
|
|||
105
src/resolvers.js
105
src/resolvers.js
|
|
@ -1,5 +1,9 @@
|
|||
import { toEntityType } from './types/helpers'
|
||||
import { getOffsetWithDefault, connectionFromArraySlice } from 'graphql-relay'
|
||||
import {
|
||||
getOffsetWithDefault,
|
||||
connectionFromArray,
|
||||
connectionFromArraySlice
|
||||
} from 'graphql-relay'
|
||||
import { getFields, extendIncludes } from './util'
|
||||
|
||||
export function includeRelations (params, info) {
|
||||
|
|
@ -35,34 +39,63 @@ export function includeSubqueries (params, info) {
|
|||
return params
|
||||
}
|
||||
|
||||
export function lookupResolver (entityType, extraParams = {}) {
|
||||
return (root, { id }, { lookupLoader }, info) => {
|
||||
const params = includeRelations(extraParams, info)
|
||||
entityType = entityType || toEntityType(info.fieldName)
|
||||
return lookupLoader.load([entityType, id, params])
|
||||
export function lookupResolver () {
|
||||
return (root, { mbid }, { lookupLoader }, info) => {
|
||||
const entityType = toEntityType(info.fieldName)
|
||||
const params = includeRelations({}, info)
|
||||
return lookupLoader.load([entityType, mbid, params])
|
||||
}
|
||||
}
|
||||
|
||||
export function browseResolver () {
|
||||
return (source, args, { browseLoader }, info) => {
|
||||
return (source, { first = 25, after, ...args }, { browseLoader }, info) => {
|
||||
const pluralName = toEntityType(info.fieldName)
|
||||
let singularName = pluralName
|
||||
if (pluralName.endsWith('s')) {
|
||||
singularName = pluralName.slice(0, -1)
|
||||
}
|
||||
const params = args
|
||||
return browseLoader.load([singularName, params])
|
||||
const { type, types, status, statuses, ...moreParams } = args
|
||||
let params = {
|
||||
...moreParams,
|
||||
type: [],
|
||||
status: [],
|
||||
limit: first,
|
||||
offset: getOffsetWithDefault(after, 0)
|
||||
}
|
||||
params = includeSubqueries(params, info)
|
||||
params = includeRelations(params, info)
|
||||
if (type) {
|
||||
params.type.push(type)
|
||||
}
|
||||
if (types) {
|
||||
params.type.push(...types)
|
||||
}
|
||||
if (status) {
|
||||
params.status.push(status)
|
||||
}
|
||||
if (statuses) {
|
||||
params.status.push(...statuses)
|
||||
}
|
||||
return browseLoader.load([singularName, params]).then(list => {
|
||||
const {
|
||||
[pluralName]: arraySlice,
|
||||
[`${singularName}-offset`]: sliceStart,
|
||||
[`${singularName}-count`]: arrayLength
|
||||
} = list
|
||||
const meta = { sliceStart, arrayLength }
|
||||
return connectionFromArraySlice(arraySlice, { first, after }, meta)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function searchResolver () {
|
||||
return (source, args, { searchLoader }, info) => {
|
||||
return (source, { first = 25, after, ...args }, { searchLoader }, info) => {
|
||||
const pluralName = toEntityType(info.fieldName)
|
||||
let singularName = pluralName
|
||||
if (pluralName.endsWith('s')) {
|
||||
singularName = pluralName.slice(0, -1)
|
||||
}
|
||||
const { query, first, after, ...params } = args
|
||||
const { query, ...params } = args
|
||||
params.limit = first
|
||||
params.offset = getOffsetWithDefault(after, 0)
|
||||
return searchLoader.load([singularName, query, params]).then(list => {
|
||||
|
|
@ -78,61 +111,31 @@ export function searchResolver () {
|
|||
}
|
||||
|
||||
export function relationResolver () {
|
||||
return (source, { offset = 0,
|
||||
limit,
|
||||
direction,
|
||||
type,
|
||||
typeID }, { lookupLoader }, info) => {
|
||||
return (source, args, context, info) => {
|
||||
const targetType = toEntityType(info.fieldName).replace('-', '_')
|
||||
return source.filter(relation => {
|
||||
const relations = source.filter(relation => {
|
||||
if (relation['target-type'] !== targetType) {
|
||||
return false
|
||||
}
|
||||
if (direction != null && relation.direction !== direction) {
|
||||
if (args.direction != null && relation.direction !== args.direction) {
|
||||
return false
|
||||
}
|
||||
if (type != null && relation.type !== type) {
|
||||
if (args.type != null && relation.type !== args.type) {
|
||||
return false
|
||||
}
|
||||
if (typeID != null && relation['type-id'] !== typeID) {
|
||||
if (args.typeID != null && relation['type-id'] !== args.typeID) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}).slice(offset, limit == null ? undefined : offset + limit)
|
||||
})
|
||||
return connectionFromArray(relations, args)
|
||||
}
|
||||
}
|
||||
|
||||
export function linkedResolver () {
|
||||
return (source, args, { browseLoader }, info) => {
|
||||
const pluralName = toEntityType(info.fieldName)
|
||||
let singularName = pluralName
|
||||
if (pluralName.endsWith('s')) {
|
||||
singularName = pluralName.slice(0, -1)
|
||||
}
|
||||
return (source, args, context, info) => {
|
||||
const parentEntity = toEntityType(info.parentType.name)
|
||||
let params = {
|
||||
[parentEntity]: source.id,
|
||||
type: [],
|
||||
status: [],
|
||||
limit: args.limit,
|
||||
offset: args.offset
|
||||
}
|
||||
params = includeSubqueries(params, info)
|
||||
params = includeRelations(params, info)
|
||||
if (args.type) {
|
||||
params.type.push(args.type)
|
||||
}
|
||||
if (args.types) {
|
||||
params.type.push(...args.types)
|
||||
}
|
||||
if (args.status) {
|
||||
params.status.push(args.status)
|
||||
}
|
||||
if (args.statuses) {
|
||||
params.status.push(...args.statuses)
|
||||
}
|
||||
return browseLoader.load([singularName, params]).then(list => {
|
||||
return list[pluralName]
|
||||
})
|
||||
args = { ...args, [parentEntity]: source.id }
|
||||
return browseResolver()(source, args, context, info)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,44 +3,36 @@ import pascalCase from 'pascalcase'
|
|||
import {
|
||||
GraphQLObjectType,
|
||||
GraphQLString,
|
||||
GraphQLInt,
|
||||
GraphQLList,
|
||||
GraphQLNonNull
|
||||
} from 'graphql'
|
||||
import { globalIdField, forwardConnectionArgs } from 'graphql-relay'
|
||||
import {
|
||||
globalIdField,
|
||||
connectionArgs,
|
||||
forwardConnectionArgs
|
||||
} from 'graphql-relay'
|
||||
import { MBID } from './scalars'
|
||||
import { ReleaseGroupType, ReleaseStatus } from './enums'
|
||||
import ArtistCredit from './artist-credit'
|
||||
import Artist from './artist'
|
||||
import Event from './event'
|
||||
import Label from './label'
|
||||
import { ArtistConnection } from './artist'
|
||||
import { EventConnection } from './event'
|
||||
import { LabelConnection } from './label'
|
||||
import LifeSpan from './life-span'
|
||||
import Place from './place'
|
||||
import Recording from './recording'
|
||||
import { PlaceConnection } from './place'
|
||||
import { RecordingConnection } from './recording'
|
||||
import Relation from './relation'
|
||||
import Release from './release'
|
||||
import ReleaseGroup from './release-group'
|
||||
import Work from './work'
|
||||
import { ReleaseConnection } from './release'
|
||||
import { ReleaseGroupConnection } from './release-group'
|
||||
import { WorkConnection } from './work'
|
||||
import {
|
||||
lookupResolver,
|
||||
linkedResolver,
|
||||
relationResolver,
|
||||
searchResolver,
|
||||
includeRelations
|
||||
} from '../resolvers'
|
||||
|
||||
export const toNodeType = pascalCase
|
||||
export const toEntityType = dashify
|
||||
|
||||
export function getByline (data) {
|
||||
const credit = data['artist-credit']
|
||||
if (credit && credit.length) {
|
||||
return credit.reduce((byline, credit) => {
|
||||
return byline + credit.name + credit.joinphrase
|
||||
}, '')
|
||||
}
|
||||
}
|
||||
|
||||
export function fieldWithID (name, config = {}) {
|
||||
config = {
|
||||
type: GraphQLString,
|
||||
|
|
@ -76,29 +68,10 @@ export function getFallback (keys) {
|
|||
}
|
||||
}
|
||||
|
||||
export function lookupQuery (entity, params) {
|
||||
return {
|
||||
type: entity,
|
||||
description: `Look up a specific ${entity.name} by its MBID.`,
|
||||
args: { id },
|
||||
resolve: lookupResolver(dashify(entity.name), params)
|
||||
}
|
||||
}
|
||||
|
||||
export function searchQuery (connectionType) {
|
||||
return {
|
||||
type: connectionType,
|
||||
args: {
|
||||
query: { type: new GraphQLNonNull(GraphQLString) },
|
||||
...forwardConnectionArgs
|
||||
},
|
||||
resolve: searchResolver()
|
||||
}
|
||||
}
|
||||
|
||||
export const id = globalIdField()
|
||||
export const mbid = {
|
||||
type: new GraphQLNonNull(MBID),
|
||||
description: 'The MBID of the entity.',
|
||||
resolve: source => source.id
|
||||
}
|
||||
export const name = { type: GraphQLString }
|
||||
|
|
@ -107,11 +80,21 @@ export const title = { type: GraphQLString }
|
|||
export const disambiguation = { type: GraphQLString }
|
||||
export const lifeSpan = { type: LifeSpan, resolve: getHyphenated }
|
||||
|
||||
function linkedQuery (connectionType, args) {
|
||||
return {
|
||||
type: connectionType,
|
||||
args: {
|
||||
...forwardConnectionArgs,
|
||||
...args
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
}
|
||||
|
||||
export const relation = {
|
||||
type: new GraphQLList(Relation),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
...connectionArgs,
|
||||
direction: { type: GraphQLString },
|
||||
type: { type: GraphQLString },
|
||||
typeID: { type: MBID }
|
||||
|
|
@ -141,7 +124,7 @@ export const relations = {
|
|||
if (source.relations != null) {
|
||||
return source.relations
|
||||
}
|
||||
const entityType = dashify(info.parentType.name)
|
||||
const entityType = toEntityType(info.parentType.name)
|
||||
const id = source.id
|
||||
const params = includeRelations({}, info)
|
||||
return lookupLoader.load([entityType, id, params]).then(entity => {
|
||||
|
|
@ -166,80 +149,22 @@ export const artistCredit = {
|
|||
}
|
||||
}
|
||||
|
||||
export const artists = {
|
||||
type: new GraphQLList(Artist),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
export const artists = linkedQuery(ArtistConnection)
|
||||
export const events = linkedQuery(EventConnection)
|
||||
export const labels = linkedQuery(LabelConnection)
|
||||
export const places = linkedQuery(PlaceConnection)
|
||||
export const recordings = linkedQuery(RecordingConnection)
|
||||
|
||||
export const events = {
|
||||
type: new GraphQLList(Event),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
export const releases = linkedQuery(ReleaseConnection, {
|
||||
type: { type: ReleaseGroupType },
|
||||
types: { type: new GraphQLList(ReleaseGroupType) },
|
||||
status: { type: ReleaseStatus },
|
||||
statuses: { type: new GraphQLList(ReleaseStatus) }
|
||||
})
|
||||
|
||||
export const labels = {
|
||||
type: new GraphQLList(Label),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
export const releaseGroups = linkedQuery(ReleaseGroupConnection, {
|
||||
type: { type: ReleaseGroupType },
|
||||
types: { type: new GraphQLList(ReleaseGroupType) }
|
||||
})
|
||||
|
||||
export const places = {
|
||||
type: new GraphQLList(Place),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
|
||||
export const recordings = {
|
||||
type: new GraphQLList(Recording),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
|
||||
export const releases = {
|
||||
type: new GraphQLList(Release),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
type: { type: ReleaseGroupType },
|
||||
types: { type: new GraphQLList(ReleaseGroupType) },
|
||||
status: { type: ReleaseStatus },
|
||||
statuses: { type: new GraphQLList(ReleaseStatus) }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
|
||||
export const releaseGroups = {
|
||||
type: new GraphQLList(ReleaseGroup),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt },
|
||||
type: { type: ReleaseGroupType },
|
||||
types: { type: new GraphQLList(ReleaseGroupType) }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
|
||||
export const works = {
|
||||
type: new GraphQLList(Work),
|
||||
args: {
|
||||
limit: { type: GraphQLInt },
|
||||
offset: { type: GraphQLInt }
|
||||
},
|
||||
resolve: linkedResolver()
|
||||
}
|
||||
export const works = linkedQuery(WorkConnection)
|
||||
|
|
|
|||
Loading…
Reference in a new issue