2.0.0-rc.4 (async injections)

This commit is contained in:
Tobe O 2019-04-17 11:15:46 -04:00
parent 106a5683dd
commit 09ff68f5ad
4 changed files with 54 additions and 12 deletions

View file

@ -1,3 +1,7 @@
# 2.0.0-rc.4
* Support resolution of asynchronous injections in controllers and `ioc`.
* Inject `RequestContext` and `ResponseContext` into requests.
# 2.0.0-rc.3
* `MapService.modify` was not actually modifying items.

View file

@ -122,6 +122,8 @@ abstract class Driver<
req.params.addAll(tuple.item2);
req.container
..registerSingleton<RequestContext>(req)
..registerSingleton<ResponseContext>(res)
..registerSingleton<MiddlewarePipeline>(tuple.item4)
..registerSingleton<MiddlewarePipeline<RequestHandler>>(line)
..registerSingleton<MiddlewarePipelineIterator>(it)

View file

@ -24,7 +24,7 @@ RequestHandler ioc(Function handler, {Iterable<String> optional = const []}) {
resolveInjection(requirement, InjectionRequest injection, RequestContext req,
ResponseContext res, bool throwOnUnresolved,
[Container container]) {
[Container container]) async {
var propFromApp;
container ??= req?.container ?? res?.app?.container;
@ -60,12 +60,19 @@ resolveInjection(requirement, InjectionRequest injection, RequestContext req,
if (req.params.containsKey(key) ||
req.app.configuration.containsKey(key) ||
_primitiveTypes.contains(type)) {
return resolveInjection(
return await resolveInjection(
key, injection, req, res, throwOnUnresolved, container);
} else
return resolveInjection(
return await resolveInjection(
type, injection, req, res, throwOnUnresolved, container);
} else if (requirement is Type && requirement != dynamic) {
try {
var futureType = container.reflector.reflectFutureOf(requirement);
return await container.make(futureType.reflectedType);
} on UnsupportedError {
// Ignore this; it just means that the reflector doesn't support futures.
}
return container.make(requirement);
} else if (throwOnUnresolved) {
throw new ArgumentError(
@ -86,7 +93,7 @@ bool suitableForInjection(
/// Handles a request with a DI-enabled handler.
RequestHandler handleContained(Function handler, InjectionRequest injection,
[Container container]) {
return (RequestContext req, ResponseContext res) {
return (RequestContext req, ResponseContext res) async {
if (injection.parameters.isNotEmpty &&
injection.parameters.values.any((p) => p.match != null) &&
!suitableForInjection(req, res, injection))
@ -95,14 +102,16 @@ RequestHandler handleContained(Function handler, InjectionRequest injection,
List args = [];
Map<Symbol, dynamic> named = {};
args.addAll(injection.required
.map((r) => resolveInjection(r, injection, req, res, true, container)));
injection.named.forEach((k, v) {
var name = new Symbol(k);
named[name] =
resolveInjection([k, v], injection, req, res, false, container);
});
for (var r in injection.required) {
args.add(await resolveInjection(r, injection, req, res, true, container));
}
for (var entry in injection.named.entries) {
var name = new Symbol(entry.key);
named[name] = await resolveInjection(
[entry.key, entry.value], injection, req, res, false, container);
}
return Function.apply(handler, args, named);
};

View file

@ -1,6 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:angel_container/angel_container.dart';
import 'package:angel_framework/http.dart';
import 'package:angel_container/mirrors.dart';
@ -26,12 +26,18 @@ main() {
// Inject some todos
app.container.registerSingleton(new Todo(text: TEXT, over: OVER));
app.container.registerFactory<Future<Foo>>((container) async {
var req = container.make<RequestContext>();
var text = await req.body.transform(utf8.decoder).join();
return Foo(text);
});
app.get("/errands", ioc((Todo singleton) => singleton));
app.get(
"/errands3",
ioc(({Errand singleton, Todo foo, RequestContext req}) =>
singleton.text));
app.post('/async', ioc((Foo foo) => {'baz': foo.bar}));
await app.configure(new SingletonController().configureServer);
await app.configure(new ErrandController().configureServer);
@ -82,6 +88,16 @@ main() {
var text = await json.decode(response.body) as String;
expect(text, equals(TEXT));
});
test('resolve from future in controller', () async {
var response = await client.post('$url/errands4/async', body: 'hey');
expect(response.body, json.encode({'bar': 'hey'}));
});
test('resolve from future in route', () async {
var response = await client.post('$url/async', body: 'yes');
expect(response.body, json.encode({'baz': 'yes'}));
});
}
void validateTodoSingleton(response) {
@ -103,6 +119,17 @@ class ErrandController extends Controller {
errand(Errand errand) {
return errand.text;
}
@Expose('/async', method: 'POST')
asyncResolve(Foo foo) {
return {'bar': foo.bar};
}
}
class Foo {
final String bar;
Foo(this.bar);
}
class Errand {