UNPKG

8.27 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _promise = require('babel-runtime/core-js/promise');
8
9var _promise2 = _interopRequireDefault(_promise);
10
11var _keys = require('babel-runtime/core-js/object/keys');
12
13var _keys2 = _interopRequireDefault(_keys);
14
15exports.includeRelationships = includeRelationships;
16exports.includeSubqueries = includeSubqueries;
17exports.resolveLookup = resolveLookup;
18exports.resolveBrowse = resolveBrowse;
19exports.resolveSearch = resolveSearch;
20exports.resolveRelationship = resolveRelationship;
21exports.resolveLinked = resolveLinked;
22exports.createSubqueryResolver = createSubqueryResolver;
23exports.resolveDiscReleases = resolveDiscReleases;
24
25var _helpers = require('./types/helpers');
26
27var _graphqlRelay = require('graphql-relay');
28
29var _util = require('./util');
30
31function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
32
33function includeRelationships(params, info, fragments = info.fragments) {
34 let fields = (0, _util.getFields)(info, fragments);
35 if (info.fieldName !== 'relationships') {
36 if (fields.relationships) {
37 fields = (0, _util.getFields)(fields.relationships, fragments);
38 } else {
39 if (fields.edges) {
40 fields = (0, _util.getFields)(fields.edges, fragments);
41 if (fields.node) {
42 return includeRelationships(params, fields.node, fragments);
43 }
44 }
45 return params;
46 }
47 }
48 if (fields) {
49 const relationships = (0, _keys2.default)(fields);
50 const includeRels = relationships.map(field => {
51 return `${(0, _helpers.toDashed)((0, _helpers.toSingular)(field))}-rels`;
52 });
53 if (includeRels.length) {
54 params = {
55 ...params,
56 inc: (0, _util.extendIncludes)(params.inc, includeRels)
57 };
58 }
59 }
60 return params;
61}
62
63function includeSubqueries(params, info, fragments = info.fragments) {
64 const subqueryIncludes = {
65 aliases: ['aliases'],
66 artistCredit: ['artist-credits'],
67 artistCredits: ['artist-credits'],
68 isrcs: ['isrcs'],
69 media: ['media', 'discids'],
70 rating: ['ratings'],
71 tags: ['tags']
72 };
73 let fields = (0, _util.getFields)(info, fragments);
74 const include = [];
75 for (const key in subqueryIncludes) {
76 if (fields[key]) {
77 const value = subqueryIncludes[key];
78 include.push(...value);
79 }
80 }
81 params = {
82 ...params,
83 inc: (0, _util.extendIncludes)(params.inc, include)
84 };
85 if (fields.edges) {
86 fields = (0, _util.getFields)(fields.edges, fragments);
87 if (fields.node) {
88 params = includeSubqueries(params, fields.node, fragments);
89 }
90 }
91 return params;
92}
93
94function resolveLookup(root, { mbid, ...params }, { loaders }, info) {
95 if (!mbid && !params.resource) {
96 throw new Error('Lookups by a field other than MBID must provide: resource');
97 }
98 const entityType = (0, _helpers.toDashed)(info.fieldName);
99 params = includeSubqueries(params, info);
100 params = includeRelationships(params, info);
101 return loaders.lookup.load([entityType, mbid, params]);
102}
103
104function resolveBrowse(root, { first, after, type = [], status = [], discID, isrc, iswc, ...args }, { loaders }, info) {
105 const pluralName = (0, _helpers.toDashed)(info.fieldName);
106 const singularName = (0, _helpers.toSingular)(pluralName);
107 let params = {
108 ...args,
109 type,
110 status,
111 limit: first,
112 offset: (0, _graphqlRelay.getOffsetWithDefault)(after, -1) + 1 || undefined
113 };
114 params = includeSubqueries(params, info);
115 params = includeRelationships(params, info, info.fragments);
116 const formatParam = value => value.toLowerCase().replace(/ /g, '');
117 params.type = params.type.map(formatParam);
118 params.status = params.status.map(formatParam);
119 let request;
120 if (discID) {
121 request = loaders.lookup.load(['discid', discID, params]);
122 // If fetching releases by disc ID, they will already include the `media`
123 // and `discids` subqueries, and it is invalid to specify them.
124 if (params.inc) {
125 params.inc = params.inc.filter(value => {
126 return value !== 'media' && value !== 'discids';
127 });
128 }
129 } else if (isrc) {
130 request = loaders.lookup.load(['isrc', isrc, params]);
131 } else if (iswc) {
132 request = loaders.lookup.load(['iswc', iswc, params]);
133 } else {
134 request = loaders.browse.load([singularName, params]);
135 }
136 return request.then(list => {
137 // Grab the list, offet, and count from the response and use them to build
138 // a Relay connection object.
139 const {
140 [pluralName]: arraySlice,
141 [`${singularName}-offset`]: sliceStart = 0,
142 [`${singularName}-count`]: arrayLength = arraySlice.length
143 } = list;
144 const meta = { sliceStart, arrayLength };
145 const connection = (0, _graphqlRelay.connectionFromArraySlice)(arraySlice, { first, after }, meta);
146 return {
147 nodes: connection.edges.map(edge => edge.node),
148 totalCount: arrayLength,
149 ...connection
150 };
151 });
152}
153
154function resolveSearch(root, { after, first, query, ...args }, { loaders }, info) {
155 const pluralName = (0, _helpers.toDashed)(info.fieldName);
156 const singularName = (0, _helpers.toSingular)(pluralName);
157 let params = {
158 ...args,
159 limit: first,
160 offset: (0, _graphqlRelay.getOffsetWithDefault)(after, -1) + 1 || undefined
161 };
162 params = includeSubqueries(params, info);
163 return loaders.search.load([singularName, query, params]).then(list => {
164 const {
165 [pluralName]: arraySlice,
166 offset: sliceStart,
167 count: arrayLength
168 } = list;
169 const meta = { sliceStart, arrayLength };
170 const connection = (0, _graphqlRelay.connectionFromArraySlice)(arraySlice, { first, after }, meta);
171 // Move the `score` field up to the edge object and make sure it's a
172 // number (MusicBrainz returns a string).
173 const edges = connection.edges.map(edge => ({
174 ...edge,
175 score: +edge.node.score
176 }));
177 const connectionWithExtras = {
178 nodes: edges.map(edge => edge.node),
179 totalCount: arrayLength,
180 ...connection,
181 edges
182 };
183 return connectionWithExtras;
184 });
185}
186
187function resolveRelationship(rels, args, context, info) {
188 const targetType = (0, _helpers.toDashed)((0, _helpers.toSingular)(info.fieldName)).replace('-', '_');
189 let matches = rels.filter(rel => rel['target-type'] === targetType);
190 // There's no way to filter these at the API level, so do it here.
191 if (args.direction != null) {
192 matches = matches.filter(rel => rel.direction === args.direction);
193 }
194 if (args.type != null) {
195 matches = matches.filter(rel => rel.type === args.type);
196 }
197 if (args.typeID != null) {
198 matches = matches.filter(rel => rel['type-id'] === args.typeID);
199 }
200 const connection = (0, _graphqlRelay.connectionFromArray)(matches, args);
201 return {
202 nodes: connection.edges.map(edge => edge.node),
203 totalCount: matches.length,
204 ...connection
205 };
206}
207
208function resolveLinked(entity, args, context, info) {
209 const parentEntity = (0, _helpers.toDashed)(info.parentType.name);
210 args = { ...args, [parentEntity]: entity.id };
211 return resolveBrowse(entity, args, context, info);
212}
213
214/**
215 * If we weren't smart enough or weren't able to include the `inc` parameter
216 * for a particular field that's being requested, make another request to grab
217 * it (after making sure it isn't already available).
218 */
219function createSubqueryResolver({ inc, key } = {}, handler = value => value) {
220 return (entity, args, { loaders }, info) => {
221 key = key || (0, _helpers.toDashed)(info.fieldName);
222 let promise;
223 if (key in entity) {
224 promise = _promise2.default.resolve(entity);
225 } else {
226 const { _type: entityType, id } = entity;
227 const params = { inc: [inc || key] };
228 promise = loaders.lookup.load([entityType, id, params]);
229 }
230 return promise.then(entity => handler(entity[key], args));
231 };
232}
233
234function resolveDiscReleases(disc, args, context, info) {
235 const { releases } = disc;
236 if (releases != null) {
237 const connection = (0, _graphqlRelay.connectionFromArray)(releases, args);
238 return {
239 nodes: connection.edges.map(edge => edge.node),
240 totalCount: releases.length,
241 ...connection
242 };
243 }
244 args = { ...args, discID: disc.id };
245 return resolveBrowse(disc, args, context, info);
246}
\No newline at end of file