Merge pull request #2 from alextekartik/master

feat: use the new sembast store API
This commit is contained in:
Tobe Osakwe 2020-02-14 17:29:27 -05:00 committed by GitHub
commit eda2acc36a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 66 deletions

View file

@ -5,17 +5,17 @@ import 'package:logging/logging.dart';
import 'package:sembast/sembast_io.dart'; import 'package:sembast/sembast_io.dart';
main() async { main() async {
var app = new Angel(); var app = Angel();
var db = await databaseFactoryIo.openDatabase('todos.db'); var db = await databaseFactoryIo.openDatabase('todos.db');
app app
..logger = (new Logger('angel_sembast_example')..onRecord.listen(print)) ..logger = (Logger('angel_sembast_example')..onRecord.listen(print))
..use('/api/todos', new SembastService(db, store: 'todos')) ..use('/api/todos', SembastService(db, store: 'todos'))
..shutdownHooks.add((_) => db.close()); ..shutdownHooks.add((_) => db.close());
var http = new AngelHttp(app); var http = AngelHttp(app);
var server = await http.startServer('127.0.0.1', 3000); var server = await http.startServer('127.0.0.1', 3000);
var uri = var uri =
new Uri(scheme: 'http', host: server.address.address, port: server.port); Uri(scheme: 'http', host: server.address.address, port: server.port);
print('angel_sembast example listening at $uri'); print('angel_sembast example listening at $uri');
} }

View file

@ -4,7 +4,7 @@ import 'package:sembast/sembast.dart';
class SembastService extends Service<String, Map<String, dynamic>> { class SembastService extends Service<String, Map<String, dynamic>> {
final Database database; final Database database;
final Store store; final StoreRef<int, Map<String, dynamic>> store;
/// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`. /// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`.
/// ///
@ -16,12 +16,11 @@ class SembastService extends Service<String, Map<String, dynamic>> {
SembastService(this.database, SembastService(this.database,
{String store, this.allowRemoveAll = false, this.allowQuery = true}) {String store, this.allowRemoveAll = false, this.allowQuery = true})
: this.store = : this.store = intMapStoreFactory.store(store),
(store == null ? database.mainStore : database.getStore(store)),
super(); super();
Finder _makeQuery([Map<String, dynamic> params]) { Finder _makeQuery([Map<String, dynamic> params]) {
params = new Map<String, dynamic>.from(params ?? {}); params = Map<String, dynamic>.from(params ?? {});
Filter out; Filter out;
var sort = <SortOrder>[]; var sort = <SortOrder>[];
@ -36,16 +35,16 @@ class SembastService extends Service<String, Map<String, dynamic>> {
var v = params[key]; var v = params[key];
if (v is! Map) { if (v is! Map) {
sort.add(new SortOrder(v.toString(), true)); sort.add(SortOrder(v.toString(), true));
} else { } else {
var m = v as Map; var m = v as Map;
m.forEach((k, sorter) { m.forEach((k, sorter) {
if (sorter is SortOrder) { if (sorter is SortOrder) {
sort.add(sorter); sort.add(sorter);
} else if (sorter is String) { } else if (sorter is String) {
sort.add(new SortOrder(k.toString(), sorter == "-1")); sort.add(SortOrder(k.toString(), sorter == "-1"));
} else if (sorter is num) { } else if (sorter is num) {
sort.add(new SortOrder(k.toString(), sorter == -1)); sort.add(SortOrder(k.toString(), sorter == -1));
} }
}); });
} }
@ -57,94 +56,81 @@ class SembastService extends Service<String, Map<String, dynamic>> {
queryObj.forEach((k, v) { queryObj.forEach((k, v) {
if (k != 'provider' && if (k != 'provider' &&
!const ['__requestctx', '__responsectx'].contains(k)) { !const ['__requestctx', '__responsectx'].contains(k)) {
var filter = new Filter.equal(k.toString(), v); var filter = Filter.equals(k.toString(), v);
if (out == null) if (out == null) {
out = filter; out = filter;
else } else {
out = new Filter.or([out, filter]); out = Filter.or([out, filter]);
}
} }
}); });
} }
} }
} }
return new Finder(filter: out, sortOrders: sort); return Finder(filter: out, sortOrders: sort);
} }
Map<String, dynamic> _jsonify(Record record) { Map<String, dynamic> _withId(Map<String, dynamic> data, String id) =>
return new Map<String, dynamic>.from(record.value as Map) Map<String, dynamic>.from(data ?? {})..['id'] = id;
..['id'] = record.key.toString();
}
@override @override
Future<Map<String, dynamic>> findOne( Future<Map<String, dynamic>> findOne(
[Map<String, dynamic> params, [Map<String, dynamic> params,
String errorMessage = 'No record was found matching the given query.']) { String errorMessage =
return store.findRecord(_makeQuery(params)).then(_jsonify); 'No record was found matching the given query.']) async {
return (await store.findFirst(database, finder: _makeQuery(params)))?.value;
} }
@override @override
Future<List<Map<String, dynamic>>> index( Future<List<Map<String, dynamic>>> index(
[Map<String, dynamic> params]) async { [Map<String, dynamic> params]) async {
var records = await store.findRecords(_makeQuery(params)); var records = await store.find(database, finder: _makeQuery(params));
return records.where((r) => r.value != null).map(_jsonify).toList(); return records
.where((r) => r.value != null)
.map((r) => _withId(r.value, r.key.toString()))
.toList();
} }
@override @override
Future<Map<String, dynamic>> read(String id, Future<Map<String, dynamic>> read(String id,
[Map<String, dynamic> params]) async { [Map<String, dynamic> params]) async {
var record = await store.get(int.parse(id)); var record = await store.record(int.parse(id)).getSnapshot(database);
if (record == null) { if (record == null) {
throw new AngelHttpException.notFound( throw AngelHttpException.notFound(message: 'No record found for ID $id');
message: 'No record found for ID $id');
} }
return (record as Map<String, dynamic>)..['id'] = id; return _withId(record.value, id);
} }
@override @override
Future<Map<String, dynamic>> create(Map<String, dynamic> data, Future<Map<String, dynamic>> create(Map<String, dynamic> data,
[Map<String, dynamic> params]) async { [Map<String, dynamic> params]) async {
return await database.transaction((txn) async { return await database.transaction((txn) async {
var store = txn.getStore(this.store.name); var key = await store.add(txn, data);
var key = await store.put(data) as int;
var id = key.toString(); var id = key.toString();
data = new Map<String, dynamic>.from(data)..['id'] = id; return _withId(data, id);
return data;
}); });
} }
@override @override
Future<Map<String, dynamic>> modify(String id, Map<String, dynamic> data, Future<Map<String, dynamic>> modify(String id, Map<String, dynamic> data,
[Map<String, dynamic> params]) async { [Map<String, dynamic> params]) async {
data = new Map<String, dynamic>.from(data)..['id'] = id;
return await database.transaction((txn) async { return await database.transaction((txn) async {
var store = txn.getStore(this.store.name); var record = store.record(int.parse(id));
var existing = await store.get(int.parse(id)); data = await record.put(txn, data, merge: true);
return _withId(data, id);
data =
new Map<String, dynamic>.from(existing as Map<String, dynamic> ?? {})
..addAll(data)
..['id'] = id;
await store.put(data, int.parse(id));
return (await store.get(int.parse(id)) as Map<String, dynamic>)
..['id'] = id;
}); });
} }
@override @override
Future<Map<String, dynamic>> update(String id, Map<String, dynamic> data, Future<Map<String, dynamic>> update(String id, Map<String, dynamic> data,
[Map<String, dynamic> params]) async { [Map<String, dynamic> params]) async {
data = new Map<String, dynamic>.from(data)..['id'] = id;
return await database.transaction((txn) async { return await database.transaction((txn) async {
var store = txn.getStore(this.store.name); var record = store.record(int.parse(id));
await store.put(data, int.parse(id)); data = await record.put(txn, data);
return (await store.get(int.parse(id)) as Map<String, dynamic>) return _withId(data, id);
..['id'] = id;
}); });
} }
@ -158,23 +144,23 @@ class SembastService extends Service<String, Map<String, dynamic>> {
throw AngelHttpException.forbidden( throw AngelHttpException.forbidden(
message: 'Clients are not allowed to delete all items.'); message: 'Clients are not allowed to delete all items.');
} else { } else {
await store.deleteAll(await store.findKeys(new Finder())); await store.delete(database);
return {}; return {};
} }
} }
return database.transaction((txn) async { return database.transaction((txn) async {
var store = txn.getStore(this.store.name); var record = store.record(int.parse(id));
var record = await store.get(int.parse(id)) as Map<String, dynamic>; var snapshot = await record.getSnapshot(txn);
if (record == null) { if (snapshot == null) {
throw new AngelHttpException.notFound( throw AngelHttpException.notFound(
message: 'No record found for ID $id'); message: 'No record found for ID $id');
} else { } else {
await store.delete(id); await record.delete(txn);
} }
return record..['id'] = id; return _withId(snapshot.value, id);
}); });
} }
} }

View file

@ -4,10 +4,10 @@ homepage: https://github.com/angel-dart/sembast
version: 1.0.1 version: 1.0.1
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
environment: environment:
sdk: ">=2.0.0-dev <3.0.0" sdk: ">=2.1.0-dev <3.0.0"
dependencies: dependencies:
angel_framework: ^2.0.0-alpha angel_framework: ^2.0.0-alpha
sembast: ^1.9.5 sembast: ^1.19.0-dev.2
dev_dependencies: dev_dependencies:
angel_http_exception: ^1.0.0 angel_http_exception: ^1.0.0
logging: logging:

View file

@ -12,7 +12,7 @@ main() async {
setUp(() async { setUp(() async {
database = await memoryDatabaseFactory.openDatabase('test.db'); database = await memoryDatabaseFactory.openDatabase('test.db');
service = new SembastService(database); service = SembastService(database);
}); });
tearDown(() => database.close()); tearDown(() => database.close());
@ -37,7 +37,7 @@ main() async {
}); });
test('read', () async { test('read', () async {
var name = 'poobah${new DateTime.now().millisecondsSinceEpoch}'; var name = 'poobah${DateTime.now().millisecondsSinceEpoch}';
var input = await service.create({'name': name, 'bar': 'baz'}); var input = await service.create({'name': name, 'bar': 'baz'});
print(input); print(input);
expect(await service.read(input['id'] as String), input); expect(await service.read(input['id'] as String), input);
@ -47,8 +47,8 @@ main() async {
var input = await service.create({'bar': 'baz', 'yes': 'no'}); var input = await service.create({'bar': 'baz', 'yes': 'no'});
var id = input['id'] as String; var id = input['id'] as String;
var output = await service.modify(id, {'bar': 'quux'}); var output = await service.modify(id, {'bar': 'quux'});
expect(new SplayTreeMap.from(output), expect(SplayTreeMap.from(output),
new SplayTreeMap.from({'id': id, 'bar': 'quux', 'yes': 'no'})); SplayTreeMap.from({'id': id, 'bar': 'quux', 'yes': 'no'}));
expect(await service.read(id), output); expect(await service.read(id), output);
}); });
@ -64,7 +64,7 @@ main() async {
var input = await service.create({'bar': 'baz'}); var input = await service.create({'bar': 'baz'});
var id = input['id'] as String; var id = input['id'] as String;
expect(await service.remove(id), input); expect(await service.remove(id), input);
expect(await database.get(id), isNull); expect(await StoreRef.main().record(id).get(database), isNull);
}); });
test('remove', () async { test('remove', () async {