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(
|
81 | root,
|
82 | { first, after, type = [], status = [], discID, isrc, iswc, ...args },
|
83 | { loaders },
|
84 | info
|
85 | ) {
|
86 | const pluralName = toDashed(info.fieldName)
|
87 | const singularName = toSingular(pluralName)
|
88 | let params = {
|
89 | ...args,
|
90 | type,
|
91 | status,
|
92 | limit: first,
|
93 | offset: getOffsetWithDefault(after, -1) + 1 || undefined
|
94 | }
|
95 | params = includeSubqueries(params, info)
|
96 | params = includeRelationships(params, info, info.fragments)
|
97 | const formatParam = value => value.toLowerCase().replace(/ /g, '')
|
98 | params.type = params.type.map(formatParam)
|
99 | params.status = params.status.map(formatParam)
|
100 | let request
|
101 | if (discID) {
|
102 | request = loaders.lookup.load(['discid', discID, params])
|
103 |
|
104 |
|
105 | if (params.inc) {
|
106 | params.inc = params.inc.filter(value => {
|
107 | return value !== 'media' && value !== 'discids'
|
108 | })
|
109 | }
|
110 | } else if (isrc) {
|
111 | request = loaders.lookup.load(['isrc', isrc, params])
|
112 | } else if (iswc) {
|
113 | request = loaders.lookup.load(['iswc', iswc, params])
|
114 | } else {
|
115 | request = loaders.browse.load([singularName, params])
|
116 | }
|
117 | return request.then(list => {
|
118 |
|
119 |
|
120 | const {
|
121 | [pluralName]: arraySlice,
|
122 | [`${singularName}-offset`]: sliceStart = 0,
|
123 | [`${singularName}-count`]: arrayLength = arraySlice.length
|
124 | } = list
|
125 | const meta = { sliceStart, arrayLength }
|
126 | const connection = connectionFromArraySlice(
|
127 | arraySlice,
|
128 | { first, after },
|
129 | meta
|
130 | )
|
131 | return {
|
132 | nodes: connection.edges.map(edge => edge.node),
|
133 | totalCount: arrayLength,
|
134 | ...connection
|
135 | }
|
136 | })
|
137 | }
|
138 |
|
139 | export function resolveSearch(
|
140 | root,
|
141 | { after, first, query, ...args },
|
142 | { loaders },
|
143 | info
|
144 | ) {
|
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(
|
161 | arraySlice,
|
162 | { first, after },
|
163 | meta
|
164 | )
|
165 |
|
166 |
|
167 | const edges = connection.edges.map(edge => ({
|
168 | ...edge,
|
169 | score: +edge.node.score
|
170 | }))
|
171 | const connectionWithExtras = {
|
172 | nodes: edges.map(edge => edge.node),
|
173 | totalCount: arrayLength,
|
174 | ...connection,
|
175 | edges
|
176 | }
|
177 | return connectionWithExtras
|
178 | })
|
179 | }
|
180 |
|
181 | export function resolveRelationship(rels, args, context, info) {
|
182 | const targetType = toDashed(toSingular(info.fieldName)).replace('-', '_')
|
183 | let matches = rels.filter(rel => rel['target-type'] === targetType)
|
184 |
|
185 | if (args.direction != null) {
|
186 | matches = matches.filter(rel => rel.direction === args.direction)
|
187 | }
|
188 | if (args.type != null) {
|
189 | matches = matches.filter(rel => rel.type === args.type)
|
190 | }
|
191 | if (args.typeID != null) {
|
192 | matches = matches.filter(rel => rel['type-id'] === args.typeID)
|
193 | }
|
194 | const connection = connectionFromArray(matches, args)
|
195 | return {
|
196 | nodes: connection.edges.map(edge => edge.node),
|
197 | totalCount: matches.length,
|
198 | ...connection
|
199 | }
|
200 | }
|
201 |
|
202 | export function resolveLinked(entity, args, context, info) {
|
203 | const parentEntity = toDashed(info.parentType.name)
|
204 | args = { ...args, [parentEntity]: entity.id }
|
205 | return resolveBrowse(entity, args, context, info)
|
206 | }
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 | export function createSubqueryResolver(
|
214 | { inc, key } = {},
|
215 | handler = value => value
|
216 | ) {
|
217 | return (entity, args, { loaders }, info) => {
|
218 | key = key || toDashed(info.fieldName)
|
219 | let promise
|
220 | if (key in entity) {
|
221 | promise = Promise.resolve(entity)
|
222 | } else {
|
223 | const { _type: entityType, id } = entity
|
224 | const params = { inc: [inc || key] }
|
225 | promise = loaders.lookup.load([entityType, id, params])
|
226 | }
|
227 | return promise.then(entity => handler(entity[key], args))
|
228 | }
|
229 | }
|
230 |
|
231 | export function resolveDiscReleases(disc, args, context, info) {
|
232 | const { releases } = disc
|
233 | if (releases != null) {
|
234 | const connection = connectionFromArray(releases, args)
|
235 | return {
|
236 | nodes: connection.edges.map(edge => edge.node),
|
237 | totalCount: releases.length,
|
238 | ...connection
|
239 | }
|
240 | }
|
241 | args = { ...args, discID: disc.id }
|
242 | return resolveBrowse(disc, args, context, info)
|
243 | }
|