platform/lib/mongo_service.dart

192 lines
5.5 KiB
Dart
Raw Normal View History

2016-09-21 04:26:22 +00:00
part of angel_mongo.services;
2016-05-09 22:51:07 +00:00
2016-06-22 18:34:28 +00:00
/// Manipulates data from MongoDB as Maps.
2016-05-09 22:51:07 +00:00
class MongoService extends Service {
DbCollection collection;
2017-02-20 16:00:42 +00:00
/// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`.
///
/// `false` by default.
final bool allowRemoveAll;
2017-02-23 01:03:30 +00:00
/// If set to `true`, parameters in `req.query` are applied to the database query.
final bool allowQuery;
2017-02-13 01:38:24 +00:00
final bool debug;
2016-05-09 22:51:07 +00:00
2017-02-20 16:00:42 +00:00
MongoService(DbCollection this.collection,
2017-02-23 01:03:30 +00:00
{this.allowRemoveAll: false, this.allowQuery: true, this.debug: true})
2017-02-20 16:00:42 +00:00
: super();
2016-06-22 18:34:28 +00:00
2017-02-23 01:03:30 +00:00
SelectorBuilder _makeQuery([Map params_]) {
Map params = params_ ?? {};
params = params..remove('provider');
SelectorBuilder result = where.exists('_id');
// You can pass a SelectorBuilder as 'query';
if (params['query'] is SelectorBuilder) {
return params['query'];
}
for (var key in params.keys) {
if (key == r'$sort' ||
key == r'$query' &&
(allowQuery == true || !params.containsKey('provider'))) {
if (params[key] is Map) {
// If they send a map, then we'll sort by every key in the map
for (String fieldName in params[key].keys.where((x) => x is String)) {
var sorter = params[key][fieldName];
if (sorter is num) {
result = result.sortBy(fieldName, descending: sorter == -1);
} else if (sorter is String) {
result = result.sortBy(fieldName, descending: sorter == "-1");
} else if (sorter is SelectorBuilder) {
result = result.and(sorter);
}
}
} else if (params[key] is String && key == r'$sort') {
// If they send just a string, then we'll sort
// by that, ascending
result = result.sortBy(params[key]);
}
} else if (key == 'query' &&
(allowQuery == true || !params.containsKey('provider'))) {
Map query = params[key];
query.forEach((key, v) {
var value = v is Map ? _filterNoQuery(v) : v;
if (!_NO_QUERY.contains(key) &&
value is! RequestContext &&
value is! ResponseContext) {
result = result.and(where.eq(key, value));
}
});
}
}
return result;
}
2016-06-22 18:34:28 +00:00
_jsonify(Map doc, [Map params]) {
2016-05-09 22:51:07 +00:00
Map result = {};
2017-02-13 01:38:24 +00:00
2016-05-09 22:51:07 +00:00
for (var key in doc.keys) {
2017-02-13 01:38:24 +00:00
var value = doc[key];
if (value is ObjectId) {
result[key] = value.toHexString();
} else if (value is! RequestContext && value is! ResponseContext) {
result[key] = value;
}
2016-05-09 22:51:07 +00:00
}
2016-06-22 18:34:28 +00:00
return _transformId(result);
2016-05-09 22:51:07 +00:00
}
2017-02-13 01:38:24 +00:00
void printDebug(e, st, msg) {
2016-12-03 17:39:48 +00:00
if (debug) {
stderr.writeln('$msg ERROR: $e');
stderr.writeln(st);
}
}
2016-05-09 22:51:07 +00:00
@override
Future<List> index([Map params]) async {
return await (await collection.find(_makeQuery(params)))
2016-06-22 18:34:28 +00:00
.map((x) => _jsonify(x, params))
2016-05-09 22:51:07 +00:00
.toList();
}
@override
2017-02-13 01:38:24 +00:00
Future create(data, [Map params]) async {
2016-06-22 18:34:28 +00:00
Map item = (data is Map) ? data : god.serializeObject(data);
item = _removeSensitive(item);
2016-05-09 22:51:07 +00:00
try {
2017-02-19 12:32:21 +00:00
item['createdAt'] = new DateTime.now().toIso8601String();
2016-06-22 18:34:28 +00:00
await collection.insert(item);
return await _lastItem(collection, _jsonify, params);
} catch (e, st) {
2017-02-13 01:38:24 +00:00
printDebug(e, st, 'CREATE');
2016-06-22 18:34:28 +00:00
throw new AngelHttpException(e, stackTrace: st);
2016-05-09 22:51:07 +00:00
}
2016-06-22 18:34:28 +00:00
}
2016-05-09 22:51:07 +00:00
2016-06-22 18:34:28 +00:00
@override
Future read(id, [Map params]) async {
ObjectId _id = _makeId(id);
Map found = await collection.findOne(where.id(_id).and(_makeQuery(params)));
2016-05-09 22:51:07 +00:00
if (found == null) {
2017-02-13 01:38:24 +00:00
throw new AngelHttpException.notFound(
2016-06-22 18:34:28 +00:00
message: 'No record found for ID ${_id.toHexString()}');
2016-05-09 22:51:07 +00:00
}
2016-06-22 18:34:28 +00:00
return _jsonify(found, params);
2016-05-09 22:51:07 +00:00
}
2016-06-22 18:34:28 +00:00
@override
2017-02-13 01:38:24 +00:00
Future modify(id, data, [Map params]) async {
var target = await read(id, params);
Map result = mergeMap([
target is Map ? target : god.serializeObject(target),
_removeSensitive(data)
]);
2017-02-19 12:32:21 +00:00
result['updatedAt'] = new DateTime.now().toIso8601String();
2016-06-22 18:34:28 +00:00
try {
await collection.update(where.id(_makeId(id)), result);
result = _jsonify(result, params);
result['id'] = id;
return result;
} catch (e, st) {
2017-02-13 01:38:24 +00:00
printDebug(e, st, 'MODIFY');
2016-06-22 18:34:28 +00:00
throw new AngelHttpException(e, stackTrace: st);
}
}
@override
Future update(id, data, [Map params]) async {
2017-02-13 01:38:24 +00:00
var target = await read(id, params);
2016-06-22 18:34:28 +00:00
Map result = _removeSensitive(data);
result['_id'] = _makeId(id);
2017-02-19 12:32:21 +00:00
result['createdAt'] =
target is Map ? target['createdAt'] : target.createdAt;
if (result['createdAt'] is DateTime)
result['createdAt'] = result['createdAt'].toIso8601String();
result['updatedAt'] = new DateTime.now().toIso8601String();
2016-06-22 18:34:28 +00:00
try {
await collection.update(where.id(_makeId(id)), result);
result = _jsonify(result, params);
result['id'] = id;
return result;
} catch (e, st) {
2017-02-13 01:38:24 +00:00
printDebug(e, st, 'UPDATE');
2016-06-22 18:34:28 +00:00
throw new AngelHttpException(e, stackTrace: st);
}
}
2016-06-23 04:58:21 +00:00
@override
Future remove(id, [Map params]) async {
2017-02-20 16:00:42 +00:00
if (id == null ||
id == 'null' &&
(allowRemoveAll == true ||
params?.containsKey('provider') != true)) {
await collection.remove(null);
return {};
}
2017-02-19 12:32:21 +00:00
var result = await read(id, params);
2016-06-22 18:34:28 +00:00
2016-06-23 04:58:21 +00:00
try {
await collection.remove(where.id(_makeId(id)).and(_makeQuery(params)));
return result;
} catch (e, st) {
2017-02-13 01:38:24 +00:00
printDebug(e, st, 'REMOVE');
2016-06-23 04:58:21 +00:00
throw new AngelHttpException(e, stackTrace: st);
}
}
2016-05-09 22:51:07 +00:00
}