Skip to content

Commit b49beb1

Browse files
janmeiermickhansen
authored andcommitted
add(resolver): Allow async before and after (#230)
add(resolver): Allow async before and after
1 parent 6194587 commit b49beb1

File tree

3 files changed

+137
-92
lines changed

3 files changed

+137
-92
lines changed

src/generateIncludes.js

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@ export default function generateIncludes(simpleAST, type, context, options) {
1212
type = type.ofType || type;
1313
options = options || {};
1414

15-
Object.keys(simpleAST.fields).forEach(function (key) {
15+
return Promise.all(Object.keys(simpleAST.fields).map(function (key) {
1616
var association
1717
, fieldAST = simpleAST.fields[key]
1818
, name = fieldAST.key || key
1919
, fieldType = type._fields[name] && type._fields[name].type
2020
, includeOptions
2121
, args = fieldAST.args
2222
, includeResolver = type._fields[name].resolve
23-
, nestedResult
2423
, allowedAttributes
2524
, include;
2625

@@ -38,22 +37,21 @@ export default function generateIncludes(simpleAST, type, context, options) {
3837
}
3938

4039
if (!fieldAST) {
41-
// No point in ncluding if no fields have been asked for
40+
// No point in including if no fields have been asked for
4241
return;
4342
}
4443

4544
if (includeResolver.$passthrough) {
46-
var dummyResult = generateIncludes(
45+
return generateIncludes(
4746
fieldAST,
4847
fieldType,
4948
context,
5049
options
51-
);
52-
53-
result.include = result.include.concat(dummyResult.include);
54-
result.attributes = result.attributes.concat(dummyResult.attributes);
55-
result.order = result.order.concat(dummyResult.order);
56-
return;
50+
).then(function (dummyResult) {
51+
result.include = result.include.concat(dummyResult.include);
52+
result.attributes = result.attributes.concat(dummyResult.attributes);
53+
result.order = result.order.concat(dummyResult.order);
54+
});
5755
}
5856

5957
association = includeResolver.$association;
@@ -63,67 +61,69 @@ export default function generateIncludes(simpleAST, type, context, options) {
6361
includeOptions = argsToFindOptions(args, association.target);
6462
allowedAttributes = Object.keys(association.target.rawAttributes);
6563

66-
6764
if (options.filterAttributes) {
6865
includeOptions.attributes = (includeOptions.attributes || [])
69-
.concat(Object.keys(fieldAST.fields).map(key => fieldAST.fields[key].key || key))
70-
.filter(inList.bind(null, allowedAttributes));
66+
.concat(Object.keys(fieldAST.fields).map(key => fieldAST.fields[key].key || key))
67+
.filter(inList.bind(null, allowedAttributes));
7168
} else {
7269
includeOptions.attributes = allowedAttributes;
7370
}
7471

75-
if (includeResolver.$before) {
76-
includeOptions = includeResolver.$before(includeOptions, args, context, {
77-
ast: fieldAST,
78-
type: type
79-
});
80-
}
72+
return Promise.resolve().then(function () {
73+
if (includeResolver.$before) {
74+
return includeResolver.$before(includeOptions, args, context, {
75+
ast: fieldAST,
76+
type: type
77+
});
78+
}
79+
return includeOptions;
80+
}).then(function (includeOptions) {
81+
if (association.associationType === 'BelongsTo') {
82+
result.attributes.push(association.foreignKey);
83+
} else if (association.source.primaryKeyAttribute) {
84+
result.attributes.push(association.source.primaryKeyAttribute);
85+
}
8186

82-
if (association.associationType === 'BelongsTo') {
83-
result.attributes.push(association.foreignKey);
84-
} else if (association.source.primaryKeyAttribute) {
85-
result.attributes.push(association.source.primaryKeyAttribute);
86-
}
87+
let separate = includeOptions.limit && association.associationType === 'HasMany';
8788

88-
let separate = includeOptions.limit && association.associationType === 'HasMany';
89+
if (include && (!includeOptions.limit || separate)) {
90+
if (includeOptions.order && !separate) {
91+
includeOptions.order.map(function (order) {
92+
order.unshift({
93+
model: association.target,
94+
as: association.options.as
95+
});
8996

90-
if (include && (!includeOptions.limit || separate)) {
91-
if (includeOptions.order && !separate) {
92-
includeOptions.order.map(function (order) {
93-
order.unshift({
94-
model: association.target,
95-
as: association.options.as
97+
return order;
9698
});
9799

98-
return order;
99-
});
100-
101-
result.order = (result.order || []).concat(includeOptions.order);
102-
delete includeOptions.order;
103-
}
100+
result.order = (result.order || []).concat(includeOptions.order);
101+
delete includeOptions.order;
102+
}
104103

105-
if (association.target.primaryKeyAttribute) {
106-
includeOptions.attributes.push(association.target.primaryKeyAttribute);
107-
}
108-
109-
if (association.associationType === 'HasMany') {
110-
includeOptions.attributes.push(association.foreignKey);
111-
}
104+
if (association.target.primaryKeyAttribute) {
105+
includeOptions.attributes.push(association.target.primaryKeyAttribute);
106+
}
112107

113-
nestedResult = generateIncludes(
114-
fieldAST,
115-
fieldType,
116-
context,
117-
includeResolver.$options
118-
);
108+
if (association.associationType === 'HasMany') {
109+
includeOptions.attributes.push(association.foreignKey);
110+
}
119111

120-
includeOptions.include = (includeOptions.include || []).concat(nestedResult.include);
121-
includeOptions.attributes = _.uniq(includeOptions.attributes.concat(nestedResult.attributes));
112+
return generateIncludes(
113+
fieldAST,
114+
fieldType,
115+
context,
116+
includeResolver.$options
117+
).then(function (nestedResult) {
118+
includeOptions.include = (includeOptions.include || []).concat(nestedResult.include);
119+
includeOptions.attributes = _.uniq(includeOptions.attributes.concat(nestedResult.attributes));
122120

123-
result.include.push(_.assign({association: association}, includeOptions));
124-
}
121+
result.include.push(_.assign({association: association}, includeOptions));
122+
});
123+
}
124+
});
125125
}
126+
})).then(function () {
127+
return result;
126128
});
127-
128-
return result;
129129
}

src/resolver.js

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ function resolverFactory(target, options) {
4040
var ast = info.fieldASTs
4141
, type = info.returnType
4242
, list = options.list || type instanceof GraphQLList
43-
, includeResult
4443
, simpleAST = simplifyAST(ast[0], info)
4544
, fields = simpleAST.fields
4645
, findOptions = argsToFindOptions(args, model);
@@ -86,50 +85,44 @@ function resolverFactory(target, options) {
8685
findOptions.attributes.push(model.primaryKeyAttribute);
8786
}
8887

89-
includeResult = generateIncludes(
88+
return generateIncludes(
9089
simpleAST,
9190
type,
9291
context,
9392
options
94-
);
95-
96-
findOptions.include = includeResult.include;
97-
if (includeResult.order) {
98-
findOptions.order = (findOptions.order || []).concat(includeResult.order);
99-
}
100-
findOptions.attributes = _.uniq(findOptions.attributes.concat(includeResult.attributes));
101-
102-
findOptions.root = context;
103-
findOptions.context = context;
104-
findOptions.logging = findOptions.logging || context.logging;
105-
106-
findOptions = options.before(findOptions, args, context, {
107-
...info,
108-
ast: simpleAST,
109-
type: type,
110-
source: source
111-
});
93+
).then(function (includeResult) {
94+
findOptions.include = includeResult.include;
95+
if (includeResult.order) {
96+
findOptions.order = (findOptions.order || []).concat(includeResult.order);
97+
}
98+
findOptions.attributes = _.uniq(findOptions.attributes.concat(includeResult.attributes));
11299

113-
if (!findOptions.order) {
114-
findOptions.order = [model.primaryKeyAttribute, 'ASC'];
115-
}
100+
findOptions.root = context;
101+
findOptions.context = context;
102+
findOptions.logging = findOptions.logging || context.logging;
116103

104+
return options.before(findOptions, args, context, {
105+
...info,
106+
ast: simpleAST,
107+
type: type,
108+
source: source
109+
});
110+
}).then(function (findOptions) {
111+
if (!findOptions.order) {
112+
findOptions.order = [model.primaryKeyAttribute, 'ASC'];
113+
}
117114

118-
if (association) {
119-
return source[association.accessors.get](findOptions).then(function (result) {
120-
if (options.handleConnection && isConnection(info.returnType)) {
121-
result = handleConnection(result, args);
122-
}
123-
return options.after(result, args, context, {
124-
...info,
125-
ast: simpleAST,
126-
type: type,
127-
source: source
115+
if (association) {
116+
return source[association.accessors.get](findOptions).then(function (result) {
117+
if (options.handleConnection && isConnection(info.returnType)) {
118+
return handleConnection(result, args);
119+
}
120+
return result;
128121
});
129-
});
130-
}
122+
}
131123

132-
return model[list ? 'findAll' : 'findOne'](findOptions).then(function (result) {
124+
return model[list ? 'findAll' : 'findOne'](findOptions);
125+
}).then(function (result) {
133126
return options.after(result, args, context, {
134127
...info,
135128
ast: simpleAST,

test/integration/resolver.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,58 @@ describe('resolver', function () {
10391039
});
10401040
});
10411041

1042+
it('should allow async before and after', function () {
1043+
var users = this.users
1044+
, schema;
1045+
1046+
schema = new GraphQLSchema({
1047+
query: new GraphQLObjectType({
1048+
name: 'RootQueryType',
1049+
fields: {
1050+
users: {
1051+
type: new GraphQLList(userType),
1052+
args: {
1053+
limit: {
1054+
type: GraphQLInt
1055+
},
1056+
order: {
1057+
type: GraphQLString
1058+
}
1059+
},
1060+
resolve: resolver(User, {
1061+
before: function (options) {
1062+
return Promise.resolve(options);
1063+
},
1064+
after: async function (result) {
1065+
await Promise.delay(100);
1066+
return result.map(function () {
1067+
return {
1068+
name: 'Delayed!'
1069+
};
1070+
});
1071+
}
1072+
})
1073+
}
1074+
}
1075+
})
1076+
});
1077+
1078+
return graphql(schema, `
1079+
{
1080+
users {
1081+
name
1082+
}
1083+
}
1084+
`).then(function (result) {
1085+
if (result.errors) throw new Error(result.errors[0].stack);
1086+
1087+
expect(result.data.users).to.have.length(users.length);
1088+
result.data.users.forEach(function (user) {
1089+
expect(user.name).to.equal('Delayed!');
1090+
});
1091+
});
1092+
});
1093+
10421094
describe('filterAttributes', function () {
10431095
beforeEach(function () {
10441096
this.defaultValue = resolver.filterAttributes;

0 commit comments

Comments
 (0)