From 74f50141c375920d446b28a11205bbc7e85724ea Mon Sep 17 00:00:00 2001 From: Tobe O Date: Tue, 21 Feb 2017 11:52:55 -0500 Subject: [PATCH 01/13] Initial commit --- .gitignore | 27 +++++++++++++++++++++++++++ LICENSE | 21 +++++++++++++++++++++ README.md | 2 ++ 3 files changed, 50 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7c280441 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# See https://www.dartlang.org/tools/private-files.html + +# Files and directories created by pub +.buildlog +.packages +.project +.pub/ +build/ +**/packages/ + +# Files created by dart2js +# (Most Dart developers will use pub build to compile Dart, use/modify these +# rules if you intend to use dart2js directly +# Convention is to use extension '.dart.js' for Dart compiled to Javascript to +# differentiate from explicit Javascript files) +*.dart.js +*.part.js +*.js.deps +*.js.map +*.info.json + +# Directory created by dartdoc +doc/api/ + +# Don't commit pubspec lock file +# (Library packages only! Remove pattern if developing an application package) +pubspec.lock diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..89074fd3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 The Angel Framework + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..9a9ffef1 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# rethink +RethinkDB-enabled services for the Angel framework. From c8a3cd9d67aa96546396f2db82c67cf63f8b6276 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Tue, 21 Feb 2017 22:13:08 -0500 Subject: [PATCH 02/13] 1.0.0 --- .gitignore | 2 + .travis.yml | 4 + README.md | 84 +++++++++++++++ lib/angel_rethink.dart | 1 + lib/src/rethink_service.dart | 194 +++++++++++++++++++++++++++++++++++ pubspec.yaml | 13 +++ test/README.md | 6 ++ test/bootstrap.dart | 7 ++ test/common.dart | 10 ++ test/generic_test.dart | 87 ++++++++++++++++ 10 files changed, 408 insertions(+) create mode 100644 .travis.yml create mode 100644 lib/angel_rethink.dart create mode 100644 lib/src/rethink_service.dart create mode 100644 pubspec.yaml create mode 100644 test/README.md create mode 100644 test/bootstrap.dart create mode 100644 test/common.dart create mode 100644 test/generic_test.dart diff --git a/.gitignore b/.gitignore index 7c280441..5d2a807f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ doc/api/ # Don't commit pubspec lock file # (Library packages only! Remove pattern if developing an application package) pubspec.lock + +rethinkdb_data/ \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..d8efdb66 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: dart +addons: + rethinkdb: '2.3' +before_script: 'dart test/bootstrap.dart' \ No newline at end of file diff --git a/README.md b/README.md index 9a9ffef1..69c110b2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,86 @@ # rethink + +[![version 1.0.0](https://img.shields.io/badge/pub-1.0.0-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) + RethinkDB-enabled services for the Angel framework. + +# Installation +Add the following to your `pubspec.yaml`: + +```yaml +dependencies: + angel_rethink: ^1.0.0 +``` + +# Usage +This library exposes one main class: `RethinkService`. By default, these services will even +listen to [changefeeds](https://www.rethinkdb.com/docs/changefeeds/ruby/) from the database, +which makes them very suitable for WebSocket use. + +However, only `CREATED`, `UPDATED` and `REMOVED` events will be fired. This is technically not +a problem, as it lowers the numbers of events you have to handle on the client side. ;) + +## Model +`Model` is class with no real functionality; however, it represents a basic document, and your services should host inherited classes. +Other Angel service providers host `Model` as well, so you will easily be able to modify your application if you ever switch databases. + +```dart +class User extends Model { + String username; + String password; +} + +main() async { + var r = new RethinkDb(); + var conn = await r.connect(); + + app.use('/api/users', new RethinkService(conn, r.table('users'))); + + // Add type de/serialization if you want + app.use('/api/users', new TypedService(new RethinkService(conn, r.table('users')))); + + // You don't have to even use a table... + app.use('/api/pro_users', new RethinkService(conn, r.table('users').filter({'membership': 'pro'}))); + + app.service('api/users').afterCreated.listen((event) { + print("New user: ${event.result}"); + }); +} +``` + +## RethinkService +This class interacts with a `Table` (from `package:rethinkdb_driver`) and serializes data to and from Maps. + +## RethinkTypedService +Does the same as above, but serializes to and from a target class using `package:json_god` and its support for reflection. + +## Querying +You can query these services as follows: + + /path/to/service?foo=bar + +The above will query the database to find records where 'foo' equals 'bar'. + +The former will sort result in ascending order of creation, and so will the latter. + +You can use advanced queries: + +```dart +// Pass an actual query... +service.index({'query': r.table('foo').filter(...)}); + +// Or, a function that creates a query from a table... +service.index({'query': (table) => table.getAll('foo')}); + +// Or, a Map, which will be transformed into a `filter` query: +service.index({'query': {'foo': 'bar', 'baz': 'quux'}}); +``` + +You can also apply sorting by adding a `reql` parameter on the server-side. + +```dart +service.index({'reql': (query) => query.sort(...)}); +``` + +See the tests for more usage examples. diff --git a/lib/angel_rethink.dart b/lib/angel_rethink.dart new file mode 100644 index 00000000..e0f27f42 --- /dev/null +++ b/lib/angel_rethink.dart @@ -0,0 +1 @@ +export 'src/rethink_service.dart'; \ No newline at end of file diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart new file mode 100644 index 00000000..98e98097 --- /dev/null +++ b/lib/src/rethink_service.dart @@ -0,0 +1,194 @@ +import 'dart:async'; +import 'package:angel_framework/angel_framework.dart'; +import 'package:json_god/json_god.dart' as god; +import 'package:rethinkdb_driver/rethinkdb_driver.dart'; + +// Extends a RethinkDB query. +typedef RqlQuery QueryCallback(RqlQuery query); + +/// Queries a single RethinkDB table or query. +class RethinkService 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 bool debug; + + /// If set to `true`, then a HookedService mounted over this instance + /// will fire events when RethinkDB pushes events. + /// + /// Good for scaling. ;) + final bool listenForChanges; + + final Connection connection; + + /// Doesn't actually have to be a table, just a RethinkDB query. + /// + /// However, a table is the most common usecase. + final RqlQuery table; + + RethinkService(this.connection, this.table, + {this.allowRemoveAll: false, + this.allowQuery: true, + this.debug: false, + this.listenForChanges: true}) + : super() {} + + RqlQuery _getQuery(RqlQuery query, Map params) { + if (params != null) + params['broadcast'] = + params.containsKey('broadcast') ? params['broadcast'] : false; + + var q = _getQueryInner(query, params); + + if (params?.containsKey('reql') == true && params['reql'] is QueryCallback) + q = params['reql'](q); + + return q ?? query; + } + + RqlQuery _getQueryInner(RqlQuery query, Map params) { + if (params == null || !params.containsKey('query')) + return null; + else { + if (params['query'] is RqlQuery) + return params['query']; + else if (params['query'] is QueryCallback) + return params['query'](table); + else if (params['query'] is! Map || allowQuery != true) + return query; + else { + Map q = params['query']; + return q.keys.map((k) => k.toString()).fold(query, + (out, key) { + var val = q[key]; + + if (val is RequestContext || + val is ResponseContext || + key == 'provider' || + val is Providers) + return out; + else { + return out.filter({k.toString(): val}); + } + }); + } + } + } + + Future _sendQuery(RqlQuery query) async { + var result = await query.run(connection); + + if (result is Cursor) + return await result.toList(); + else if (result is Map && result['generated_keys'] is List) { + if (result['generated_keys'].length == 1) + return await read(result['generated_keys'].first); + return await Future.wait(result['generated_keys'].map(read)); + } else + return result; + } + + Map _serialize(data) { + if (data is Map) + return data; + else + return god.serializeObject(data); + } + + Map _squeeze(Map data) { + return data.keys.fold({}, (map, k) => map..[k.toString()] = data[k]); + } + + void onHooked(HookedService hookedService) { + if (listenForChanges == true) { + listenToQuery(table, hookedService); + } + } + + Future listenToQuery(RqlQuery query, HookedService hookedService) async { + Feed feed = await query.changes({'include_types': true}).run(connection); + + feed.listen((Map event) { + String type = event['type']?.toString(); + var newVal = event['new_val'], oldVal = event['old_val']; + + if (type == 'add') { + // Create + hookedService.fire(HookedServiceEvent.CREATED, newVal); + } else if (type == 'change') { + // Update + hookedService.fire(HookedServiceEvent.UPDATED, newVal, (e) { + e + ..id = oldVal['id'] + ..data = newVal; + }); + } else if (type == 'remove') { + // Remove + hookedService.fire(HookedServiceEvent.CREATED, oldVal, (e) { + e.id = oldVal['id']; + }); + } + }); + } + + @override + Future index([Map params]) async { + var query = _getQuery(table, params); + return await _sendQuery(query); + } + + @override + Future read(id, [Map params]) async { + var query = _getQuery(table.get(id?.toString()), params); + var found = await _sendQuery(query); + print('Found for $id: $found'); + + if (found == null) { + throw new AngelHttpException.notFound( + message: 'No record found for ID $id'); + } else + return found; + } + + @override + Future create(data, [Map params]) async { + if (table is! Table) + throw new StateError( + 'RethinkServices can only create data within tables.'); + + var d = _serialize(data); + var q = table as Table; + var query = _getQuery(q.insert(_squeeze(d)), params); + return await _sendQuery(query); + } + + @override + Future modify(id, data, [Map params]) => update(id, data, params); + + @override + Future update(id, data, [Map params]) async { + var query = _getQuery(table.get(id?.toString()), params).update(data); + await _sendQuery(query); + return await read(id, params); + } + + @override + Future remove(id, [Map params]) async { + if (id == null || + id == 'null' && + (allowRemoveAll == true || + params?.containsKey('provider') != true)) { + return await _sendQuery(table.delete()); + } else { + var prior = await read(id, params); + var query = _getQuery(table.get(id), params).delete(); + await _sendQuery(query); + return prior; + } + } +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 00000000..aab3367b --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,13 @@ +name: angel_rethink +version: 1.0.0 +description: RethinkDB-enabled services for the Angel framework. +author: Tobe O +environment: + sdk: ">=1.19.0" +homepage: https://github.com/angel-dart/rethink +dependencies: + angel_framework: ^1.0.0-dev + rethinkdb_driver: ^2.3.1 +dev_dependencies: + angel_test: ^1.0.0-dev + test: ^0.12.0 \ No newline at end of file diff --git a/test/README.md b/test/README.md new file mode 100644 index 00000000..2b9eed87 --- /dev/null +++ b/test/README.md @@ -0,0 +1,6 @@ +# Tests + +The tests expect you to have installed RethinkDB. You must have a `test` database +available, and a server ready at the default port. + +Also, the tests expect a table named `todos`. \ No newline at end of file diff --git a/test/bootstrap.dart b/test/bootstrap.dart new file mode 100644 index 00000000..01e9454e --- /dev/null +++ b/test/bootstrap.dart @@ -0,0 +1,7 @@ +import 'package:rethinkdb_driver/rethinkdb_driver.dart'; + +main() async { + var r = new Rethinkdb(); + var conn = await r.connect(); + await r.tableCreate('todos').run(conn); +} \ No newline at end of file diff --git a/test/common.dart b/test/common.dart new file mode 100644 index 00000000..15a4b813 --- /dev/null +++ b/test/common.dart @@ -0,0 +1,10 @@ +class Todo { + String title; + bool completed; + + Todo({this.title, this.completed: false}); + + Map toJson() { + return {'title': title, 'completed': completed == true}; + } +} diff --git a/test/generic_test.dart b/test/generic_test.dart new file mode 100644 index 00000000..038c86d3 --- /dev/null +++ b/test/generic_test.dart @@ -0,0 +1,87 @@ +import 'package:angel_client/angel_client.dart' as c; +import 'package:angel_framework/angel_framework.dart'; +import 'package:angel_rethink/angel_rethink.dart'; +import 'package:angel_test/angel_test.dart'; +import 'package:rethinkdb_driver/rethinkdb_driver.dart'; +import 'package:test/test.dart'; +import 'common.dart'; + +main() { + Angel app; + TestClient client; + Rethinkdb r; + c.Service todoService; + + setUp(() async { + r = new Rethinkdb(); + var conn = await r.connect(); + + app = new Angel(); + app.use('/todos', new RethinkService(conn, r.table('todos'))); + + app.onError((e, req, res) async { + print('Whoops: $e'); + }); + + app.fatalErrorStream.listen((e) { + print('Whoops: ${e.error}'); + print(e.stack); + }); + + client = await connectTo(app); + todoService = client.service('todos'); + }); + + tearDown(() => client.close()); + + test('index', () async { + var result = await todoService.index(); + print('Response: $result'); + expect(result, isList); + }); + + test('create+read', () async { + var todo = new Todo(title: 'Clean your room'); + var creation = await todoService.create(todo.toJson()); + print('Creation: $creation'); + + var id = creation['id']; + var result = await todoService.read(id); + + print('Response: $result'); + expect(result, isMap); + expect(result['id'], equals(id)); + expect(result['title'], equals(todo.title)); + expect(result['completed'], equals(todo.completed)); + }); + + test('update', () async { + var todo = new Todo(title: 'Clean your room'); + var creation = await todoService.create(todo.toJson()); + print('Creation: $creation'); + + var id = creation['id']; + var result = await todoService.update(id, {'title': 'Eat healthy'}); + + print('Response: $result'); + expect(result, isMap); + expect(result['id'], equals(id)); + expect(result['title'], equals('Eat healthy')); + expect(result['completed'], equals(todo.completed)); + }); + + test('remove', () async { + var todo = new Todo(title: 'Clean your room'); + var creation = await todoService.create(todo.toJson()); + print('Creation: $creation'); + + var id = creation['id']; + var result = await todoService.remove(id); + + print('Response: $result'); + expect(result, isMap); + expect(result['id'], equals(id)); + expect(result['title'], equals(todo.title)); + expect(result['completed'], equals(todo.completed)); + }); +} From 16cdd2c1bdb5d532288e04e2c63de39a923e8585 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Tue, 21 Feb 2017 22:15:50 -0500 Subject: [PATCH 03/13] README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 69c110b2..4ed3e14b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ dependencies: ``` # Usage -This library exposes one main class: `RethinkService`. By default, these services will even +This library exposes one class: `RethinkService`. By default, these services will even listen to [changefeeds](https://www.rethinkdb.com/docs/changefeeds/ruby/) from the database, which makes them very suitable for WebSocket use. From 228b413ef07eed75fc1dd3c4f37dec931ce004f0 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Tue, 21 Feb 2017 22:34:50 -0500 Subject: [PATCH 04/13] Better bootstrap --- test/bootstrap.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/bootstrap.dart b/test/bootstrap.dart index 01e9454e..5186437d 100644 --- a/test/bootstrap.dart +++ b/test/bootstrap.dart @@ -1,7 +1,11 @@ +import 'dart:io'; import 'package:rethinkdb_driver/rethinkdb_driver.dart'; main() async { var r = new Rethinkdb(); - var conn = await r.connect(); - await r.tableCreate('todos').run(conn); -} \ No newline at end of file + r.connect().then((conn) { + r.tableCreate('todos').run(conn); + print('Done'); + exit(0); + }); +} From f4186e4c9605bbb31496d6f976f35c33d72036c2 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Wed, 22 Feb 2017 17:02:17 -0500 Subject: [PATCH 05/13] 1.0.1 --- README.md | 6 ++++-- lib/src/rethink_service.dart | 38 +++++++++++++++++++++--------------- pubspec.yaml | 2 +- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 4ed3e14b..54f7c5db 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rethink -[![version 1.0.0](https://img.shields.io/badge/pub-1.0.0-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.1](https://img.shields.io/badge/pub-1.0.1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. @@ -13,6 +13,8 @@ dependencies: angel_rethink: ^1.0.0 ``` +`package:rethinkdb_driver` will be installed as well. + # Usage This library exposes one class: `RethinkService`. By default, these services will even listen to [changefeeds](https://www.rethinkdb.com/docs/changefeeds/ruby/) from the database, @@ -50,7 +52,7 @@ main() async { ``` ## RethinkService -This class interacts with a `Table` (from `package:rethinkdb_driver`) and serializes data to and from Maps. +This class interacts with a `Query` (usually a table) and serializes data to and from Maps. ## RethinkTypedService Does the same as above, but serializes to and from a target class using `package:json_god` and its support for reflection. diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index 98e98097..aad667cc 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -38,17 +38,18 @@ class RethinkService extends Service { this.listenForChanges: true}) : super() {} - RqlQuery _getQuery(RqlQuery query, Map params) { + RqlQuery buildQuery(RqlQuery initialQuery, Map params) { if (params != null) - params['broadcast'] = - params.containsKey('broadcast') ? params['broadcast'] : false; + params['broadcast'] = params.containsKey('broadcast') + ? params['broadcast'] + : (listenForChanges != true); - var q = _getQueryInner(query, params); + var q = _getQueryInner(initialQuery, params); if (params?.containsKey('reql') == true && params['reql'] is QueryCallback) q = params['reql'](q); - return q ?? query; + return q ?? initialQuery; } RqlQuery _getQueryInner(RqlQuery query, Map params) { @@ -93,15 +94,22 @@ class RethinkService extends Service { return result; } - Map _serialize(data) { + _serialize(data) { if (data is Map) return data; + else if (data is Iterable) + return data.map(_serialize).toList(); else return god.serializeObject(data); } - Map _squeeze(Map data) { - return data.keys.fold({}, (map, k) => map..[k.toString()] = data[k]); + _squeeze(data) { + if (data is Map) + return data.keys.fold({}, (map, k) => map..[k.toString()] = data[k]); + else if (data is Iterable) + return data.map(_squeeze).toList(); + else + return data; } void onHooked(HookedService hookedService) { @@ -138,13 +146,13 @@ class RethinkService extends Service { @override Future index([Map params]) async { - var query = _getQuery(table, params); + var query = buildQuery(table, params); return await _sendQuery(query); } @override Future read(id, [Map params]) async { - var query = _getQuery(table.get(id?.toString()), params); + var query = buildQuery(table.get(id?.toString()), params); var found = await _sendQuery(query); print('Found for $id: $found'); @@ -157,13 +165,11 @@ class RethinkService extends Service { @override Future create(data, [Map params]) async { - if (table is! Table) - throw new StateError( - 'RethinkServices can only create data within tables.'); + if (table is! Table) throw new AngelHttpException.methodNotAllowed(); var d = _serialize(data); var q = table as Table; - var query = _getQuery(q.insert(_squeeze(d)), params); + var query = buildQuery(q.insert(_squeeze(d)), params); return await _sendQuery(query); } @@ -172,7 +178,7 @@ class RethinkService extends Service { @override Future update(id, data, [Map params]) async { - var query = _getQuery(table.get(id?.toString()), params).update(data); + var query = buildQuery(table.get(id?.toString()), params).update(data); await _sendQuery(query); return await read(id, params); } @@ -186,7 +192,7 @@ class RethinkService extends Service { return await _sendQuery(table.delete()); } else { var prior = await read(id, params); - var query = _getQuery(table.get(id), params).delete(); + var query = buildQuery(table.get(id), params).delete(); await _sendQuery(query); return prior; } diff --git a/pubspec.yaml b/pubspec.yaml index aab3367b..ae6900c0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.0 +version: 1.0.1 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: From ae5b31184ed4de29297e19e05c6e1b35abf3b59e Mon Sep 17 00:00:00 2001 From: thosakwe Date: Wed, 22 Feb 2017 20:08:02 -0500 Subject: [PATCH 06/13] 1.0.2 --- README.md | 2 +- lib/src/rethink_service.dart | 24 +++++++++++++++--------- pubspec.yaml | 2 +- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 54f7c5db..9b082d14 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rethink -[![version 1.0.1](https://img.shields.io/badge/pub-1.0.1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.2](https://img.shields.io/badge/pub-1.0.2-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index aad667cc..41570b75 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -127,19 +127,25 @@ class RethinkService extends Service { if (type == 'add') { // Create - hookedService.fire(HookedServiceEvent.CREATED, newVal); + hookedService.fireEvent( + hookedService.afterCreated, + new HookedServiceEvent( + true, null, null, this, HookedServiceEvent.CREATED, + result: newVal)); } else if (type == 'change') { // Update - hookedService.fire(HookedServiceEvent.UPDATED, newVal, (e) { - e - ..id = oldVal['id'] - ..data = newVal; - }); + hookedService.fireEvent( + hookedService.afterCreated, + new HookedServiceEvent( + true, null, null, this, HookedServiceEvent.UPDATED, + result: newVal, id: oldVal['od'], data: newVal)); } else if (type == 'remove') { // Remove - hookedService.fire(HookedServiceEvent.CREATED, oldVal, (e) { - e.id = oldVal['id']; - }); + hookedService.fireEvent( + hookedService.afterCreated, + new HookedServiceEvent( + true, null, null, this, HookedServiceEventREMOVED, + result: oldVal, id: oldVal['id'])); } }); } diff --git a/pubspec.yaml b/pubspec.yaml index ae6900c0..8ea2aa6b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.1 +version: 1.0.2 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: From 7be95223b42578f4c6329b6350a1a31c343d52c5 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Wed, 1 Mar 2017 23:29:29 -0500 Subject: [PATCH 07/13] 1.0.3 --- README.md | 4 ++-- lib/src/rethink_service.dart | 2 +- pubspec.yaml | 4 ++-- test/bootstrap.dart | 2 +- test/generic_test.dart | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9b082d14..f3346469 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rethink -[![version 1.0.2](https://img.shields.io/badge/pub-1.0.2-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.3](https://img.shields.io/badge/pub-1.0.3-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. @@ -13,7 +13,7 @@ dependencies: angel_rethink: ^1.0.0 ``` -`package:rethinkdb_driver` will be installed as well. +`package:rethinkdb_driver2` will be installed as well. # Usage This library exposes one class: `RethinkService`. By default, these services will even diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index 41570b75..0e14d964 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:angel_framework/angel_framework.dart'; import 'package:json_god/json_god.dart' as god; -import 'package:rethinkdb_driver/rethinkdb_driver.dart'; +import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; // Extends a RethinkDB query. typedef RqlQuery QueryCallback(RqlQuery query); diff --git a/pubspec.yaml b/pubspec.yaml index 8ea2aa6b..edc872fb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.2 +version: 1.0.3 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: @@ -7,7 +7,7 @@ environment: homepage: https://github.com/angel-dart/rethink dependencies: angel_framework: ^1.0.0-dev - rethinkdb_driver: ^2.3.1 + rethinkdb_driver2: ^2.3.1 dev_dependencies: angel_test: ^1.0.0-dev test: ^0.12.0 \ No newline at end of file diff --git a/test/bootstrap.dart b/test/bootstrap.dart index 5186437d..f137f1b3 100644 --- a/test/bootstrap.dart +++ b/test/bootstrap.dart @@ -1,5 +1,5 @@ import 'dart:io'; -import 'package:rethinkdb_driver/rethinkdb_driver.dart'; +import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; main() async { var r = new Rethinkdb(); diff --git a/test/generic_test.dart b/test/generic_test.dart index 038c86d3..e61765bf 100644 --- a/test/generic_test.dart +++ b/test/generic_test.dart @@ -2,7 +2,7 @@ import 'package:angel_client/angel_client.dart' as c; import 'package:angel_framework/angel_framework.dart'; import 'package:angel_rethink/angel_rethink.dart'; import 'package:angel_test/angel_test.dart'; -import 'package:rethinkdb_driver/rethinkdb_driver.dart'; +import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; import 'package:test/test.dart'; import 'common.dart'; From 705c1d8b274a07c30eb2482f5f3ceb2b1595dcbc Mon Sep 17 00:00:00 2001 From: thosakwe Date: Sat, 4 Mar 2017 16:08:15 -0500 Subject: [PATCH 08/13] 1.0.4 --- README.md | 2 +- lib/src/rethink_service.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f3346469..e207a4a1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rethink -[![version 1.0.3](https://img.shields.io/badge/pub-1.0.3-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.4](https://img.shields.io/badge/pub-1.0.4-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index 0e14d964..8f88f247 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -138,7 +138,7 @@ class RethinkService extends Service { hookedService.afterCreated, new HookedServiceEvent( true, null, null, this, HookedServiceEvent.UPDATED, - result: newVal, id: oldVal['od'], data: newVal)); + result: newVal, id: oldVal['id'], data: newVal)); } else if (type == 'remove') { // Remove hookedService.fireEvent( diff --git a/pubspec.yaml b/pubspec.yaml index edc872fb..fb46be59 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.3 +version: 1.0.4 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: From ef3d0bb32aebc872270b36fb3afe7c93569a2cee Mon Sep 17 00:00:00 2001 From: thosakwe Date: Tue, 7 Mar 2017 16:23:09 -0500 Subject: [PATCH 09/13] 1.0.5 --- README.md | 2 +- lib/src/rethink_service.dart | 5 ++--- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e207a4a1..1d29fdd4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rethink -[![version 1.0.4](https://img.shields.io/badge/pub-1.0.4-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.5](https://img.shields.io/badge/pub-1.0.5-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index 8f88f247..0d3e4aac 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -64,8 +64,7 @@ class RethinkService extends Service { return query; else { Map q = params['query']; - return q.keys.map((k) => k.toString()).fold(query, - (out, key) { + return q.keys.fold(query, (out, key) { var val = q[key]; if (val is RequestContext || @@ -74,7 +73,7 @@ class RethinkService extends Service { val is Providers) return out; else { - return out.filter({k.toString(): val}); + return out.filter({key.toString(): val}); } }); } diff --git a/pubspec.yaml b/pubspec.yaml index fb46be59..f53df862 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.4 +version: 1.0.5 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: From 24d45e64b55271f5e7f14026dd66491f4047215c Mon Sep 17 00:00:00 2001 From: thosakwe Date: Tue, 7 Mar 2017 17:06:26 -0500 Subject: [PATCH 10/13] print gone --- README.md | 2 +- lib/src/rethink_service.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1d29fdd4..06280dad 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # rethink -[![version 1.0.5](https://img.shields.io/badge/pub-1.0.5-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.6](https://img.shields.io/badge/pub-1.0.6-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index 0d3e4aac..a869ee59 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -159,7 +159,7 @@ class RethinkService extends Service { Future read(id, [Map params]) async { var query = buildQuery(table.get(id?.toString()), params); var found = await _sendQuery(query); - print('Found for $id: $found'); + //print('Found for $id: $found'); if (found == null) { throw new AngelHttpException.notFound( diff --git a/pubspec.yaml b/pubspec.yaml index f53df862..537cf14c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.5 +version: 1.0.6 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: From 550a334c660e15451225ba0f2c5f0398a87d21e6 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Sun, 9 Apr 2017 22:11:48 -0400 Subject: [PATCH 11/13] 1.0.7 --- README.md | 3 +-- lib/src/rethink_service.dart | 38 +++++++++++++++++++++++++++++++++--- pubspec.yaml | 2 +- test/generic_test.dart | 8 ++++---- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 06280dad..d899a0ff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # rethink - -[![version 1.0.6](https://img.shields.io/badge/pub-1.0.6-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) +[![version 1.0.7](https://img.shields.io/badge/pub-1.0.7-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink) [![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink) RethinkDB-enabled services for the Angel framework. diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index a869ee59..b655f3b1 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:json_god/json_god.dart' as god; import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; @@ -54,7 +55,7 @@ class RethinkService extends Service { RqlQuery _getQueryInner(RqlQuery query, Map params) { if (params == null || !params.containsKey('query')) - return null; + return query; else { if (params['query'] is RqlQuery) return params['query']; @@ -179,11 +180,42 @@ class RethinkService extends Service { } @override - Future modify(id, data, [Map params]) => update(id, data, params); + Future modify(id, data, [Map params]) async { + var d = _serialize(data); + + if (d is Map && d.containsKey('id')) { + try { + await read(d['id'], params); + } on AngelHttpException catch (e) { + if (e.statusCode == HttpStatus.NOT_FOUND) + return await create(data, params); + else + rethrow; + } + } + + var query = buildQuery(table.get(id?.toString()), params).update(d); + await _sendQuery(query); + return await read(id, params); + } @override Future update(id, data, [Map params]) async { - var query = buildQuery(table.get(id?.toString()), params).update(data); + var d = _serialize(data); + + if (d is Map && d.containsKey('id')) { + try { + await read(d['id'], params); + } on AngelHttpException catch (e) { + if (e.statusCode == HttpStatus.NOT_FOUND) + return await create(data, params); + else + rethrow; + } + } + + if (d is Map && !d.containsKey('id')) d['id'] = id.toString(); + var query = buildQuery(table.get(id?.toString()), params).replace(d); await _sendQuery(query); return await read(id, params); } diff --git a/pubspec.yaml b/pubspec.yaml index 537cf14c..242f29cd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_rethink -version: 1.0.6 +version: 1.0.7 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: diff --git a/test/generic_test.dart b/test/generic_test.dart index e61765bf..7d9aec5e 100644 --- a/test/generic_test.dart +++ b/test/generic_test.dart @@ -19,9 +19,9 @@ main() { app = new Angel(); app.use('/todos', new RethinkService(conn, r.table('todos'))); - app.onError((e, req, res) async { + app.errorHandler = (e, req, res) async { print('Whoops: $e'); - }); + }; app.fatalErrorStream.listen((e) { print('Whoops: ${e.error}'); @@ -55,13 +55,13 @@ main() { expect(result['completed'], equals(todo.completed)); }); - test('update', () async { + test('modify', () async { var todo = new Todo(title: 'Clean your room'); var creation = await todoService.create(todo.toJson()); print('Creation: $creation'); var id = creation['id']; - var result = await todoService.update(id, {'title': 'Eat healthy'}); + var result = await todoService.modify(id, {'title': 'Eat healthy'}); print('Response: $result'); expect(result, isMap); From 1207881c71daff0d17b069435485a7b640caf6e8 Mon Sep 17 00:00:00 2001 From: Tobe O Date: Sun, 3 Jun 2018 21:35:44 -0400 Subject: [PATCH 12/13] 1.1.0 --- .gitignore | 3 ++- CHANGELOG.md | 3 +++ lib/src/rethink_service.dart | 14 +++++++------- pubspec.yaml | 13 ++++++++----- test/bootstrap.dart | 2 +- test/generic_test.dart | 8 +++----- 6 files changed, 24 insertions(+), 19 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.gitignore b/.gitignore index 5d2a807f..b29d1dd1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,5 @@ doc/api/ # (Library packages only! Remove pattern if developing an application package) pubspec.lock -rethinkdb_data/ \ No newline at end of file +rethinkdb_data/ +.idea \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3c801a88 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# 1.1.0 +* Moved to `package:rethinkdb_driver` +* Fixed references to old hooked event names. \ No newline at end of file diff --git a/lib/src/rethink_service.dart b/lib/src/rethink_service.dart index b655f3b1..da37906f 100644 --- a/lib/src/rethink_service.dart +++ b/lib/src/rethink_service.dart @@ -1,8 +1,8 @@ import 'dart:async'; -import 'dart:io'; +//import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:json_god/json_god.dart' as god; -import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; +import 'package:rethinkdb_driver/rethinkdb_driver.dart'; // Extends a RethinkDB query. typedef RqlQuery QueryCallback(RqlQuery query); @@ -130,21 +130,21 @@ class RethinkService extends Service { hookedService.fireEvent( hookedService.afterCreated, new HookedServiceEvent( - true, null, null, this, HookedServiceEvent.CREATED, + true, null, null, this, HookedServiceEvent.created, result: newVal)); } else if (type == 'change') { // Update hookedService.fireEvent( hookedService.afterCreated, new HookedServiceEvent( - true, null, null, this, HookedServiceEvent.UPDATED, + true, null, null, this, HookedServiceEvent.updated, result: newVal, id: oldVal['id'], data: newVal)); } else if (type == 'remove') { // Remove hookedService.fireEvent( hookedService.afterCreated, new HookedServiceEvent( - true, null, null, this, HookedServiceEventREMOVED, + true, null, null, this, HookedServiceEvent.removed, result: oldVal, id: oldVal['id'])); } }); @@ -187,7 +187,7 @@ class RethinkService extends Service { try { await read(d['id'], params); } on AngelHttpException catch (e) { - if (e.statusCode == HttpStatus.NOT_FOUND) + if (e.statusCode == 404) return await create(data, params); else rethrow; @@ -207,7 +207,7 @@ class RethinkService extends Service { try { await read(d['id'], params); } on AngelHttpException catch (e) { - if (e.statusCode == HttpStatus.NOT_FOUND) + if (e.statusCode == 404) return await create(data, params); else rethrow; diff --git a/pubspec.yaml b/pubspec.yaml index 242f29cd..9d5c6ce1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,13 +1,16 @@ name: angel_rethink -version: 1.0.7 +version: 1.1.0 description: RethinkDB-enabled services for the Angel framework. author: Tobe O environment: - sdk: ">=1.19.0" + sdk: ">=1.19.0 <3.0.0" homepage: https://github.com/angel-dart/rethink dependencies: - angel_framework: ^1.0.0-dev - rethinkdb_driver2: ^2.3.1 + angel_framework: ^1.1.0 + json_god: ^2.0.0-beta + rethinkdb_driver: ^2.3.1 dev_dependencies: - angel_test: ^1.0.0-dev + angel_client: ^1.1.0 + angel_test: ^1.1.0 + logging: ^0.11.3 test: ^0.12.0 \ No newline at end of file diff --git a/test/bootstrap.dart b/test/bootstrap.dart index f137f1b3..5186437d 100644 --- a/test/bootstrap.dart +++ b/test/bootstrap.dart @@ -1,5 +1,5 @@ import 'dart:io'; -import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; +import 'package:rethinkdb_driver/rethinkdb_driver.dart'; main() async { var r = new Rethinkdb(); diff --git a/test/generic_test.dart b/test/generic_test.dart index 7d9aec5e..ee9ee169 100644 --- a/test/generic_test.dart +++ b/test/generic_test.dart @@ -2,7 +2,8 @@ import 'package:angel_client/angel_client.dart' as c; import 'package:angel_framework/angel_framework.dart'; import 'package:angel_rethink/angel_rethink.dart'; import 'package:angel_test/angel_test.dart'; -import 'package:rethinkdb_driver2/rethinkdb_driver2.dart'; +import 'package:logging/logging.dart'; +import 'package:rethinkdb_driver/rethinkdb_driver.dart'; import 'package:test/test.dart'; import 'common.dart'; @@ -23,10 +24,7 @@ main() { print('Whoops: $e'); }; - app.fatalErrorStream.listen((e) { - print('Whoops: ${e.error}'); - print(e.stack); - }); + app.logger = new Logger.detached('angel')..onRecord.listen(print); client = await connectTo(app); todoService = client.service('todos'); From 6cc85e04095bf1665bf18d1f626930f0e61c0cb2 Mon Sep 17 00:00:00 2001 From: Tobe O Date: Sun, 3 Jun 2018 21:49:28 -0400 Subject: [PATCH 13/13] Ignore .dart_tool --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b29d1dd1..20880a05 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,5 @@ doc/api/ pubspec.lock rethinkdb_data/ -.idea \ No newline at end of file +.idea +.dart_tool \ No newline at end of file