Functionality done

This commit is contained in:
thosakwe 2016-06-23 00:58:21 -04:00
parent 7d54936623
commit 71fe379db9
7 changed files with 111 additions and 45 deletions

View file

@ -1,2 +1,35 @@
# angel_mongo
![version 1.0.0-dev](https://img.shields.io/badge/version-1.0.0--dev-red.svg)
MongoDB-enabled services for the Angel framework.
# Installation
Add the following to your `pubspec.yaml`:
```yaml
dependencies:
angel_mongo: ^1.0.0-dev
```
# Usage
This library exposes three main classes: `Model`, `MongoService` and `MongoTypedService<T>`.
## Model
`Model` is class with no real functionality; however, it represents a basic MongoDB document, and your services should host inherited classes.
```dart
@Hooked()
class User extends Model {
String username;
String password;
}
```
## MongoService
This class interacts with a `DbCollection` (from mongo_dart) and serializing data to and from Maps.
## MongoTypedService<T>
Does the same as above, but serializes to and from a target class using json_god and its support for reflection.
See the tests for more usage examples.

View file

@ -23,7 +23,6 @@ class Model {
DateTime updatedAt;
}
Map _transformId(Map doc) {
Map result = mergeMap([doc]);
result['id'] = doc['_id'];
@ -33,8 +32,8 @@ Map _transformId(Map doc) {
_lastItem(DbCollection collection, Function _jsonify, [Map params]) async {
return (await (await collection
.find(where.sortBy('\$natural', descending: true)))
.toList())
.find(where.sortBy('\$natural', descending: true)))
.toList())
.map((x) => _jsonify(x, params))
.first;
}
@ -48,8 +47,11 @@ ObjectId _makeId(id) {
}
Map _removeSensitive(Map data) {
return data..remove('id')..remove('_id')..remove('createdAt')..remove(
'updatedAt');
return data
..remove('id')
..remove('_id')
..remove('createdAt')
..remove('updatedAt');
}
SelectorBuilder _makeQuery([Map params_]) {

View file

@ -4,14 +4,7 @@ part of angel_mongo;
class MongoService extends Service {
DbCollection collection;
MongoService(DbCollection this.collection):super();
Map _transformId(Map doc) {
Map result = mergeMap([doc]);
result['id'] = doc['_id'];
return result..remove('_id');
}
MongoService(DbCollection this.collection) : super();
_jsonify(Map doc, [Map params]) {
Map result = {};
@ -123,5 +116,15 @@ class MongoService extends Service {
}
}
@override
Future remove(id, [Map params]) async {
Map result = await read(id, params);
try {
await collection.remove(where.id(_makeId(id)).and(_makeQuery(params)));
return result;
} catch (e, st) {
throw new AngelHttpException(e, stackTrace: st);
}
}
}

View file

@ -4,19 +4,12 @@ part of angel_mongo;
class MongoTypedService<T> extends Service {
DbCollection collection;
MongoTypedService(DbCollection this.collection):super() {
MongoTypedService(DbCollection this.collection) : super() {
if (!reflectType(T).isAssignableTo(reflectType(Model)))
throw new Exception(
"If you specify a type for MongoService, it must be dynamic, Map, or extend from Model.");
}
Map _transformId(Map doc) {
Map result = mergeMap([doc]);
result['id'] = doc['_id'];
return result..remove('_id');
}
_jsonify(Map doc, [Map params]) {
Map result = {};
for (var key in doc.keys) {
@ -31,8 +24,7 @@ class MongoTypedService<T> extends Service {
// Clients will always receive JSON.
if ((params != null && params['provider'] != null)) {
return result;
}
else {
} else {
// However, when we run server-side, we should return a T, not a Map.
Model typedResult = god.deserializeDatum(result, outputType: T);
typedResult.createdAt = result['createdAt'];
@ -54,7 +46,7 @@ class MongoTypedService<T> extends Service {
try {
Model target =
(data is T) ? data : god.deserializeDatum(data, outputType: T);
(data is T) ? data : god.deserializeDatum(data, outputType: T);
item = god.serializeObject(target);
item = _removeSensitive(item);
@ -86,8 +78,8 @@ class MongoTypedService<T> extends Service {
Future modify(id, Map data, [Map params]) async {
ObjectId _id = _makeId(id);
try {
Map result = await collection.findOne(
where.id(_id).and(_makeQuery(params)));
Map result =
await collection.findOne(where.id(_id).and(_makeQuery(params)));
if (result == null) {
throw new AngelHttpException.NotFound(
@ -108,8 +100,8 @@ class MongoTypedService<T> extends Service {
@override
Future update(id, _data, [Map params]) async {
try {
Model data = (_data is T) ? _data : god.deserializeDatum(
_data, outputType: T);
Model data =
(_data is T) ? _data : god.deserializeDatum(_data, outputType: T);
ObjectId _id = _makeId(id);
Map rawData = _removeSensitive(god.serializeObject(data));
rawData['_id'] = _id;
@ -128,4 +120,16 @@ class MongoTypedService<T> extends Service {
throw new AngelHttpException(e, stackTrace: st);
}
}
@override
Future remove(id, [Map params]) async {
Map result = await read(id, params);
try {
await collection.remove(where.id(_makeId(id)).and(_makeQuery(params)));
return result;
} catch (e, st) {
throw new AngelHttpException(e, stackTrace: st);
}
}
}

View file

@ -23,6 +23,9 @@ wireHooked(HookedService hooked) {
})
..afterUpdated.listen((HookedServiceEvent event) {
print("Just updated: ${event.result}");
})
..afterRemoved.listen((HookedServiceEvent event) {
print("Just removed: ${event.result}");
});
}
@ -48,7 +51,7 @@ main() {
app.use('/api', Greetings);
HttpServer server =
await app.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
await app.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
url = "http://${server.address.host}:${server.port}";
});
@ -93,9 +96,8 @@ main() {
expect(response.statusCode, equals(HttpStatus.OK));
Map created = god.deserialize(response.body);
response = await client.patch(
"$url/api/${created['id']}", body: god.serialize({"to": "Mom"}),
headers: headers);
response = await client.patch("$url/api/${created['id']}",
body: god.serialize({"to": "Mom"}), headers: headers);
Map modified = god.deserialize(response.body);
expect(response.statusCode, equals(HttpStatus.OK));
expect(modified['id'], equals(created['id']));
@ -109,9 +111,8 @@ main() {
expect(response.statusCode, equals(HttpStatus.OK));
Map created = god.deserialize(response.body);
response = await client.post(
"$url/api/${created['id']}", body: god.serialize({"to": "Updated"}),
headers: headers);
response = await client.post("$url/api/${created['id']}",
body: god.serialize({"to": "Updated"}), headers: headers);
Map modified = god.deserialize(response.body);
expect(response.statusCode, equals(HttpStatus.OK));
expect(modified['id'], equals(created['id']));
@ -119,11 +120,19 @@ main() {
expect(modified['updatedAt'], isNot(null));
});
test('remove item', () async {});
test('remove item', () async {
var response = await client.post("$url/api",
body: god.serialize(testGreeting), headers: headers);
Map created = god.deserialize(response.body);
test(r'$sort', () async {
int lastCount = (await Greetings.index()).length;
await client.delete("$url/api/${created['id']}");
expect((await Greetings.index()).length, equals(lastCount - 1));
});
test(r'$sort', () async {});
test('query parameters', () async {});
});
}

1
test/packages Symbolic link
View file

@ -0,0 +1 @@
../packages

View file

@ -54,7 +54,7 @@ main() {
app.use('/api', Greetings);
HttpServer server =
await app.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
await app.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
url = "http://${server.address.host}:${server.port}";
});
@ -109,9 +109,8 @@ main() {
expect(response.statusCode, equals(HttpStatus.OK));
Map created = god.deserialize(response.body);
response = await client.patch(
"$url/api/${created['id']}", body: god.serialize({"to": "Mom"}),
headers: headers);
response = await client.patch("$url/api/${created['id']}",
body: god.serialize({"to": "Mom"}), headers: headers);
Map modified = god.deserialize(response.body);
expect(response.statusCode, equals(HttpStatus.OK));
expect(modified['id'], equals(created['id']));
@ -129,9 +128,8 @@ main() {
expect(response.statusCode, equals(HttpStatus.OK));
Map created = god.deserialize(response.body);
response = await client.post(
"$url/api/${created['id']}", body: god.serialize({"to": "Updated"}),
headers: headers);
response = await client.post("$url/api/${created['id']}",
body: god.serialize({"to": "Updated"}), headers: headers);
Map modified = god.deserialize(response.body);
expect(response.statusCode, equals(HttpStatus.OK));
expect(modified['id'], equals(created['id']));
@ -139,7 +137,23 @@ main() {
expect(modified['updatedAt'], isNot(null));
});
test('remove item', () async {});
test('remove item', () async {
var response = await client.post("$url/api",
body: god.serialize(testGreeting), headers: headers);
Map created = god.deserialize(response.body);
int lastCount = (await Greetings.index()).length;
await client.delete("$url/api/${created['id']}");
expect((await Greetings.index()).length, equals(lastCount - 1));
Greeting bernie =
await Greetings.create(new Greeting(to: "Bernie Sanders"));
lastCount = (await Greetings.index()).length;
await Greetings.remove(bernie.id);
expect((await Greetings.index()).length, equals(lastCount - 1));
});
test(r'$sort', () async {});