platform/lib/src/core/map_service.dart

166 lines
4.9 KiB
Dart
Raw Normal View History

2017-02-23 00:37:15 +00:00
import 'dart:async';
2018-08-04 03:38:31 +00:00
2017-09-22 04:48:22 +00:00
import 'package:angel_http_exception/angel_http_exception.dart';
2018-08-04 03:38:31 +00:00
2017-02-23 00:37:15 +00:00
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;
2017-11-18 17:42:31 +00:00
/// If set to `true` (default), then the service will manage an `id` string and `createdAt` and `updatedAt` fields.
final bool autoIdAndDateFields;
/// If set to `true` (default), then the keys `created_at` and `updated_at` will automatically be snake_cased.
final bool autoSnakeCaseNames;
2017-02-23 00:37:15 +00:00
final List<Map<String, dynamic>> items = [];
2017-11-18 17:42:31 +00:00
MapService(
{this.allowRemoveAll: false,
this.allowQuery: true,
this.autoIdAndDateFields: true,
this.autoSnakeCaseNames: true})
2017-11-18 17:42:31 +00:00
: super();
2017-02-23 00:37:15 +00:00
String get createdAtKey =>
autoSnakeCaseNames == false ? 'createdAt' : 'created_at';
String get updatedAtKey =>
autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at';
2017-12-10 05:05:59 +00:00
bool Function(Map) _matchesId(id) {
return (Map item) {
if (item['id'] == null)
return false;
else if (autoIdAndDateFields != false)
return item['id'] == id?.toString();
else
return item['id'] == id;
};
2017-02-23 00:37:15 +00:00
}
@override
2018-06-08 07:06:26 +00:00
Future<List> index([Map params]) {
2017-05-27 12:39:45 +00:00
if (allowQuery == false || params == null || params['query'] is! Map)
2018-06-08 07:06:26 +00:00
return new Future.value(items);
2017-02-23 00:37:15 +00:00
else {
Map query = params['query'];
2018-06-08 07:06:26 +00:00
return new Future.value(items.where((item) {
2017-02-23 00:37:15 +00:00
for (var key in query.keys) {
if (!item.containsKey(key))
return false;
else if (item[key] != query[key]) return false;
}
return true;
2018-06-08 07:06:26 +00:00
}).toList());
2017-02-23 00:37:15 +00:00
}
}
@override
2018-06-08 07:06:26 +00:00
Future<Map> read(id, [Map params]) {
return new Future.value(items.firstWhere(_matchesId(id),
2017-02-23 00:37:15 +00:00
orElse: () => throw new AngelHttpException.notFound(
2018-06-08 07:06:26 +00:00
message: 'No record found for ID $id')));
2017-02-23 00:37:15 +00:00
}
@override
2018-06-08 07:06:26 +00:00
Future<Map> create(data, [Map params]) {
2017-02-23 00:37:15 +00:00
if (data is! Map)
throw new AngelHttpException.badRequest(
message:
'MapService does not support `create` with ${data.runtimeType}.');
2018-03-30 18:33:36 +00:00
var now = new DateTime.now().toIso8601String();
2018-06-23 03:29:38 +00:00
var result = data as Map;
2017-11-18 17:42:31 +00:00
if (autoIdAndDateFields == true) {
result
..['id'] = items.length.toString()
..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] = now
..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = now;
2017-11-18 17:42:31 +00:00
}
2018-08-04 03:38:31 +00:00
items.add(_foldStringDynamic(result));
2018-06-08 07:06:26 +00:00
return new Future.value(result);
2017-02-23 00:37:15 +00:00
}
2018-08-04 03:38:31 +00:00
Map<String, dynamic> _foldStringDynamic(Map map) {
return map == null
? null
: map.keys.fold<Map<String, dynamic>>(
<String, dynamic>{}, (out, k) => out..[k.toString()] = map[k]);
}
2017-02-23 00:37:15 +00:00
@override
2018-06-08 07:06:26 +00:00
Future<Map> modify(id, data, [Map params]) {
2017-02-23 00:37:15 +00:00
if (data is! Map)
throw new AngelHttpException.badRequest(
message:
2017-02-25 00:16:31 +00:00
'MapService does not support `modify` with ${data.runtimeType}.');
2018-06-08 07:06:26 +00:00
if (!items.any(_matchesId(id))) return create(data, params);
2017-03-28 23:29:22 +00:00
2018-06-08 07:06:26 +00:00
return read(id).then((item) {
2018-06-23 03:29:38 +00:00
var result = item..addAll(data as Map);
2017-11-18 17:42:31 +00:00
2018-06-08 07:06:26 +00:00
if (autoIdAndDateFields == true)
result
..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] =
new DateTime.now().toIso8601String();
return new Future.value(result);
});
2017-02-23 00:37:15 +00:00
}
@override
2018-06-08 07:06:26 +00:00
Future<Map> update(id, data, [Map params]) {
2017-02-23 00:37:15 +00:00
if (data is! Map)
throw new AngelHttpException.badRequest(
message:
2017-02-25 00:16:31 +00:00
'MapService does not support `update` with ${data.runtimeType}.');
2018-06-08 07:06:26 +00:00
if (!items.any(_matchesId(id))) return create(data, params);
return read(id).then((old) {
if (!items.remove(old))
throw new AngelHttpException.notFound(
message: 'No record found for ID $id');
2018-06-23 03:29:38 +00:00
var result = data as Map;
2018-06-08 07:06:26 +00:00
if (autoIdAndDateFields == true) {
result
..['id'] = id?.toString()
..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] =
old[autoSnakeCaseNames == false ? 'createdAt' : 'created_at']
..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] =
new DateTime.now().toIso8601String();
}
2018-08-04 03:38:31 +00:00
items.add(_foldStringDynamic(result));
2018-06-08 07:06:26 +00:00
return new Future.value(result);
});
2017-02-23 00:37:15 +00:00
}
@override
2018-06-08 07:06:26 +00:00
Future<Map> remove(id, [Map params]) {
2017-04-15 17:42:21 +00:00
if (id == null ||
id == 'null' &&
(allowRemoveAll == true ||
params?.containsKey('provider') != true)) {
items.clear();
2018-06-08 07:06:26 +00:00
return new Future.value({});
2017-04-15 17:42:21 +00:00
}
2018-06-08 07:06:26 +00:00
return read(id, params).then((result) {
if (items.remove(result))
return result;
else
throw new AngelHttpException.notFound(
message: 'No record found for ID $id');
});
2017-02-23 00:37:15 +00:00
}
}