This commit is contained in:
Brian Beck 2016-08-31 21:31:48 -07:00
parent 8759943638
commit ed5339f2e1
9 changed files with 794 additions and 618 deletions

View file

@ -37,7 +37,7 @@ type Area implements Entity {
statuses: [ReleaseStatus]): [Release] statuses: [ReleaseStatus]): [Release]
} }
type AreaPage { type AreaConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -80,7 +80,7 @@ type ArtistCredit {
joinPhrase: String joinPhrase: String
} }
type ArtistPage { type ArtistConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -94,23 +94,23 @@ type BrowseQuery {
recording: MBID, recording: MBID,
release: MBID, release: MBID,
releaseGroup: MBID, releaseGroup: MBID,
work: MBID): ArtistPage work: MBID): ArtistConnection
events(limit: Int, events(limit: Int,
offset: Int, offset: Int,
area: MBID, area: MBID,
artist: MBID, artist: MBID,
place: MBID): EventPage place: MBID): EventConnection
labels(limit: Int, labels(limit: Int,
offset: Int, offset: Int,
area: MBID, area: MBID,
release: MBID): LabelPage release: MBID): LabelConnection
places(limit: Int, places(limit: Int,
offset: Int, offset: Int,
area: MBID): PlacePage area: MBID): PlaceConnection
recordings(limit: Int, recordings(limit: Int,
offset: Int, offset: Int,
artist: MBID, artist: MBID,
release: MBID): RecordingPage release: MBID): RecordingConnection
releases(limit: Int, releases(limit: Int,
offset: Int, offset: Int,
area: MBID, area: MBID,
@ -119,17 +119,17 @@ type BrowseQuery {
track: MBID, track: MBID,
trackArtist: MBID, trackArtist: MBID,
recording: MBID, recording: MBID,
releaseGroup: MBID): ReleasePage releaseGroup: MBID): ReleaseConnection
releaseGroups(limit: Int, releaseGroups(limit: Int,
offset: Int, offset: Int,
artist: MBID, artist: MBID,
release: MBID): ReleaseGroupPage release: MBID): ReleaseGroupConnection
works(limit: Int, works(limit: Int,
offset: Int, offset: Int,
artist: MBID): WorkPage artist: MBID): WorkConnection
urls(limit: Int, urls(limit: Int,
offset: Int, offset: Int,
resource: URLString): URLPage resource: URLString): URLConnection
} }
type Coordinates { type Coordinates {
@ -157,7 +157,7 @@ type Event implements Entity {
typeID: MBID typeID: MBID
} }
type EventPage { type EventConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -195,7 +195,7 @@ type Label implements Entity {
statuses: [ReleaseStatus]): [Release] statuses: [ReleaseStatus]): [Release]
} }
type LabelPage { type LabelConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -237,7 +237,7 @@ type Place implements Entity {
events(limit: Int, offset: Int): [Event] events(limit: Int, offset: Int): [Event]
} }
type PlacePage { type PlaceConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -261,7 +261,7 @@ type Recording implements Entity {
relations: Relations relations: Relations
} }
type RecordingPage { type RecordingConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -394,7 +394,7 @@ type ReleaseGroup implements Entity {
relations: Relations relations: Relations
} }
type ReleaseGroupPage { type ReleaseGroupConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -420,7 +420,7 @@ enum ReleaseGroupType {
NAT NAT
} }
type ReleasePage { type ReleaseConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -441,14 +441,14 @@ type RootQuery {
} }
type SearchQuery { type SearchQuery {
areas(query: String!, limit: Int, offset: Int): AreaPage areas(query: String!, limit: Int, offset: Int): AreaConnection
artists(query: String!, limit: Int, offset: Int): ArtistPage artists(query: String!, limit: Int, offset: Int): ArtistConnection
labels(query: String!, limit: Int, offset: Int): LabelPage labels(query: String!, limit: Int, offset: Int): LabelConnection
places(query: String!, limit: Int, offset: Int): PlacePage places(query: String!, limit: Int, offset: Int): PlaceConnection
recordings(query: String!, limit: Int, offset: Int): RecordingPage recordings(query: String!, limit: Int, offset: Int): RecordingConnection
releases(query: String!, limit: Int, offset: Int): ReleasePage releases(query: String!, limit: Int, offset: Int): ReleaseConnection
releaseGroups(query: String!, limit: Int, offset: Int): ReleaseGroupPage releaseGroups(query: String!, limit: Int, offset: Int): ReleaseGroupConnection
works(query: String!, limit: Int, offset: Int): WorkPage works(query: String!, limit: Int, offset: Int): WorkConnection
} }
scalar Time scalar Time
@ -459,7 +459,7 @@ type URL implements Entity {
relations: Relations relations: Relations
} }
type URLPage { type URLConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date
@ -480,7 +480,7 @@ type Work implements Entity {
relations: Relations relations: Relations
} }
type WorkPage { type WorkConnection {
count: Int! count: Int!
offset: Int! offset: Int!
created: Date created: Date

View file

@ -47,7 +47,7 @@
"pascalcase": "^0.1.1", "pascalcase": "^0.1.1",
"qs": "^6.2.1", "qs": "^6.2.1",
"request": "^2.74.0", "request": "^2.74.0",
"retry": "^0.9.0" "retry": "^0.10.0"
}, },
"devDependencies": { "devDependencies": {
"babel-cli": "^6.11.4", "babel-cli": "^6.11.4",
@ -59,7 +59,7 @@
"mocha": "^3.0.1", "mocha": "^3.0.1",
"nodemon": "^1.10.2", "nodemon": "^1.10.2",
"snazzy": "^4.0.1", "snazzy": "^4.0.1",
"standard": "^7.1.2" "standard": "^8.0.0"
}, },
"standard": { "standard": {
"parser": "babel-eslint" "parser": "babel-eslint"

File diff suppressed because it is too large Load diff

View file

@ -2,15 +2,15 @@ import { GraphQLObjectType, GraphQLInt } from 'graphql'
import { import {
MBID, MBID,
URLString, URLString,
ArtistPage, ArtistConnection,
EventPage, EventConnection,
LabelPage, LabelConnection,
PlacePage, PlaceConnection,
RecordingPage, RecordingConnection,
ReleasePage, ReleaseConnection,
ReleaseGroupPage, ReleaseGroupConnection,
URLPage, URLConnection,
WorkPage WorkConnection
} from '../types' } from '../types'
import { browseResolver } from '../resolvers' import { browseResolver } from '../resolvers'
@ -21,7 +21,7 @@ export default new GraphQLObjectType({
'to another entity.', 'to another entity.',
fields: { fields: {
artists: { artists: {
type: ArtistPage, type: ArtistConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -34,7 +34,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
events: { events: {
type: EventPage, type: EventConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -45,7 +45,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
labels: { labels: {
type: LabelPage, type: LabelConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -55,7 +55,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
places: { places: {
type: PlacePage, type: PlaceConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -64,7 +64,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
recordings: { recordings: {
type: RecordingPage, type: RecordingConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -74,7 +74,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
releases: { releases: {
type: ReleasePage, type: ReleaseConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -89,7 +89,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
releaseGroups: { releaseGroups: {
type: ReleaseGroupPage, type: ReleaseGroupConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -99,7 +99,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
works: { works: {
type: WorkPage, type: WorkConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },
@ -108,7 +108,7 @@ export default new GraphQLObjectType({
resolve: browseResolver() resolve: browseResolver()
}, },
urls: { urls: {
type: URLPage, type: URLConnection,
args: { args: {
limit: { type: GraphQLInt }, limit: { type: GraphQLInt },
offset: { type: GraphQLInt }, offset: { type: GraphQLInt },

View file

@ -1,13 +1,13 @@
import { GraphQLObjectType } from 'graphql' import { GraphQLObjectType } from 'graphql'
import { import {
AreaPage, AreaConnection,
ArtistPage, ArtistConnection,
LabelPage, LabelConnection,
PlacePage, PlaceConnection,
RecordingPage, RecordingConnection,
ReleasePage, ReleaseConnection,
ReleaseGroupPage, ReleaseGroupConnection,
WorkPage WorkConnection
} from '../types' } from '../types'
import { searchQuery } from '../types/helpers' import { searchQuery } from '../types/helpers'
@ -17,13 +17,13 @@ export default new GraphQLObjectType({
'Search queries provide a way to search for MusicBrainz entities using ' + 'Search queries provide a way to search for MusicBrainz entities using ' +
'Lucene query syntax.', 'Lucene query syntax.',
fields: { fields: {
areas: searchQuery(AreaPage), areas: searchQuery(AreaConnection),
artists: searchQuery(ArtistPage), artists: searchQuery(ArtistConnection),
labels: searchQuery(LabelPage), labels: searchQuery(LabelConnection),
places: searchQuery(PlacePage), places: searchQuery(PlaceConnection),
recordings: searchQuery(RecordingPage), recordings: searchQuery(RecordingConnection),
releases: searchQuery(ReleasePage), releases: searchQuery(ReleaseConnection),
releaseGroups: searchQuery(ReleaseGroupPage), releaseGroups: searchQuery(ReleaseGroupConnection),
works: searchQuery(WorkPage) works: searchQuery(WorkConnection)
} }
}) })

View file

@ -1,4 +1,5 @@
import dashify from 'dashify' import { toEntityType } from './types/helpers'
import { getOffsetWithDefault, connectionFromArraySlice } from 'graphql-relay'
import { getFields, extendIncludes } from './util' import { getFields, extendIncludes } from './util'
export function includeRelations (params, info) { export function includeRelations (params, info) {
@ -12,7 +13,7 @@ export function includeRelations (params, info) {
} }
if (fields) { if (fields) {
const relations = Object.keys(fields) const relations = Object.keys(fields)
const includeRels = relations.map(key => `${dashify(key)}-rels`) const includeRels = relations.map(key => `${toEntityType(key)}-rels`)
if (includeRels.length) { if (includeRels.length) {
params = { params = {
...params, ...params,
@ -37,14 +38,14 @@ export function includeSubqueries (params, info) {
export function lookupResolver (entityType, extraParams = {}) { export function lookupResolver (entityType, extraParams = {}) {
return (root, { id }, { lookupLoader }, info) => { return (root, { id }, { lookupLoader }, info) => {
const params = includeRelations(extraParams, info) const params = includeRelations(extraParams, info)
entityType = entityType || dashify(info.fieldName) entityType = entityType || toEntityType(info.fieldName)
return lookupLoader.load([entityType, id, params]) return lookupLoader.load([entityType, id, params])
} }
} }
export function browseResolver () { export function browseResolver () {
return (source, args, { browseLoader }, info) => { return (source, args, { browseLoader }, info) => {
const pluralName = dashify(info.fieldName) const pluralName = toEntityType(info.fieldName)
let singularName = pluralName let singularName = pluralName
if (pluralName.endsWith('s')) { if (pluralName.endsWith('s')) {
singularName = pluralName.slice(0, -1) singularName = pluralName.slice(0, -1)
@ -56,13 +57,23 @@ export function browseResolver () {
export function searchResolver () { export function searchResolver () {
return (source, args, { searchLoader }, info) => { return (source, args, { searchLoader }, info) => {
const pluralName = dashify(info.fieldName) const pluralName = toEntityType(info.fieldName)
let singularName = pluralName let singularName = pluralName
if (pluralName.endsWith('s')) { if (pluralName.endsWith('s')) {
singularName = pluralName.slice(0, -1) singularName = pluralName.slice(0, -1)
} }
const { query, ...params } = args const { query, first, after, ...params } = args
return searchLoader.load([singularName, query, params]) params.limit = first
params.offset = getOffsetWithDefault(after, 0)
return searchLoader.load([singularName, query, params]).then(list => {
const {
[pluralName]: arraySlice,
offset: sliceStart,
count: arrayLength
} = list
const meta = { sliceStart, arrayLength }
return connectionFromArraySlice(arraySlice, { first, after }, meta)
})
} }
} }
@ -72,7 +83,7 @@ export function relationResolver () {
direction, direction,
type, type,
typeID }, { lookupLoader }, info) => { typeID }, { lookupLoader }, info) => {
const targetType = dashify(info.fieldName).replace('-', '_') const targetType = toEntityType(info.fieldName).replace('-', '_')
return source.filter(relation => { return source.filter(relation => {
if (relation['target-type'] !== targetType) { if (relation['target-type'] !== targetType) {
return false return false
@ -93,12 +104,12 @@ export function relationResolver () {
export function linkedResolver () { export function linkedResolver () {
return (source, args, { browseLoader }, info) => { return (source, args, { browseLoader }, info) => {
const pluralName = dashify(info.fieldName) const pluralName = toEntityType(info.fieldName)
let singularName = pluralName let singularName = pluralName
if (pluralName.endsWith('s')) { if (pluralName.endsWith('s')) {
singularName = pluralName.slice(0, -1) singularName = pluralName.slice(0, -1)
} }
const parentEntity = dashify(info.parentType.name) const parentEntity = toEntityType(info.parentType.name)
let params = { let params = {
[parentEntity]: source.id, [parentEntity]: source.id,
type: [], type: [],

View file

@ -7,7 +7,7 @@ import {
GraphQLList, GraphQLList,
GraphQLNonNull GraphQLNonNull
} from 'graphql' } from 'graphql'
import { globalIdField } from 'graphql-relay' import { globalIdField, forwardConnectionArgs } from 'graphql-relay'
import { MBID } from './scalars' import { MBID } from './scalars'
import { ReleaseGroupType, ReleaseStatus } from './enums' import { ReleaseGroupType, ReleaseStatus } from './enums'
import ArtistCredit from './artist-credit' import ArtistCredit from './artist-credit'
@ -85,22 +85,22 @@ export function lookupQuery (entity, params) {
} }
} }
export function searchQuery (entityPage) { export function searchQuery (connectionType) {
const entity = entityPage.getFields().results.type.ofType.ofType
return { return {
type: entityPage, type: connectionType,
description: `Search for ${entity.name} entities.`,
args: { args: {
query: { type: new GraphQLNonNull(GraphQLString) }, query: { type: new GraphQLNonNull(GraphQLString) },
limit: { type: GraphQLInt }, ...forwardConnectionArgs
offset: { type: GraphQLInt }
}, },
resolve: searchResolver() resolve: searchResolver()
} }
} }
export const id = globalIdField() export const id = globalIdField()
export const mbid = { type: new GraphQLNonNull(MBID) } export const mbid = {
type: new GraphQLNonNull(MBID),
resolve: source => source.id
}
export const name = { type: GraphQLString } export const name = { type: GraphQLString }
export const sortName = { type: GraphQLString, resolve: getHyphenated } export const sortName = { type: GraphQLString, resolve: getHyphenated }
export const title = { type: GraphQLString } export const title = { type: GraphQLString }

View file

@ -2,15 +2,15 @@ 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 } from './entity'
export { default as Area, AreaPage } from './area' export { default as Area, AreaConnection } from './area'
export { default as Artist, ArtistPage } from './artist' export { default as Artist, ArtistConnection } from './artist'
export { default as Event, EventPage } from './event' export { default as Event, EventConnection } from './event'
export { default as Instrument } from './instrument' export { default as Instrument } from './instrument'
export { default as Label, LabelPage } from './label' export { default as Label, LabelConnection } from './label'
export { default as Place, PlacePage } from './place' export { default as Place, PlaceConnection } from './place'
export { default as Recording, RecordingPage } from './recording' export { default as Recording, RecordingConnection } from './recording'
export { default as Release, ReleasePage } from './release' export { default as Release, ReleaseConnection } from './release'
export { default as ReleaseGroup, ReleaseGroupPage } from './release-group' export { default as ReleaseGroup, ReleaseGroupConnection } from './release-group'
export { default as Series, SeriesPage } from './series' export { default as Series, SeriesConnection } from './series'
export { default as URL, URLPage } from './url' export { default as URL, URLConnection } from './url'
export { default as Work, WorkPage } from './work' export { default as Work, WorkConnection } from './work'

View file

@ -10,8 +10,9 @@ const { nodeInterface, nodeField } = nodeDefinitions(
}, },
(obj) => { (obj) => {
try { try {
return require(`./${obj.entityType}`) return require(`./${obj.entityType}`).default
} catch (err) { } catch (err) {
console.error(err)
return null return null
} }
} }