1 | import { toDashed, toSingular } from './types/helpers'
|
2 | import {
|
3 | getOffsetWithDefault,
|
4 | connectionFromArray,
|
5 | connectionFromArraySlice
|
6 | } from 'graphql-relay'
|
7 | import { getFields, extendIncludes } from './util'
|
8 |
|
9 | export function includeRelationships (params, info, fragments = info.fragments) {
|
10 | let fields = getFields(info, fragments)
|
11 | if (info.fieldName !== 'relationships') {
|
12 | if (fields.relationships) {
|
13 | fields = getFields(fields.relationships, fragments)
|
14 | } else {
|
15 | if (fields.edges) {
|
16 | fields = getFields(fields.edges, fragments)
|
17 | if (fields.node) {
|
18 | return includeRelationships(params, fields.node, fragments)
|
19 | }
|
20 | }
|
21 | return params
|
22 | }
|
23 | }
|
24 | if (fields) {
|
25 | const relationships = Object.keys(fields)
|
26 | const includeRels = relationships.map(field => {
|
27 | return `${toDashed(toSingular(field))}-rels`
|
28 | })
|
29 | if (includeRels.length) {
|
30 | params = {
|
31 | ...params,
|
32 | inc: extendIncludes(params.inc, includeRels)
|
33 | }
|
34 | }
|
35 | }
|
36 | return params
|
37 | }
|
38 |
|
39 | export function includeSubqueries (params, info, fragments = info.fragments) {
|
40 | const subqueryIncludes = {
|
41 | aliases: ['aliases'],
|
42 | artistCredit: ['artist-credits'],
|
43 | artistCredits: ['artist-credits'],
|
44 | isrcs: ['isrcs'],
|
45 | media: ['media', 'discids'],
|
46 | rating: ['ratings'],
|
47 | tags: ['tags']
|
48 | }
|
49 | let fields = getFields(info, fragments)
|
50 | const include = []
|
51 | for (const key in subqueryIncludes) {
|
52 | if (fields[key]) {
|
53 | const value = subqueryIncludes[key]
|
54 | include.push(...value)
|
55 | }
|
56 | }
|
57 | params = {
|
58 | ...params,
|
59 | inc: extendIncludes(params.inc, include)
|
60 | }
|
61 | if (fields.edges) {
|
62 | fields = getFields(fields.edges, fragments)
|
63 | if (fields.node) {
|
64 | params = includeSubqueries(params, fields.node, fragments)
|
65 | }
|
66 | }
|
67 | return params
|
68 | }
|
69 |
|
70 | export function resolveLookup (root, { mbid, ...params }, { loaders }, info) {
|
71 | if (!mbid && !params.resource) {
|
72 | throw new Error('Lookups by a field other than MBID must provide: resource')
|
73 | }
|
74 | const entityType = toDashed(info.fieldName)
|
75 | params = includeSubqueries(params, info)
|
76 | params = includeRelationships(params, info)
|
77 | return loaders.lookup.load([entityType, mbid, params])
|
78 | }
|
79 |
|
80 | export function resolveBrowse (root, {
|
81 | first,
|
82 | after,
|
83 | type = [],
|
84 | status = [],
|
85 | discID,
|
86 | isrc,
|
87 | iswc,
|
88 | ...args
|
89 | }, { loaders }, info) {
|
90 | const pluralName = toDashed(info.fieldName)
|
91 | const singularName = toSingular(pluralName)
|
92 | let params = {
|
93 | ...args,
|
94 | type,
|
95 | status,
|
96 | limit: first,
|
97 | offset: getOffsetWithDefault(after, -1) + 1 || undefined
|
98 | }
|
99 | params = includeSubqueries(params, info)
|
100 | params = includeRelationships(params, info, info.fragments)
|
101 | const formatParam = value => value.toLowerCase().replace(/ /g, '')
|
102 | params.type = params.type.map(formatParam)
|
103 | params.status = params.status.map(formatParam)
|
104 | let request
|
105 | if (discID) {
|
106 | request = loaders.lookup.load(['discid', discID, params])
|
107 |
|
108 |
|
109 | if (params.inc) {
|
110 | params.inc = params.inc.filter(value => {
|
111 | return value !== 'media' && value !== 'discids'
|
112 | })
|
113 | }
|
114 | } else if (isrc) {
|
115 | request = loaders.lookup.load(['isrc', isrc, params])
|
116 | } else if (iswc) {
|
117 | request = loaders.lookup.load(['iswc', iswc, params])
|
118 | } else {
|
119 | request = loaders.browse.load([singularName, params])
|
120 | }
|
121 | return request.then(list => {
|
122 |
|
123 |
|
124 | const {
|
125 | [pluralName]: arraySlice,
|
126 | [`${singularName}-offset`]: sliceStart = 0,
|
127 | [`${singularName}-count`]: arrayLength = arraySlice.length
|
128 | } = list
|
129 | const meta = { sliceStart, arrayLength }
|
130 | const connection = connectionFromArraySlice(arraySlice, { first, after }, meta)
|
131 | return {
|
132 | nodes: connection.edges.map(edge => edge.node),
|
133 | totalCount: arrayLength,
|
134 | ...connection
|
135 | }
|
136 | })
|
137 | }
|
138 |
|
139 | export function resolveSearch (root, {
|
140 | after,
|
141 | first,
|
142 | query,
|
143 | ...args
|
144 | }, { loaders }, info) {
|
145 | const pluralName = toDashed(info.fieldName)
|
146 | const singularName = toSingular(pluralName)
|
147 | let params = {
|
148 | ...args,
|
149 | limit: first,
|
150 | offset: getOffsetWithDefault(after, -1) + 1 || undefined
|
151 | }
|
152 | params = includeSubqueries(params, info)
|
153 | return loaders.search.load([singularName, query, params]).then(list => {
|
154 | const {
|
155 | [pluralName]: arraySlice,
|
156 | offset: sliceStart,
|
157 | count: arrayLength
|
158 | } = list
|
159 | const meta = { sliceStart, arrayLength }
|
160 | const connection = connectionFromArraySlice(arraySlice, { first, after }, meta)
|
161 |
|
162 |
|
163 | const edges = connection.edges.map(edge => ({ ...edge, score: +edge.node.score }))
|
164 | const connectionWithExtras = {
|
165 | nodes: edges.map(edge => edge.node),
|
166 | totalCount: arrayLength,
|
167 | ...connection,
|
168 | edges
|
169 | }
|
170 | return connectionWithExtras
|
171 | })
|
172 | }
|
173 |
|
174 | export function resolveRelationship (rels, args, context, info) {
|
175 | const targetType = toDashed(toSingular(info.fieldName)).replace('-', '_')
|
176 | let matches = rels.filter(rel => rel['target-type'] === targetType)
|
177 |
|
178 | if (args.direction != null) {
|
179 | matches = matches.filter(rel => rel.direction === args.direction)
|
180 | }
|
181 | if (args.type != null) {
|
182 | matches = matches.filter(rel => rel.type === args.type)
|
183 | }
|
184 | if (args.typeID != null) {
|
185 | matches = matches.filter(rel => rel['type-id'] === args.typeID)
|
186 | }
|
187 | const connection = connectionFromArray(matches, args)
|
188 | return {
|
189 | nodes: connection.edges.map(edge => edge.node),
|
190 | totalCount: matches.length,
|
191 | ...connection
|
192 | }
|
193 | }
|
194 |
|
195 | export function resolveLinked (entity, args, context, info) {
|
196 | const parentEntity = toDashed(info.parentType.name)
|
197 | args = { ...args, [parentEntity]: entity.id }
|
198 | return resolveBrowse(entity, args, context, info)
|
199 | }
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | export function createSubqueryResolver ({ inc, key } = {}, handler = value => value) {
|
207 | return (entity, args, { loaders }, info) => {
|
208 | key = key || toDashed(info.fieldName)
|
209 | let promise
|
210 | if (key in entity) {
|
211 | promise = Promise.resolve(entity)
|
212 | } else {
|
213 | const { _type: entityType, id } = entity
|
214 | const params = { inc: [inc || key] }
|
215 | promise = loaders.lookup.load([entityType, id, params])
|
216 | }
|
217 | return promise.then(entity => handler(entity[key], args))
|
218 | }
|
219 | }
|
220 |
|
221 | export function resolveDiscReleases (disc, args, context, info) {
|
222 | const { releases } = disc
|
223 | if (releases != null) {
|
224 | const connection = connectionFromArray(releases, args)
|
225 | return {
|
226 | nodes: connection.edges.map(edge => edge.node),
|
227 | totalCount: releases.length,
|
228 | ...connection
|
229 | }
|
230 | }
|
231 | args = { ...args, discID: disc.id }
|
232 | return resolveBrowse(disc, args, context, info)
|
233 | }
|