diff --git a/src/resolvers.js b/src/resolvers.js index 7366990..1b8ddbb 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -160,22 +160,17 @@ export function resolveSearch (root, { export function resolveRelationship (rels, args, context, info) { const targetType = toDashed(toSingular(info.fieldName)).replace('-', '_') + let matches = rels.filter(rel => rel['target-type'] === targetType) // 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 - }) + if (args.direction != null) { + matches = matches.filter(rel => rel.direction === args.direction) + } + if (args.type != null) { + matches = matches.filter(rel => rel.type === args.type) + } + if (args.typeID != null) { + matches = matches.filter(rel => rel['type-id'] === args.typeID) + } return { totalCount: matches.length, ...connectionFromArray(matches, args) diff --git a/test/fixtures/1f64e39ed51023c3c258447c628d9f76 b/test/fixtures/1f64e39ed51023c3c258447c628d9f76 new file mode 100644 index 0000000..b4d509d Binary files /dev/null and b/test/fixtures/1f64e39ed51023c3c258447c628d9f76 differ diff --git a/test/fixtures/1f64e39ed51023c3c258447c628d9f76.headers b/test/fixtures/1f64e39ed51023c3c258447c628d9f76.headers new file mode 100644 index 0000000..26cac50 --- /dev/null +++ b/test/fixtures/1f64e39ed51023c3c258447c628d9f76.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 20:39:30 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "217", + "x-ratelimit-reset": "1481575170", + "server": "Plack::Handler::Starlet", + "etag": "W/\"4ec669743d386e627a2a12a3a56fa457\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/artist/65314b12-0e08-43fa-ba33-baaa7b874c15?inc=artist-rels&fmt=json", + "time": 534, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.4.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/c7c9fd40e14262c634d1c06a962af78f b/test/fixtures/c7c9fd40e14262c634d1c06a962af78f new file mode 100644 index 0000000..3485f2b Binary files /dev/null and b/test/fixtures/c7c9fd40e14262c634d1c06a962af78f differ diff --git a/test/fixtures/c7c9fd40e14262c634d1c06a962af78f.headers b/test/fixtures/c7c9fd40e14262c634d1c06a962af78f.headers new file mode 100644 index 0000000..598e253 --- /dev/null +++ b/test/fixtures/c7c9fd40e14262c634d1c06a962af78f.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 20:39:30 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "220", + "x-ratelimit-reset": "1481575170", + "server": "Plack::Handler::Starlet", + "etag": "W/\"a1c5627837ae92cd0acc8d2ce30a386f\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/area/10cb2ebd-1bc7-4c11-b10d-54f60c421d20?inc=area-rels&fmt=json", + "time": 1255, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.4.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/fixtures/e5f2bd64ae9be1fe45177483a4d5e80e b/test/fixtures/e5f2bd64ae9be1fe45177483a4d5e80e new file mode 100644 index 0000000..a9d0ee2 Binary files /dev/null and b/test/fixtures/e5f2bd64ae9be1fe45177483a4d5e80e differ diff --git a/test/fixtures/e5f2bd64ae9be1fe45177483a4d5e80e.headers b/test/fixtures/e5f2bd64ae9be1fe45177483a4d5e80e.headers new file mode 100644 index 0000000..475d615 --- /dev/null +++ b/test/fixtures/e5f2bd64ae9be1fe45177483a4d5e80e.headers @@ -0,0 +1,29 @@ +{ + "statusCode": 200, + "headers": { + "date": "Mon, 12 Dec 2016 20:28:24 GMT", + "content-type": "application/json; charset=utf-8", + "transfer-encoding": "chunked", + "connection": "keep-alive", + "keep-alive": "timeout=15", + "vary": "Accept-Encoding", + "x-ratelimit-limit": "700", + "x-ratelimit-remaining": "427", + "x-ratelimit-reset": "1481574505", + "server": "Plack::Handler::Starlet", + "etag": "W/\"d0d38fc0408632fad58f6eeeb230ca90\"", + "access-control-allow-origin": "*", + "content-encoding": "gzip" + }, + "url": "http://musicbrainz.org:80/ws/2/artist/5b11f4ce-a62d-471e-81fc-a69a8278c7da?inc=artist-rels&fmt=json", + "time": 578, + "request": { + "method": "GET", + "headers": { + "User-Agent": "graphbrainz/4.4.0 ( https://github.com/exogen/graphbrainz )", + "host": "musicbrainz.org", + "accept-encoding": "gzip, deflate", + "accept": "application/json" + } + } +} \ No newline at end of file diff --git a/test/schema.js b/test/schema.js index f1fa856..e0838da 100644 --- a/test/schema.js +++ b/test/schema.js @@ -196,7 +196,7 @@ test('throws an error if given a malformed MBID', testError, ` t.is(err.message, 'Malformed MBID: ABC123') }) -test('Artist beginArea/endArea pulls from begin_area/end_area for lookup queries', testData, ` +test('artist areas access begin_area/end_area for lookup queries', testData, ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -215,7 +215,7 @@ test('Artist beginArea/endArea pulls from begin_area/end_area for lookup queries t.is(artist.endArea.name, 'Los Angeles') }) -test('Artist beginArea/endArea pull from begin_area/end_area for browse queries', testData, ` +test('artist areas access begin_area/end_area for browse queries', testData, ` { browse { artists(area: "3f504d54-c40c-487d-bc16-c1990eac887f") { @@ -239,7 +239,7 @@ test('Artist beginArea/endArea pull from begin_area/end_area for browse queries' t.true(artists.some(artist => artist.endArea)) }) -test('Artist beginArea/endArea pulls from begin-area/end-area for search queries', testData, ` +test('artist areas access begin-area/end-area for search queries', testData, ` { search { artists(query: "Leonard Cohen", first: 1) { @@ -263,7 +263,7 @@ test('Artist beginArea/endArea pulls from begin-area/end-area for search queries t.is(artists[0].endArea.name, 'Los Angeles') }) -test('relationships filter by type', testData, ` +test('relationships are grouped by target type', testData, ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -321,7 +321,102 @@ test('relationships filter by type', testData, ` }) }) -test('Area maps iso-3166-1-codes to isoCodes', testData, ` +test('relationships can be filtered by type', testData, ` + { + lookup { + artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { + relationships { + artists(type: "parent") { + edges { + node { + targetType + type + } + } + } + } + } + } + } +`, (t, data) => { + const { artist } = data.lookup + const rels = artist.relationships.artists.edges.map(edge => edge.node) + t.is(rels.length, 2) + rels.forEach(rel => { + t.is(rel.targetType, 'artist') + t.is(rel.type, 'parent') + }) +}) + +test('relationships can be filtered by type ID', testData, ` + { + lookup { + artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { + relationships { + artists(typeID: "fd3927ba-fd51-4fa9-bcc2-e83637896fe8") { + edges { + node { + targetType + type + } + } + } + } + } + } + } +`, (t, data) => { + const { artist } = data.lookup + const rels = artist.relationships.artists.edges.map(edge => edge.node) + t.is(rels.length, 1) + rels.forEach(rel => { + t.is(rel.targetType, 'artist') + t.is(rel.type, 'involved with') + }) +}) + +test('relationships can be filtered by direction', testData, ` + { + lookup { + area(mbid: "10cb2ebd-1bc7-4c11-b10d-54f60c421d20") { + relationships { + isPartOf: areas(direction: "backward") { + edges { + node { + type + direction + } + } + } + hasParts: areas(direction: "forward") { + edges { + node { + type + direction + } + } + } + } + } + } + } +`, (t, data) => { + const { area } = data.lookup + const isPartOf = area.relationships.isPartOf.edges.map(edge => edge.node) + const hasParts = area.relationships.hasParts.edges.map(edge => edge.node) + t.true(isPartOf.length > 0) + t.true(hasParts.length > 0) + isPartOf.forEach(rel => { + t.is(rel.type, 'part of') + t.is(rel.direction, 'backward') + }) + hasParts.forEach(rel => { + t.is(rel.type, 'part of') + t.is(rel.direction, 'forward') + }) +}) + +test('area maps iso-3166-1-codes to isoCodes', testData, ` { lookup { area(mbid: "489ce91b-6658-3307-9877-795b68554c98") { @@ -334,7 +429,7 @@ test('Area maps iso-3166-1-codes to isoCodes', testData, ` t.deepEqual(data.lookup.area.isoCodes, ['US']) }) -test('Alias locales use the Locale scalar', testData, ` +test('alias locales use the locale scalar', testData, ` { lookup { artist(mbid: "f99b7d67-4e63-4678-aa66-4c6ac0f7d24a") { @@ -351,7 +446,7 @@ test('Alias locales use the Locale scalar', testData, ` t.is(aliases.find(alias => alias.locale === 'ko').name, '싸이') }) -test('Work ISWCs use the ISWC scalar', testData, ` +test('work ISWCs use the ISWC scalar', testData, ` { lookup { work(mbid: "ef7d0814-da6a-32f5-a600-ff81cffd1aed") { @@ -381,7 +476,7 @@ test('URLs may be looked up by resource', testData, ` t.is(url.resource, 'http://www.nirvana.com/') }) -test('throws an error if given a malformed URLString', testError, ` +test('throws an error if given a malformed resource URL', testError, ` { lookup { url(resource: "http:foo") { @@ -396,7 +491,7 @@ test('throws an error if given a malformed URLString', testError, ` t.is(err.message, 'Malformed URL: http:foo') }) -test('Release groups can be browsed by type', testData, ` +test('release groups can be browsed by type', testData, ` { browse { releaseGroups(artist: "5b11f4ce-a62d-471e-81fc-a69a8278c7da", type: EP) { @@ -414,7 +509,7 @@ test('Release groups can be browsed by type', testData, ` releaseGroups.forEach(releaseGroup => t.is(releaseGroup.primaryType, 'EP')) }) -test('Releases can be browsed by type and status', testData, ` +test('releases can be browsed by type and status', testData, ` { browse { releases(artist: "5b11f4ce-a62d-471e-81fc-a69a8278c7da", type: EP, status: BOOTLEG) { @@ -432,7 +527,7 @@ test('Releases can be browsed by type and status', testData, ` releases.forEach(release => t.is(release.status, 'BOOTLEG')) }) -test('Releases have an ASIN field', testData, ` +test('releases have an ASIN field', testData, ` { lookup { release(mbid: "d5cdb7fd-c7e9-460a-9549-8a369655cc52") { @@ -445,7 +540,7 @@ test('Releases have an ASIN field', testData, ` t.is(release.asin, 'B01KN6XDS6') }) -test('Artists have a list of ISNIs and IPIs', testData, ` +test('artists have a list of ISNIs and IPIs', testData, ` { lookup { artist(mbid: "65314b12-0e08-43fa-ba33-baaa7b874c15") { @@ -515,7 +610,7 @@ test('artistCredits is an alias for artistCredit', testData, ` t.deepEqual(releaseGroup.artistCredits, releaseGroup.artistCredit) }) -test('Recordings can be browsed by isrc', testData, ` +test('recordings can be browsed by ISRC', testData, ` { browse { recordings(isrc: "USSUB0200002") { @@ -537,7 +632,7 @@ test('Recordings can be browsed by isrc', testData, ` ]) }) -test('Releases can be browsed by discID', testData, ` +test('releases can be browsed by Disc ID', testData, ` { browse { releases(discID: "XzPS7vW.HPHsYemQh0HBUGr8vuU-") { @@ -558,7 +653,7 @@ test('Releases can be browsed by discID', testData, ` t.true(releases.some(release => release.mbid === '96f6f90e-d831-4f37-bf72-ce2982e459fb')) }) -test('Works can be browsed by iswc', testData, ` +test('works can be browsed by ISWC', testData, ` { browse { works(iswc: "T-900.755.682-3") { @@ -580,7 +675,7 @@ test('Works can be browsed by iswc', testData, ` ]) }) -test('Recordings have a length in milliseconds', testData, ` +test('recordings have a length in milliseconds', testData, ` { lookup { recording(mbid: "9f9cf187-d6f9-437f-9d98-d59cdbd52757") { @@ -593,7 +688,7 @@ test('Recordings have a length in milliseconds', testData, ` t.is(recording.length, 383493) }) -test('Collections can be browsed by the entities they contain', testData, ` +test('collections can be browsed by the entities they contain', testData, ` { browse { collections(artist: "24f1766e-9635-4d58-a4d4-9413f9f98a4c") { @@ -631,7 +726,7 @@ test('Collections can be browsed by the entities they contain', testData, ` }) }) -test('Collections can be looked up by MBID', testData, ` +test('collections can be looked up by MBID', testData, ` { lookup { collection(mbid: "85da782d-2ec0-41ec-a97f-9be464bba309") { @@ -686,7 +781,7 @@ test('entities have a collections field', testData, ` t.true(artist.collections.edges.length > 0) }) -test('Releases support a list of media', testData, ` +test('releases support a list of media', testData, ` { lookup { release(mbid: "a4864e94-6d75-4ade-bc93-0dabf3521453") { @@ -719,3 +814,15 @@ test('Releases support a list of media', testData, ` } ]) }) + +test('throws an error if looking up a URL without an argument', testError, ` + { + lookup { + url { + mbid + } + } + } +`, (t, errors) => { + t.is(errors[0].message, 'Lookups by a field other than MBID must provide: resource') +})