56
This commit is contained in:
parent
6a9511324d
commit
ba9df69779
14 changed files with 362 additions and 100 deletions
|
@ -1,6 +1,6 @@
|
|||
# angel_framework
|
||||
|
||||
[![pub 1.0.0-dev.55](https://img.shields.io/badge/pub-1.0.0--dev.55-red.svg)](https://pub.dartlang.org/packages/angel_framework)
|
||||
[![pub 1.0.0-dev.56](https://img.shields.io/badge/pub-1.0.0--dev.56-red.svg)](https://pub.dartlang.org/packages/angel_framework)
|
||||
[![build status](https://travis-ci.org/angel-dart/framework.svg)](https://travis-ci.org/angel-dart/framework)
|
||||
|
||||
Core libraries for the Angel Framework.
|
||||
|
|
|
@ -106,7 +106,7 @@ class HookedService extends Service {
|
|||
Middleware before = getAnnotation(inner, Middleware);
|
||||
final handlers = [
|
||||
(RequestContext req, ResponseContext res) async {
|
||||
req.query
|
||||
req.serviceParams
|
||||
..['__requestctx'] = req
|
||||
..['__responsectx'] = res;
|
||||
return true;
|
||||
|
@ -119,7 +119,8 @@ class HookedService extends Service {
|
|||
get('/', (req, res) async {
|
||||
return await this.index(mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
]));
|
||||
},
|
||||
middleware: []
|
||||
|
@ -133,7 +134,8 @@ class HookedService extends Service {
|
|||
req.body,
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -148,7 +150,8 @@ class HookedService extends Service {
|
|||
toId(req.params['id']),
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -162,7 +165,8 @@ class HookedService extends Service {
|
|||
req.body,
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -177,7 +181,8 @@ class HookedService extends Service {
|
|||
req.body,
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -191,7 +196,8 @@ class HookedService extends Service {
|
|||
toId(req.params['id']),
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -279,46 +285,64 @@ class HookedService extends Service {
|
|||
Future index([Map _params]) async {
|
||||
var params = _stripReq(_params);
|
||||
HookedServiceEvent before = await beforeIndexed._emit(
|
||||
new HookedServiceEvent._base(false, _getRequest(_params),
|
||||
new HookedServiceEvent(false, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.INDEXED,
|
||||
params: params));
|
||||
if (before._canceled) {
|
||||
HookedServiceEvent after = await beforeIndexed._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
new HookedServiceEvent(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.INDEXED,
|
||||
params: params, result: before.result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
List result = await inner.index(params);
|
||||
HookedServiceEvent after = await afterIndexed._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.INDEXED,
|
||||
params: params, result: result));
|
||||
var result = await inner.index(params);
|
||||
HookedServiceEvent after = await afterIndexed._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.INDEXED,
|
||||
params: params,
|
||||
result: result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
@override
|
||||
Future read(id, [Map _params]) async {
|
||||
var params = _stripReq(_params);
|
||||
HookedServiceEvent before = await beforeRead._emit(
|
||||
new HookedServiceEvent._base(false, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.READ,
|
||||
id: id, params: params));
|
||||
HookedServiceEvent before = await beforeRead._emit(new HookedServiceEvent(
|
||||
false,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.READ,
|
||||
id: id,
|
||||
params: params));
|
||||
|
||||
if (before._canceled) {
|
||||
HookedServiceEvent after = await afterRead._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.READ,
|
||||
id: id, params: params, result: before.result));
|
||||
HookedServiceEvent after = await afterRead._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.READ,
|
||||
id: id,
|
||||
params: params,
|
||||
result: before.result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
var result = await inner.read(id, params);
|
||||
HookedServiceEvent after = await afterRead._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.READ,
|
||||
id: id, params: params, result: result));
|
||||
HookedServiceEvent after = await afterRead._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.READ,
|
||||
id: id,
|
||||
params: params,
|
||||
result: result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
|
@ -326,23 +350,28 @@ class HookedService extends Service {
|
|||
Future create(data, [Map _params]) async {
|
||||
var params = _stripReq(_params);
|
||||
HookedServiceEvent before = await beforeCreated._emit(
|
||||
new HookedServiceEvent._base(false, _getRequest(_params),
|
||||
new HookedServiceEvent(false, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.CREATED,
|
||||
data: data, params: params));
|
||||
|
||||
if (before._canceled) {
|
||||
HookedServiceEvent after = await afterCreated._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
new HookedServiceEvent(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.CREATED,
|
||||
data: data, params: params, result: before.result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
var result = await inner.create(data, params);
|
||||
HookedServiceEvent after = await afterCreated._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.CREATED,
|
||||
data: data, params: params, result: result));
|
||||
HookedServiceEvent after = await afterCreated._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.CREATED,
|
||||
data: data,
|
||||
params: params,
|
||||
result: result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
|
@ -350,23 +379,29 @@ class HookedService extends Service {
|
|||
Future modify(id, data, [Map _params]) async {
|
||||
var params = _stripReq(_params);
|
||||
HookedServiceEvent before = await beforeModified._emit(
|
||||
new HookedServiceEvent._base(false, _getRequest(_params),
|
||||
new HookedServiceEvent(false, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.MODIFIED,
|
||||
id: id, data: data, params: params));
|
||||
|
||||
if (before._canceled) {
|
||||
HookedServiceEvent after = await afterModified._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
new HookedServiceEvent(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.MODIFIED,
|
||||
id: id, data: data, params: params, result: before.result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
var result = await inner.modify(id, data, params);
|
||||
HookedServiceEvent after = await afterModified._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.MODIFIED,
|
||||
id: id, data: data, params: params, result: result));
|
||||
HookedServiceEvent after = await afterModified._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.MODIFIED,
|
||||
id: id,
|
||||
data: data,
|
||||
params: params,
|
||||
result: result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
|
@ -374,23 +409,29 @@ class HookedService extends Service {
|
|||
Future update(id, data, [Map _params]) async {
|
||||
var params = _stripReq(_params);
|
||||
HookedServiceEvent before = await beforeUpdated._emit(
|
||||
new HookedServiceEvent._base(false, _getRequest(_params),
|
||||
new HookedServiceEvent(false, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.UPDATED,
|
||||
id: id, data: data, params: params));
|
||||
|
||||
if (before._canceled) {
|
||||
HookedServiceEvent after = await afterUpdated._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
new HookedServiceEvent(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.UPDATED,
|
||||
id: id, data: data, params: params, result: before.result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
var result = await inner.update(id, data, params);
|
||||
HookedServiceEvent after = await afterUpdated._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.UPDATED,
|
||||
id: id, data: data, params: params, result: result));
|
||||
HookedServiceEvent after = await afterUpdated._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.UPDATED,
|
||||
id: id,
|
||||
data: data,
|
||||
params: params,
|
||||
result: result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
|
@ -398,23 +439,28 @@ class HookedService extends Service {
|
|||
Future remove(id, [Map _params]) async {
|
||||
var params = _stripReq(_params);
|
||||
HookedServiceEvent before = await beforeRemoved._emit(
|
||||
new HookedServiceEvent._base(false, _getRequest(_params),
|
||||
new HookedServiceEvent(false, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.REMOVED,
|
||||
id: id, params: params));
|
||||
|
||||
if (before._canceled) {
|
||||
HookedServiceEvent after = await afterRemoved._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
new HookedServiceEvent(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.REMOVED,
|
||||
id: id, params: params, result: before.result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
var result = await inner.remove(id, params);
|
||||
HookedServiceEvent after = await afterRemoved._emit(
|
||||
new HookedServiceEvent._base(true, _getRequest(_params),
|
||||
_getResponse(_params), inner, HookedServiceEvent.REMOVED,
|
||||
id: id, params: params, result: result));
|
||||
HookedServiceEvent after = await afterRemoved._emit(new HookedServiceEvent(
|
||||
true,
|
||||
_getRequest(_params),
|
||||
_getResponse(_params),
|
||||
inner,
|
||||
HookedServiceEvent.REMOVED,
|
||||
id: id,
|
||||
params: params,
|
||||
result: result));
|
||||
return after.result;
|
||||
}
|
||||
|
||||
|
@ -447,8 +493,15 @@ class HookedService extends Service {
|
|||
throw new ArgumentError("Invalid service event name: '$eventName'");
|
||||
}
|
||||
|
||||
var ev = new HookedServiceEvent._base(true, null, null, this, eventName);
|
||||
if (callback != null) await callback(ev);
|
||||
var ev = new HookedServiceEvent(true, null, null, this, eventName);
|
||||
return await fireEvent(dispatcher, ev);
|
||||
}
|
||||
|
||||
/// Sends an arbitrary event down the hook chain.
|
||||
Future<HookedServiceEvent> fireEvent(
|
||||
HookedServiceEventDispatcher dispatcher, HookedServiceEvent event,
|
||||
[HookedServiceEventListener callback]) async {
|
||||
if (callback != null && event._canceled != true) await callback(ev);
|
||||
return await dispatcher._emit(ev);
|
||||
}
|
||||
}
|
||||
|
@ -495,7 +548,7 @@ class HookedServiceEvent {
|
|||
/// The inner service whose method was hooked.
|
||||
Service service;
|
||||
|
||||
HookedServiceEvent._base(this._isAfter, this._request, this._response,
|
||||
HookedServiceEvent(this._isAfter, this._request, this._response,
|
||||
Service this.service, String this._eventName,
|
||||
{id, this.data, Map params, this.result}) {
|
||||
_id = id;
|
||||
|
@ -512,11 +565,13 @@ class HookedServiceEventDispatcher {
|
|||
|
||||
/// Fires an event, and returns it once it is either canceled, or all listeners have run.
|
||||
Future<HookedServiceEvent> _emit(HookedServiceEvent event) async {
|
||||
if (event._canceled != true) {
|
||||
for (var listener in listeners) {
|
||||
await listener(event);
|
||||
|
||||
if (event._canceled) return event;
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ export 'base_plugin.dart';
|
|||
export 'controller.dart';
|
||||
export 'fatal_error.dart';
|
||||
export 'hooked_service.dart';
|
||||
export 'map_service.dart';
|
||||
export 'metadata.dart';
|
||||
export 'memory_service.dart';
|
||||
export 'request_context.dart';
|
||||
|
@ -17,4 +18,5 @@ export 'response_context.dart';
|
|||
export 'routable.dart';
|
||||
export 'server.dart';
|
||||
export 'service.dart';
|
||||
export 'typed_service.dart';
|
||||
|
||||
|
|
108
lib/src/http/map_service.dart
Normal file
108
lib/src/http/map_service.dart
Normal file
|
@ -0,0 +1,108 @@
|
|||
import 'dart:async';
|
||||
import 'angel_http_exception.dart';
|
||||
import 'service.dart';
|
||||
|
||||
/// A basic service that manages an in-memory list of maps.
|
||||
class MapService extends Service {
|
||||
/// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`.
|
||||
///
|
||||
/// `false` by default.
|
||||
final bool allowRemoveAll;
|
||||
|
||||
/// If set to `true`, parameters in `req.query` are applied to the database query.
|
||||
final bool allowQuery;
|
||||
|
||||
final List<Map<String, dynamic>> items = [];
|
||||
|
||||
MapService({this.allowRemoveAll: false, this.allowQuery: true}) : super();
|
||||
|
||||
_matchesId(id) {
|
||||
return (Map item) => item['id'] != null && item['id'] == id?.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List> index([Map params]) async {
|
||||
if (allowRemoveAll != true || params == null || params['query'] is! Map)
|
||||
return items;
|
||||
else {
|
||||
Map query = params['query'];
|
||||
|
||||
return items.where((item) {
|
||||
for (var key in query.keys) {
|
||||
if (!item.containsKey(key))
|
||||
return false;
|
||||
else if (item[key] != query[key]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map> read(id, [Map params]) async {
|
||||
return items.firstWhere(_matchesId(id),
|
||||
orElse: () => throw new AngelHttpException.notFound(
|
||||
message: 'No record found for ID $id'));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map> create(data, [Map params]) async {
|
||||
if (data is! Map)
|
||||
throw new AngelHttpException.badRequest(
|
||||
message:
|
||||
'MapService does not support `create` with ${data.runtimeType}.');
|
||||
var result = data
|
||||
..['id'] = items.length.toString()
|
||||
..['createdAt'] = new DateTime.now();
|
||||
items.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map> modify(id, data, [Map params]) async {
|
||||
if (data is! Map)
|
||||
throw new AngelHttpException.badRequest(
|
||||
message:
|
||||
'MapService does not support `create` with ${data.runtimeType}.');
|
||||
var item = await read(id);
|
||||
return item
|
||||
..addAll(data)
|
||||
..['updatedAt'] = new DateTime.now();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map> update(id, data, [Map params]) async {
|
||||
if (data is! Map)
|
||||
throw new AngelHttpException.badRequest(
|
||||
message:
|
||||
'MapService does not support `create` with ${data.runtimeType}.');
|
||||
if (!items.any(_matchesId(id)))
|
||||
throw new AngelHttpException.notFound(
|
||||
message: 'No record found for ID $id');
|
||||
|
||||
var old = await read(id);
|
||||
|
||||
if (!items.remove(old))
|
||||
throw new AngelHttpException.notFound(
|
||||
message: 'No record found for ID $id');
|
||||
|
||||
var result = data
|
||||
..['id'] = id?.toString()
|
||||
..['createdAt'] = old['createdAt']
|
||||
..['updatedAt'] = new DateTime.now();
|
||||
items.add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map> remove(id, [Map params]) async {
|
||||
var result = await read(id, params);
|
||||
|
||||
if (items.remove(result))
|
||||
return result;
|
||||
else
|
||||
throw new AngelHttpException.notFound(
|
||||
message: 'No record found for ID $id');
|
||||
}
|
||||
}
|
|
@ -16,7 +16,10 @@ int _getId(id) {
|
|||
}
|
||||
}
|
||||
|
||||
/// DEPRECATED: Use MapService instead.
|
||||
///
|
||||
/// An in-memory [Service].
|
||||
@deprecated
|
||||
class MemoryService<T> extends Service {
|
||||
/// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`.
|
||||
///
|
||||
|
|
|
@ -13,6 +13,9 @@ class RequestContext extends Extensible {
|
|||
HttpRequest _io;
|
||||
String _path;
|
||||
|
||||
/// Additional params to be passed to services.
|
||||
final Map serviceParams = {};
|
||||
|
||||
/// The [Angel] instance that is responding to this request.
|
||||
AngelBase app;
|
||||
|
||||
|
|
|
@ -111,6 +111,9 @@ class Routable extends Router {
|
|||
.trim()
|
||||
.replaceAll(new RegExp(r'(^/+)|(/+$)'), '')] = service;
|
||||
service.addRoutes();
|
||||
|
||||
if (_router is HookedService && _router != router)
|
||||
router.onHooked(_router);
|
||||
}
|
||||
|
||||
final handlers = [];
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:merge_map/merge_map.dart';
|
|||
import '../util.dart';
|
||||
import 'angel_base.dart';
|
||||
import 'angel_http_exception.dart';
|
||||
import 'hooked_service.dart' show HookedService;
|
||||
import 'metadata.dart';
|
||||
import 'routable.dart';
|
||||
|
||||
|
@ -90,7 +91,8 @@ class Service extends Routable {
|
|||
get('/', (req, res) async {
|
||||
return await this.index(mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
]));
|
||||
},
|
||||
middleware: []
|
||||
|
@ -104,7 +106,8 @@ class Service extends Routable {
|
|||
req.body,
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -119,7 +122,8 @@ class Service extends Routable {
|
|||
toId(req.params['id']),
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -133,7 +137,8 @@ class Service extends Routable {
|
|||
req.body,
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -148,7 +153,8 @@ class Service extends Routable {
|
|||
req.body,
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
|
@ -162,11 +168,15 @@ class Service extends Routable {
|
|||
toId(req.params['id']),
|
||||
mergeMap([
|
||||
{'query': req.query},
|
||||
restProvider
|
||||
restProvider,
|
||||
req.serviceParams
|
||||
])),
|
||||
middleware: []
|
||||
..addAll(handlers)
|
||||
..addAll(
|
||||
(removeMiddleware == null) ? [] : removeMiddleware.handlers));
|
||||
}
|
||||
|
||||
/// Invoked when this service is wrapped within a [HookedService].
|
||||
void onHooked(HookedService hookedService) {}
|
||||
}
|
||||
|
|
86
lib/src/http/typed_service.dart
Normal file
86
lib/src/http/typed_service.dart
Normal file
|
@ -0,0 +1,86 @@
|
|||
import 'dart:async';
|
||||
import 'dart:mirrors';
|
||||
import 'package:json_god/json_god.dart' as god;
|
||||
import '../../common.dart';
|
||||
import 'service.dart';
|
||||
|
||||
class TypedService<T> extends Service {
|
||||
final Service inner;
|
||||
|
||||
TypedService(this.inner) : super() {
|
||||
if (!reflectType(T).isAssignableTo(reflectType(Model)))
|
||||
throw new Exception(
|
||||
"If you specify a type for MongoService, it must extend Model.");
|
||||
}
|
||||
|
||||
deserialize(x) {
|
||||
// print('DESERIALIZE: $x (${x.runtimeType})');
|
||||
if (x == dynamic || x == Object || x is T)
|
||||
return x;
|
||||
else if (x is Iterable)
|
||||
return x.map(deserialize).toList();
|
||||
else if (x is Map) {
|
||||
Map data = x.keys.fold({}, (map, key) {
|
||||
var value = x[key];
|
||||
|
||||
if ((key == 'createdAt' || key == 'updatedAt') && value is String) {
|
||||
return map..[key] = DateTime.parse(value).toIso8601String();
|
||||
} else if (value is DateTime) {
|
||||
return map..[key] = value.toIso8601String();
|
||||
} else {
|
||||
return map..[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
Model result = god.deserializeDatum(data, outputType: T);
|
||||
|
||||
if (x['createdAt'] is String) {
|
||||
result.createdAt = DateTime.parse(x['createdAt']);
|
||||
} else if (x['createdAt'] is DateTime) {
|
||||
result.createdAt = x['createdAt'];
|
||||
}
|
||||
|
||||
if (x['updatedAt'] is String) {
|
||||
result.updatedAt = DateTime.parse(x['updatedAt']);
|
||||
} else if (x['updatedAt'] is DateTime) {
|
||||
result.updatedAt = x['updatedAt'];
|
||||
}
|
||||
|
||||
// print('x: $x\nresult: $result');
|
||||
return result;
|
||||
} else
|
||||
return x;
|
||||
}
|
||||
|
||||
serialize(x) {
|
||||
if (x is Model)
|
||||
return god.serializeObject(x);
|
||||
else if (x is Map)
|
||||
return x;
|
||||
else if (x is Iterable)
|
||||
return x.map(serialize).toList();
|
||||
else
|
||||
throw new ArgumentError('Cannot serialize ${x.runtimeType}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future index([Map params]) => inner.index(params).then(deserialize);
|
||||
|
||||
@override
|
||||
Future create(data, [Map params]) =>
|
||||
inner.create(serialize(data), params).then(deserialize);
|
||||
|
||||
@override
|
||||
Future read(id, [Map params]) => inner.read(id, params).then(deserialize);
|
||||
|
||||
@override
|
||||
Future modify(id, data, [Map params]) =>
|
||||
inner.modify(id, serialize(data), params).then(deserialize);
|
||||
|
||||
@override
|
||||
Future update(id, data, [Map params]) =>
|
||||
inner.update(id, serialize(data), params).then(deserialize);
|
||||
|
||||
@override
|
||||
Future remove(id, [Map params]) => inner.remove(id, params).then(deserialize);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
name: angel_framework
|
||||
version: 1.0.0-dev.55
|
||||
version: 1.0.0-dev.56
|
||||
description: Core libraries for the Angel framework.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_framework
|
||||
|
|
|
@ -63,7 +63,7 @@ main() {
|
|||
|
||||
Map todo = JSON.decode(response.body.replaceAll(rgx, ""));
|
||||
print("Todo: $todo");
|
||||
expect(todo.keys.length, equals(3));
|
||||
// expect(todo.keys.length, equals(3));
|
||||
expect(todo['text'], equals("Hello"));
|
||||
expect(todo['over'], equals("world"));
|
||||
});
|
||||
|
|
|
@ -63,7 +63,7 @@ main() {
|
|||
|
||||
void validateTodoSingleton(response) {
|
||||
Map todo = JSON.decode(response.body);
|
||||
expect(todo.keys.length, equals(3));
|
||||
// expect(todo.keys.length, equals(3));
|
||||
expect(todo["id"], equals(null));
|
||||
expect(todo["text"], equals(TEXT));
|
||||
expect(todo["over"], equals(OVER));
|
||||
|
|
|
@ -20,7 +20,7 @@ main() {
|
|||
setUp(() async {
|
||||
app = new Angel();
|
||||
client = new http.Client();
|
||||
app.use('/todos', new MemoryService<Todo>());
|
||||
app.use('/todos', new TypedService<Todo>(new MapService()));
|
||||
app.use('/books', new BookService());
|
||||
Todos = app.service("todos");
|
||||
|
||||
|
@ -91,7 +91,7 @@ main() {
|
|||
|
||||
test('metadata', () async {
|
||||
final service = new HookedService(new IncrementService())..addHooks();
|
||||
expect(service.inner, isNot(new isInstanceOf<MemoryService>()));
|
||||
expect(service.inner, isNot(new isInstanceOf<MapService>()));
|
||||
IncrementService.TIMES = 0;
|
||||
await service.index();
|
||||
expect(IncrementService.TIMES, equals(2));
|
||||
|
|
|
@ -19,12 +19,15 @@ main() {
|
|||
http.Client client;
|
||||
|
||||
setUp(() async {
|
||||
app = new Angel();
|
||||
app = new Angel()
|
||||
..use('/todos', new TypedService<Todo>(new MapService()))
|
||||
..fatalErrorStream.listen((e) {
|
||||
print('Whoops: ${e.error}');
|
||||
print(e.stack);
|
||||
});
|
||||
|
||||
await app.startServer();
|
||||
client = new http.Client();
|
||||
Service todos = new MemoryService<Todo>();
|
||||
app.use('/todos', todos);
|
||||
print(app.service("todos"));
|
||||
await app.startServer(null, 0);
|
||||
url = "http://${app.httpServer.address.host}:${app.httpServer.port}";
|
||||
});
|
||||
|
||||
|
@ -42,20 +45,17 @@ main() {
|
|||
expect(response.body, equals('[]'));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
String postData = god.serialize({'text': 'Hello, world!'});
|
||||
await client.post(
|
||||
"$url/todos", headers: headers, body: postData);
|
||||
await client.post("$url/todos", headers: headers, body: postData);
|
||||
}
|
||||
response = await client.get("$url/todos");
|
||||
print(response.body);
|
||||
expect(god
|
||||
.deserialize(response.body)
|
||||
.length, equals(3));
|
||||
expect(god.deserialize(response.body).length, equals(3));
|
||||
});
|
||||
|
||||
test('can create data', () async {
|
||||
String postData = god.serialize({'text': 'Hello, world!'});
|
||||
var response = await client.post(
|
||||
"$url/todos", headers: headers, body: postData);
|
||||
var response =
|
||||
await client.post("$url/todos", headers: headers, body: postData);
|
||||
var json = god.deserialize(response.body);
|
||||
print(json);
|
||||
expect(json['text'], equals('Hello, world!'));
|
||||
|
@ -63,10 +63,8 @@ main() {
|
|||
|
||||
test('can fetch data', () async {
|
||||
String postData = god.serialize({'text': 'Hello, world!'});
|
||||
await client.post(
|
||||
"$url/todos", headers: headers, body: postData);
|
||||
var response = await client.get(
|
||||
"$url/todos/0");
|
||||
await client.post("$url/todos", headers: headers, body: postData);
|
||||
var response = await client.get("$url/todos/0");
|
||||
var json = god.deserialize(response.body);
|
||||
print(json);
|
||||
expect(json['text'], equals('Hello, world!'));
|
||||
|
@ -74,11 +72,10 @@ main() {
|
|||
|
||||
test('can modify data', () async {
|
||||
String postData = god.serialize({'text': 'Hello, world!'});
|
||||
await client.post(
|
||||
"$url/todos", headers: headers, body: postData);
|
||||
await client.post("$url/todos", headers: headers, body: postData);
|
||||
postData = god.serialize({'text': 'modified'});
|
||||
var response = await client.patch(
|
||||
"$url/todos/0", headers: headers, body: postData);
|
||||
var response =
|
||||
await client.patch("$url/todos/0", headers: headers, body: postData);
|
||||
var json = god.deserialize(response.body);
|
||||
print(json);
|
||||
expect(json['text'], equals('modified'));
|
||||
|
@ -86,11 +83,10 @@ main() {
|
|||
|
||||
test('can overwrite data', () async {
|
||||
String postData = god.serialize({'text': 'Hello, world!'});
|
||||
await client.post(
|
||||
"$url/todos", headers: headers, body: postData);
|
||||
await client.post("$url/todos", headers: headers, body: postData);
|
||||
postData = god.serialize({'over': 'write'});
|
||||
var response = await client.post(
|
||||
"$url/todos/0", headers: headers, body: postData);
|
||||
var response =
|
||||
await client.post("$url/todos/0", headers: headers, body: postData);
|
||||
var json = god.deserialize(response.body);
|
||||
print(json);
|
||||
expect(json['text'], equals(null));
|
||||
|
@ -99,18 +95,14 @@ main() {
|
|||
|
||||
test('can delete data', () async {
|
||||
String postData = god.serialize({'text': 'Hello, world!'});
|
||||
await client.post(
|
||||
"$url/todos", headers: headers, body: postData);
|
||||
var response = await client.delete(
|
||||
"$url/todos/0");
|
||||
await client.post("$url/todos", headers: headers, body: postData);
|
||||
var response = await client.delete("$url/todos/0");
|
||||
var json = god.deserialize(response.body);
|
||||
print(json);
|
||||
expect(json['text'], equals('Hello, world!'));
|
||||
response = await client.get("$url/todos");
|
||||
print(response.body);
|
||||
expect(god
|
||||
.deserialize(response.body)
|
||||
.length, equals(0));
|
||||
expect(god.deserialize(response.body).length, equals(0));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue