From 09ff68f5adeb21adf5c5e4785a1eb5a89de4b9bd Mon Sep 17 00:00:00 2001 From: Tobe O Date: Wed, 17 Apr 2019 11:15:46 -0400 Subject: [PATCH] 2.0.0-rc.4 (async injections) --- CHANGELOG.md | 4 ++++ lib/src/core/driver.dart | 2 ++ lib/src/core/injection.dart | 31 ++++++++++++++++++++----------- test/di_test.dart | 29 ++++++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad7599d6..56c07b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/lib/src/core/driver.dart b/lib/src/core/driver.dart index e49a8ab1..fdb75c39 100644 --- a/lib/src/core/driver.dart +++ b/lib/src/core/driver.dart @@ -122,6 +122,8 @@ abstract class Driver< req.params.addAll(tuple.item2); req.container + ..registerSingleton(req) + ..registerSingleton(res) ..registerSingleton(tuple.item4) ..registerSingleton>(line) ..registerSingleton(it) diff --git a/lib/src/core/injection.dart b/lib/src/core/injection.dart index ededfb9b..9eb26d66 100644 --- a/lib/src/core/injection.dart +++ b/lib/src/core/injection.dart @@ -24,7 +24,7 @@ RequestHandler ioc(Function handler, {Iterable 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 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); }; diff --git a/test/di_test.dart b/test/di_test.dart index 00888dc7..ea7205cb 100644 --- a/test/di_test.dart +++ b/test/di_test.dart @@ -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>((container) async { + var req = container.make(); + 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 {