-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathquery.js
More file actions
126 lines (91 loc) · 4.48 KB
/
query.js
File metadata and controls
126 lines (91 loc) · 4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const _ = require('lodash');
const { resolver, argsToFindOptions } = require('graphql-sequelize');
const { EXPECTED_OPTIONS_KEY } = require('dataloader-sequelize');
const hooks = require('./hooks');
const { getIncludes, getOrderBy } = require('../utils');
const QUERY_TYPE = 'fetch';
module.exports = (options) => {
const { dataloaderContext, limits, globalHooks, models } = options;
return async (model, source, args, context, info, queryOptions) => {
const isAssociation = Boolean(model.target);
const realModel = isAssociation ? model.target : model;
const graphql = realModel.graphql;
const { simpleAST, permissions } = queryOptions;
const includes = getIncludes(simpleAST, realModel.name, models);
// setup dataloader for resolver.
resolver.contextToOptions = { [EXPECTED_OPTIONS_KEY]: EXPECTED_OPTIONS_KEY };
context[EXPECTED_OPTIONS_KEY] = dataloaderContext;
if (!isAssociation) {
args.limit = args.limit || (limits.default !== 0 && limits.default) || undefined;
args.limit = (limits.max !== 0 && args.limit > limits.max) ? limits.max : args.limit;
}
// No need to call authorizer again on associations
if (!isAssociation) await options.authorizer(source, args, context, info);
if (globalHooks.before.fetch) {
await globalHooks.before.fetch(source, args, context, info);
}
// query being overwritten at graphql.overwrite.fetch, run it and skip the rest
if (_.has(graphql.overwrite, QUERY_TYPE)) {
return graphql.overwrite[QUERY_TYPE](source, args, context, info);
}
// hook coming from graphql.before.fetch
const beforeHookResponse = await hooks.before(isAssociation ? model.target : model, source, args, context, info, QUERY_TYPE);
if (beforeHookResponse) {
return beforeHookResponse;
}
// see if a scope is specified to be applied to find queries.
const variablePath = { args, context, ctx: context };
// sequelize-graphql before hook to parse orderby clause to make sure it supports multiple orderby
const before = (findOptions, args) => {
// hook coming from graphql.find.before
if (model.graphql?.find?.before) {
model.graphql.find.before(findOptions, args, context);
}
if (isAssociation && model.through) {
findOptions.through = {
attributes: Object.keys(model.through.model.rawAttributes)
};
}
if (args.throughWhere) {
findOptions.where = argsToFindOptions.default({ where: args.throughWhere }, Object.keys(model.through.model.rawAttributes));
}
const order = getOrderBy(args.order);
findOptions.order = order.length ? order : undefined;
// if paranoid option from sequelize is set, this switch can be used to fetch archived, non-archived or all items.
findOptions.paranoid = ((args.where && args.where.deletedAt && args.where.deletedAt.ne === null) || args.fetchDeleted) ? false : model.options.paranoid;
if (includes.length) {
findOptions.include = includes;
}
if (!isAssociation && permissions?.conditions) {
const clauses = permissions.conditions.reduce((all, condition) => {
if (typeof condition.value === 'string' && condition.value.startsWith(':')) {
all[condition.field] = _.get(variablePath, condition.value.replace(':', ''));
} else {
all[condition.field] = condition.value;
}
return all;
}, {});
findOptions.where = {...(findOptions.where || {}), ...clauses};
}
findOptions.gqlContext = context;
return findOptions;
};
const after = model.graphql?.find?.after;
const scope = Array.isArray(graphql.scopes) ? { method: [graphql.scopes[0], _.get(variablePath, graphql.scopes[1], graphql.scopes[2] || null)] } : graphql.scopes;
const resolverOptions = {
before,
after,
separate: isAssociation,
};
const data = await resolver((isAssociation ? model : model.scope(scope)), resolverOptions)(source, args, context, info);
if (_.has(graphql.extend, QUERY_TYPE) || _.has(graphql.after, QUERY_TYPE)) {
await (graphql.extend || graphql.after)[QUERY_TYPE](data, source, args, context, info);
}
if ((globalHooks.extend || globalHooks.extend || {}).fetch) {
await (globalHooks.extend || globalHooks.extend).fetch(data, source, args, context, info);
}
// Logger only runs for base query.
if (!isAssociation) await options.logger(data, source, args, context, info);
return data;
};
};