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 # 2.0.0-rc.3
* `MapService.modify` was not actually modifying items. * `MapService.modify` was not actually modifying items.

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:angel_container/angel_container.dart'; import 'package:angel_container/angel_container.dart';
import 'package:angel_framework/http.dart'; import 'package:angel_framework/http.dart';
import 'package:angel_container/mirrors.dart'; import 'package:angel_container/mirrors.dart';
@ -26,12 +26,18 @@ main() {
// Inject some todos // Inject some todos
app.container.registerSingleton(new Todo(text: TEXT, over: OVER)); 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("/errands", ioc((Todo singleton) => singleton));
app.get( app.get(
"/errands3", "/errands3",
ioc(({Errand singleton, Todo foo, RequestContext req}) => ioc(({Errand singleton, Todo foo, RequestContext req}) =>
singleton.text)); singleton.text));
app.post('/async', ioc((Foo foo) => {'baz': foo.bar}));
await app.configure(new SingletonController().configureServer); await app.configure(new SingletonController().configureServer);
await app.configure(new ErrandController().configureServer); await app.configure(new ErrandController().configureServer);
@ -82,6 +88,16 @@ main() {
var text = await json.decode(response.body) as String; var text = await json.decode(response.body) as String;
expect(text, equals(TEXT)); 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) { void validateTodoSingleton(response) {
@ -103,6 +119,17 @@ class ErrandController extends Controller {
errand(Errand errand) { errand(Errand errand) {
return errand.text; return errand.text;
} }
@Expose('/async', method: 'POST')
asyncResolve(Foo foo) {
return {'bar': foo.bar};
}
}
class Foo {
final String bar;
Foo(this.bar);
} }
class Errand { class Errand {