Merge pull request #87 from dukefirehawk/feature/fix-deprecated
Feature/fix deprecated
This commit is contained in:
commit
a7c750e70f
155 changed files with 164 additions and 5786 deletions
4
.github/workflows/dart.yml
vendored
4
.github/workflows/dart.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
|
|
||||||
- uses: dart-lang/setup-dart@v1
|
- uses: dart-lang/setup-dart@v1
|
||||||
with:
|
with:
|
||||||
sdk: "2.17.0"
|
sdk: "2.18.0"
|
||||||
|
|
||||||
- id: angel3_container_upgrade
|
- id: angel3_container_upgrade
|
||||||
name: angel3_container; Upgrade depedencies
|
name: angel3_container; Upgrade depedencies
|
||||||
|
@ -87,7 +87,7 @@ jobs:
|
||||||
|
|
||||||
- uses: dart-lang/setup-dart@v1
|
- uses: dart-lang/setup-dart@v1
|
||||||
with:
|
with:
|
||||||
sdk: "2.17.0"
|
sdk: "2.18.0"
|
||||||
|
|
||||||
# Angel3 ORM
|
# Angel3 ORM
|
||||||
- id: angel3_orm_upgrade
|
- id: angel3_orm_upgrade
|
||||||
|
|
BIN
archived_packages/eventsource.zip
Normal file
BIN
archived_packages/eventsource.zip
Normal file
Binary file not shown.
65
archived_packages/eventsource/.gitignore
vendored
65
archived_packages/eventsource/.gitignore
vendored
|
@ -1,65 +0,0 @@
|
||||||
# Created by .ignore support plugin (hsz.mobi)
|
|
||||||
### JetBrains template
|
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
||||||
|
|
||||||
# User-specific stuff:
|
|
||||||
.idea/**/workspace.xml
|
|
||||||
.idea/**/tasks.xml
|
|
||||||
.idea/dictionaries
|
|
||||||
|
|
||||||
# Sensitive or high-churn files:
|
|
||||||
.idea/**/dataSources/
|
|
||||||
.idea/**/dataSources.ids
|
|
||||||
.idea/**/dataSources.xml
|
|
||||||
.idea/**/dataSources.local.xml
|
|
||||||
.idea/**/sqlDataSources.xml
|
|
||||||
.idea/**/dynamic.xml
|
|
||||||
.idea/**/uiDesigner.xml
|
|
||||||
|
|
||||||
# Gradle:
|
|
||||||
.idea/**/gradle.xml
|
|
||||||
.idea/**/libraries
|
|
||||||
|
|
||||||
# CMake
|
|
||||||
cmake-build-debug/
|
|
||||||
|
|
||||||
# Mongo Explorer plugin:
|
|
||||||
.idea/**/mongoSettings.xml
|
|
||||||
|
|
||||||
## File-based project format:
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
## Plugin-specific files:
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
|
||||||
.idea_modules/
|
|
||||||
|
|
||||||
# JIRA plugin
|
|
||||||
atlassian-ide-plugin.xml
|
|
||||||
|
|
||||||
# Cursive Clojure plugin
|
|
||||||
.idea/replstate.xml
|
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
fabric.properties
|
|
||||||
### Dart template
|
|
||||||
# See https://www.dartlang.org/tools/private-files.html
|
|
||||||
|
|
||||||
# Files and directories created by pub
|
|
||||||
.packages
|
|
||||||
.pub/
|
|
||||||
build/
|
|
||||||
# If you're building an application, you may want to check-in your pubspec.lock
|
|
||||||
pubspec.lock
|
|
||||||
|
|
||||||
# Directory created by dartdoc
|
|
||||||
# If you don't generate documentation locally you can remove this line.
|
|
||||||
doc/api/
|
|
||||||
.dart_tool
|
|
|
@ -1,21 +0,0 @@
|
||||||
MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1,33 +0,0 @@
|
||||||
# eventsource
|
|
||||||
Server-sent Events (SSE) plugin for Angel.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
In your `pubspec.yaml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
dependencies:
|
|
||||||
angel_eventsource: ^1.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
SSE and WebSockets are somewhat similar in that they allow pushing of events from server
|
|
||||||
to client. SSE is not bi-directional, but the same abstractions used for WebSockets can be
|
|
||||||
applied to SSE easily.
|
|
||||||
|
|
||||||
For this reason, the `AngelEventSourcePublisher` class is a simple adapter that
|
|
||||||
hands control of SSE requests to an existing `AngelWebSocket` driver.
|
|
||||||
|
|
||||||
So, using this is pretty straightforward. You can dispatch events
|
|
||||||
via WebSocket as per usual, and have them propagated to SSE clients
|
|
||||||
as well.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
var app = new Angel();
|
|
||||||
var ws = new AngelWebSocket(app);
|
|
||||||
var events = new AngelEventSourcePublisher(ws);
|
|
||||||
|
|
||||||
await app.configure(ws.configureServer);
|
|
||||||
|
|
||||||
app.all('/ws', ws.handleRequest);
|
|
||||||
app.get('/events', events.handleRequest);
|
|
||||||
```
|
|
|
@ -1,3 +0,0 @@
|
||||||
analyzer:
|
|
||||||
strong-mode:
|
|
||||||
implicit-casts: false
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
|
||||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
|
@ -1,50 +0,0 @@
|
||||||
import 'package:angel_eventsource/server.dart';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_framework/http.dart';
|
|
||||||
import 'package:angel_websocket/server.dart';
|
|
||||||
import 'package:eventsource/eventsource.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'pretty_logging.dart';
|
|
||||||
|
|
||||||
main() async {
|
|
||||||
var app = new Angel();
|
|
||||||
var ws = new AngelWebSocket(app);
|
|
||||||
var events = new AngelEventSourcePublisher(ws);
|
|
||||||
|
|
||||||
await app.configure(ws.configureServer);
|
|
||||||
|
|
||||||
app.use('/api/todos', new MapService());
|
|
||||||
app.all('/ws', ws.handleRequest);
|
|
||||||
app.get('/events', events.handleRequest);
|
|
||||||
|
|
||||||
app.logger = new Logger('angel_eventsource')..onRecord.listen(prettyLog);
|
|
||||||
|
|
||||||
var http = new AngelHttp(app);
|
|
||||||
var server = await http.startServer('127.0.0.1', 3000);
|
|
||||||
var url = Uri.parse('http://${server.address.address}:${server.port}');
|
|
||||||
print('Listening at $url');
|
|
||||||
|
|
||||||
/*
|
|
||||||
var sock = await Socket.connect(server.address, server.port);
|
|
||||||
sock
|
|
||||||
..writeln('GET /sse HTTP/1.1')
|
|
||||||
..writeln('Accept: text/event-stream')
|
|
||||||
..writeln('Host: 127.0.0.1')
|
|
||||||
..writeln()
|
|
||||||
..flush();
|
|
||||||
sock.transform(UTF8.decoder).transform(const LineSplitter()).listen(print);
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
var client = new HttpClient();
|
|
||||||
var rq = await client.openUrl('GET', url);
|
|
||||||
var rs = await rq.close();
|
|
||||||
rs.transform(UTF8.decoder).transform(const LineSplitter()).listen(print);
|
|
||||||
*/
|
|
||||||
|
|
||||||
var eventSource = await EventSource.connect(url);
|
|
||||||
|
|
||||||
await for (var event in eventSource) {
|
|
||||||
print(event.data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
import 'package:console/console.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
|
|
||||||
/// Prints the contents of a [LogRecord] with pretty colors.
|
|
||||||
prettyLog(LogRecord record) async {
|
|
||||||
var pen = new TextPen();
|
|
||||||
chooseLogColor(pen.reset(), record.level);
|
|
||||||
pen(record.toString());
|
|
||||||
|
|
||||||
if (record.error != null) pen(record.error.toString());
|
|
||||||
if (record.stackTrace != null) pen(record.stackTrace.toString());
|
|
||||||
|
|
||||||
pen();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Chooses a color based on the logger [level].
|
|
||||||
void chooseLogColor(TextPen pen, Level level) {
|
|
||||||
if (level == Level.SHOUT)
|
|
||||||
pen.darkRed();
|
|
||||||
else if (level == Level.SEVERE)
|
|
||||||
pen.red();
|
|
||||||
else if (level == Level.WARNING)
|
|
||||||
pen.yellow();
|
|
||||||
else if (level == Level.INFO)
|
|
||||||
pen.magenta();
|
|
||||||
else if (level == Level.FINER)
|
|
||||||
pen.blue();
|
|
||||||
else if (level == Level.FINEST) pen.darkBlue();
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export 'package:angel_websocket/angel_websocket.dart';
|
|
|
@ -1,51 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_websocket/server.dart';
|
|
||||||
import 'package:eventsource/eventsource.dart';
|
|
||||||
import 'package:eventsource/src/encoder.dart';
|
|
||||||
import 'package:eventsource/publisher.dart';
|
|
||||||
import 'package:stream_channel/stream_channel.dart';
|
|
||||||
|
|
||||||
class AngelEventSourcePublisher {
|
|
||||||
final AngelWebSocket webSocketDriver;
|
|
||||||
|
|
||||||
final String channel;
|
|
||||||
|
|
||||||
int _count = 0;
|
|
||||||
|
|
||||||
AngelEventSourcePublisher(this.webSocketDriver, {this.channel: ''});
|
|
||||||
|
|
||||||
Future handleRequest(RequestContext req, ResponseContext res) async {
|
|
||||||
if (!req.accepts('text/event-stream', strict: false))
|
|
||||||
throw new AngelHttpException.badRequest();
|
|
||||||
|
|
||||||
res.headers.addAll({
|
|
||||||
'cache-control': 'no-cache, no-store, must-revalidate',
|
|
||||||
'content-type': 'text/event-stream',
|
|
||||||
'connection': 'keep-alive',
|
|
||||||
});
|
|
||||||
|
|
||||||
var acceptsGzip =
|
|
||||||
(req.headers['accept-encoding']?.contains('gzip') == true);
|
|
||||||
|
|
||||||
if (acceptsGzip) res.headers['content-encoding'] = 'gzip';
|
|
||||||
|
|
||||||
var eventSink = new EventSourceEncoder(compressed: acceptsGzip)
|
|
||||||
.startChunkedConversion(res);
|
|
||||||
|
|
||||||
// Listen for events.
|
|
||||||
var ctrl = new StreamChannelController();
|
|
||||||
|
|
||||||
// Incoming events are strings, and should be sent via the eventSink.
|
|
||||||
ctrl.local.stream.cast<String>().listen((data) {
|
|
||||||
eventSink.add(new Event(
|
|
||||||
id: (_count++).toString(),
|
|
||||||
data: data,
|
|
||||||
));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a new WebSocketContext, and hand it off to the driver.
|
|
||||||
var socket = new WebSocketContext(ctrl.foreign, req, res);
|
|
||||||
return await webSocketDriver.handleClient(socket);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
name: angel_eventsource
|
|
||||||
version: 2.0.0
|
|
||||||
description: Server-sent Events (SSE) plugin for Angel.
|
|
||||||
homepage: https://github.com/angel-dart/eventsource
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.10.0 <3.0.0"
|
|
||||||
dependencies:
|
|
||||||
angel_framework:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x
|
|
||||||
path: packages/framework
|
|
||||||
angel_websocket:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x
|
|
||||||
path: packages/websocket
|
|
||||||
eventsource:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/dart-eventsource.git
|
|
||||||
stream_channel: ^2.0.0
|
|
||||||
dev_dependencies:
|
|
||||||
console: ^4.0.0
|
|
||||||
logging: ^1.0.0
|
|
||||||
test: ^1.16.5
|
|
BIN
archived_packages/orm.zip
Normal file
BIN
archived_packages/orm.zip
Normal file
Binary file not shown.
|
@ -1,21 +0,0 @@
|
||||||
MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2021 dukefirehawk.com
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1,5 +0,0 @@
|
||||||
name: angel_orm_sqlite
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.16.0 <3.0.0"
|
|
||||||
dependencies:
|
|
||||||
angel_orm: ^2.0.0-dev
|
|
BIN
archived_packages/poll.zip
Normal file
BIN
archived_packages/poll.zip
Normal file
Binary file not shown.
64
archived_packages/poll/.gitignore
vendored
64
archived_packages/poll/.gitignore
vendored
|
@ -1,64 +0,0 @@
|
||||||
# Created by .ignore support plugin (hsz.mobi)
|
|
||||||
### JetBrains template
|
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
||||||
|
|
||||||
# User-specific stuff:
|
|
||||||
.idea/**/workspace.xml
|
|
||||||
.idea/**/tasks.xml
|
|
||||||
.idea/dictionaries
|
|
||||||
|
|
||||||
# Sensitive or high-churn files:
|
|
||||||
.idea/**/dataSources/
|
|
||||||
.idea/**/dataSources.ids
|
|
||||||
.idea/**/dataSources.xml
|
|
||||||
.idea/**/dataSources.local.xml
|
|
||||||
.idea/**/sqlDataSources.xml
|
|
||||||
.idea/**/dynamic.xml
|
|
||||||
.idea/**/uiDesigner.xml
|
|
||||||
|
|
||||||
# Gradle:
|
|
||||||
.idea/**/gradle.xml
|
|
||||||
.idea/**/libraries
|
|
||||||
|
|
||||||
# CMake
|
|
||||||
cmake-build-debug/
|
|
||||||
|
|
||||||
# Mongo Explorer plugin:
|
|
||||||
.idea/**/mongoSettings.xml
|
|
||||||
|
|
||||||
## File-based project format:
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
## Plugin-specific files:
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
|
||||||
.idea_modules/
|
|
||||||
|
|
||||||
# JIRA plugin
|
|
||||||
atlassian-ide-plugin.xml
|
|
||||||
|
|
||||||
# Cursive Clojure plugin
|
|
||||||
.idea/replstate.xml
|
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
fabric.properties
|
|
||||||
### Dart template
|
|
||||||
# See https://www.dartlang.org/tools/private-files.html
|
|
||||||
|
|
||||||
# Files and directories created by pub
|
|
||||||
.packages
|
|
||||||
.pub/
|
|
||||||
build/
|
|
||||||
# If you're building an application, you may want to check-in your pubspec.lock
|
|
||||||
pubspec.lock
|
|
||||||
|
|
||||||
# Directory created by dartdoc
|
|
||||||
# If you don't generate documentation locally you can remove this line.
|
|
||||||
doc/api/
|
|
|
@ -1 +0,0 @@
|
||||||
language: dart
|
|
|
@ -1,12 +0,0 @@
|
||||||
Primary Authors
|
|
||||||
===============
|
|
||||||
|
|
||||||
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
|
||||||
|
|
||||||
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
|
||||||
code base to support NNBD.
|
|
||||||
|
|
||||||
* __[Tobe O](thosakwe@gmail.com)__
|
|
||||||
|
|
||||||
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
|
||||||
is no longer involved with the project.
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
## 2.0.0
|
|
||||||
|
|
||||||
* Migrated to support Dart >= 2.12 NNBD
|
|
||||||
|
|
||||||
## 1.0.0
|
|
||||||
|
|
||||||
* Created package + tests
|
|
|
@ -1,29 +0,0 @@
|
||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2021, dukefirehawk.com
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,42 +0,0 @@
|
||||||
# poll
|
|
||||||
[![Pub](https://img.shields.io/pub/v/angel_poll.svg)](https://pub.dartlang.org/packages/angel_poll)
|
|
||||||
[![build status](https://travis-ci.org/angel-dart/poll.svg?branch=master)](https://travis-ci.org/angel-dart/poll)
|
|
||||||
|
|
||||||
`package:angel_client` support for "realtime" interactions with Angel via long polling.
|
|
||||||
|
|
||||||
Angel supports [WebSockets](https://github.com/angel-dart/websocket) on the server and client, which
|
|
||||||
makes it very straightforward to implement realtime collections. However, not every user's browser
|
|
||||||
supports WebSockets. In such a case, applications might *gracefully degrade* to long-polling
|
|
||||||
the server for changes.
|
|
||||||
|
|
||||||
A `PollingService` wraps a client-side `Service` (typically a REST-based one), and calls its
|
|
||||||
`index` method at a regular interval. After indexing, the `PollingService` performs a diff
|
|
||||||
and identifies whether items have been created, modified, or removed. The updates are sent out
|
|
||||||
through `onCreated`, `onModified`, etc., effectively managing a real-time collection of data.
|
|
||||||
|
|
||||||
A common use-case would be passing this service to `ServiceList`, a class that manages the state
|
|
||||||
of a collection managed in real-time.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
import 'package:angel_client/io.dart';
|
|
||||||
import 'package:angel_poll/angel_poll.dart';
|
|
||||||
|
|
||||||
main() {
|
|
||||||
var app = new Rest('http://localhost:3000');
|
|
||||||
|
|
||||||
var todos = new ServiceList(
|
|
||||||
new PollingService(
|
|
||||||
// Typically, you'll pass a REST-based service instance here.
|
|
||||||
app.service('api/todos'),
|
|
||||||
|
|
||||||
// `index` called every 5 seconds
|
|
||||||
const Duration(seconds: 5),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
todos.onChange.listen((_) {
|
|
||||||
// Something happened here.
|
|
||||||
// Maybe an item was created, modified, etc.
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1 +0,0 @@
|
||||||
include: package:lints/recommended.yaml
|
|
|
@ -1,21 +0,0 @@
|
||||||
import 'package:angel_client/io.dart';
|
|
||||||
import 'package:angel_poll/angel_poll.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
var app = Rest('http://localhost:3000');
|
|
||||||
|
|
||||||
var todos = ServiceList(
|
|
||||||
PollingService(
|
|
||||||
// Typically, you'll pass a REST-based service instance here.
|
|
||||||
app.service('api/todos'),
|
|
||||||
|
|
||||||
// `index` called every 5 seconds
|
|
||||||
const Duration(seconds: 5),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
todos.onChange.listen((_) {
|
|
||||||
// Something happened here.
|
|
||||||
// Maybe an item was created, modified, etc.
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,265 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:angel_client/angel_client.dart';
|
|
||||||
|
|
||||||
/// A [Service] that facilitates real-time updates via the long polling of an [inner] service.
|
|
||||||
///
|
|
||||||
/// Works well with [ServiceList].
|
|
||||||
class PollingService extends Service {
|
|
||||||
/// The underlying [Service] that does the actual communication with the server.
|
|
||||||
final Service inner;
|
|
||||||
|
|
||||||
/// Perform computations after polling to discern whether new items were created.
|
|
||||||
final bool checkForCreated;
|
|
||||||
|
|
||||||
/// Perform computations after polling to discern whether items were modified.
|
|
||||||
final bool checkForModified;
|
|
||||||
|
|
||||||
/// Perform computations after polling to discern whether items were removed.
|
|
||||||
final bool checkForRemoved;
|
|
||||||
|
|
||||||
/// An [EqualityBy] used to compare the ID's of two items.
|
|
||||||
///
|
|
||||||
/// Defaults to comparing the [idField] of two `Map` instances.
|
|
||||||
final EqualityBy compareId;
|
|
||||||
|
|
||||||
/// An [Equality] used to discern whether two items, with the same [idField], are the same item.
|
|
||||||
///
|
|
||||||
/// Defaults to [MapEquality], which deep-compares `Map` instances.
|
|
||||||
final Equality compareItems;
|
|
||||||
|
|
||||||
/// A [String] used as an index through which to compare `Map` instances.
|
|
||||||
///
|
|
||||||
/// Defaults to `id`.
|
|
||||||
final String idField;
|
|
||||||
|
|
||||||
/// If `true` (default: `false`), then `index` events will be handled as a [Map] containing a `data` field.
|
|
||||||
///
|
|
||||||
/// See https://github.com/angel-dart/paginate.
|
|
||||||
final bool asPaginated;
|
|
||||||
|
|
||||||
final List _items = [];
|
|
||||||
final List<StreamSubscription> _subs = [];
|
|
||||||
|
|
||||||
final StreamController<List<dynamic>> _onIndexed = StreamController(),
|
|
||||||
_onRead = StreamController(),
|
|
||||||
_onCreated = StreamController(),
|
|
||||||
_onModified = StreamController(),
|
|
||||||
_onUpdated = StreamController(),
|
|
||||||
_onRemoved = StreamController();
|
|
||||||
|
|
||||||
late Timer _timer;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Angel get app => inner.app;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<List<dynamic>> get onIndexed => _onIndexed.stream;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream get onRead => _onRead.stream;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream get onCreated => _onCreated.stream;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream get onModified => _onModified.stream;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream get onUpdated => _onUpdated.stream;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream get onRemoved => _onRemoved.stream;
|
|
||||||
|
|
||||||
PollingService(this.inner, Duration interval,
|
|
||||||
{this.checkForCreated = true,
|
|
||||||
this.checkForModified = true,
|
|
||||||
this.checkForRemoved = true,
|
|
||||||
this.idField = 'id',
|
|
||||||
this.asPaginated = false,
|
|
||||||
EqualityBy? compareId,
|
|
||||||
this.compareItems = const MapEquality()})
|
|
||||||
: compareId = compareId ?? EqualityBy((map) => map[idField]) {
|
|
||||||
_timer = Timer.periodic(interval, (_) {
|
|
||||||
index().catchError((error) {
|
|
||||||
_onIndexed.addError(error as Object);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var streams = <Stream, StreamController>{
|
|
||||||
inner.onRead: _onRead,
|
|
||||||
inner.onCreated: _onCreated,
|
|
||||||
inner.onModified: _onModified,
|
|
||||||
inner.onUpdated: _onUpdated,
|
|
||||||
inner.onRemoved: _onRemoved,
|
|
||||||
};
|
|
||||||
|
|
||||||
streams.forEach((stream, ctrl) {
|
|
||||||
_subs.add(stream.listen(ctrl.add, onError: ctrl.addError));
|
|
||||||
});
|
|
||||||
|
|
||||||
_subs.add(
|
|
||||||
inner.onIndexed.listen(
|
|
||||||
_handleIndexed,
|
|
||||||
onError: _onIndexed.addError,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future close() async {
|
|
||||||
_timer.cancel();
|
|
||||||
for (var s in _subs) {
|
|
||||||
s.cancel();
|
|
||||||
}
|
|
||||||
await _onIndexed.close();
|
|
||||||
await _onRead.close();
|
|
||||||
await _onCreated.close();
|
|
||||||
await _onModified.close();
|
|
||||||
await _onUpdated.close();
|
|
||||||
await _onRemoved.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: To revisit this logic
|
|
||||||
@override
|
|
||||||
Future<List<dynamic>> index([Map? params]) {
|
|
||||||
return inner.index().then((data) {
|
|
||||||
//return asPaginated == true ? data['data'] : data;
|
|
||||||
//return asPaginated == true ? data[0] : data;
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@override
|
|
||||||
Future index([Map params]) {
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@override
|
|
||||||
Future remove(id, [Map<String, dynamic>? params]) {
|
|
||||||
return inner.remove(id, params).then((result) {
|
|
||||||
_items.remove(result);
|
|
||||||
return result;
|
|
||||||
}).catchError(_onRemoved.addError);
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _handleUpdate(result) {
|
|
||||||
var index = -1;
|
|
||||||
|
|
||||||
for (var i = 0; i < _items.length; i++) {
|
|
||||||
if (compareId.equals(_items[i], result)) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index > -1) {
|
|
||||||
_items[index] = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future update(id, data, [Map<String, dynamic>? params]) {
|
|
||||||
return inner
|
|
||||||
.update(id, data, params)
|
|
||||||
.then(_handleUpdate)
|
|
||||||
.catchError(_onUpdated.addError);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future modify(id, data, [Map<String, dynamic>? params]) {
|
|
||||||
return inner
|
|
||||||
.modify(id, data, params)
|
|
||||||
.then(_handleUpdate)
|
|
||||||
.catchError(_onModified.addError);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future create(data, [Map<String, dynamic>? params]) {
|
|
||||||
return inner.create(data, params).then((result) {
|
|
||||||
_items.add(result);
|
|
||||||
return result;
|
|
||||||
}).catchError(_onCreated.addError);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future read(id, [Map<String, dynamic>? params]) {
|
|
||||||
return inner.read(id, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleIndexed(List<dynamic> data) {
|
|
||||||
//var items = asPaginated == true ? data['data'] : data;
|
|
||||||
var items = data;
|
|
||||||
var changesComputed = false;
|
|
||||||
|
|
||||||
if (checkForCreated != false) {
|
|
||||||
var newItems = <int, dynamic>{};
|
|
||||||
|
|
||||||
for (var i = 0; i < items.length; i++) {
|
|
||||||
var item = items[i];
|
|
||||||
|
|
||||||
if (!_items.any((i) => compareId.equals(i, item))) {
|
|
||||||
newItems[i] = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newItems.forEach((index, item) {
|
|
||||||
_items.insert(index, item);
|
|
||||||
_onCreated.add([item]);
|
|
||||||
});
|
|
||||||
|
|
||||||
changesComputed = newItems.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkForRemoved != false) {
|
|
||||||
var removedItems = <int, dynamic>{};
|
|
||||||
|
|
||||||
for (var i = 0; i < _items.length; i++) {
|
|
||||||
var item = _items[i];
|
|
||||||
|
|
||||||
if (!items.any((i) => compareId.equals(i, item))) {
|
|
||||||
removedItems[i] = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removedItems.forEach((index, item) {
|
|
||||||
_items.removeAt(index);
|
|
||||||
_onRemoved.add([item]);
|
|
||||||
});
|
|
||||||
|
|
||||||
changesComputed = changesComputed || removedItems.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkForModified != false) {
|
|
||||||
var modifiedItems = <int, dynamic>{};
|
|
||||||
|
|
||||||
for (var item in items) {
|
|
||||||
for (var i = 0; i < _items.length; i++) {
|
|
||||||
var localItem = _items[i];
|
|
||||||
|
|
||||||
if (compareId.equals(item, localItem)) {
|
|
||||||
if (!compareItems.equals(item, localItem)) {
|
|
||||||
modifiedItems[i] = item;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modifiedItems.forEach((index, item) {
|
|
||||||
_onModified.add([_items[index] = item]);
|
|
||||||
});
|
|
||||||
|
|
||||||
changesComputed = changesComputed || modifiedItems.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!changesComputed) {
|
|
||||||
_items
|
|
||||||
..clear()
|
|
||||||
..add(items);
|
|
||||||
_onIndexed.add([items]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
|
||||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
|
@ -1,23 +0,0 @@
|
||||||
name: angel_poll
|
|
||||||
version: 2.0.0
|
|
||||||
description: package:angel_client support for "realtime" interactions with Angel via long polling.
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
|
||||||
homepage: https://github.com/angel-dart/poll
|
|
||||||
dependencies:
|
|
||||||
angel_client: # ^1.0.0
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/client
|
|
||||||
async: ^2.7.0
|
|
||||||
collection: ^1.15.0
|
|
||||||
dev_dependencies:
|
|
||||||
angel_test:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/test
|
|
||||||
test: ^1.17.8
|
|
||||||
lints: ^1.0.0
|
|
|
@ -1,105 +0,0 @@
|
||||||
import 'package:angel_framework/angel_framework.dart' as srv;
|
|
||||||
import 'package:angel_container/mirrors.dart';
|
|
||||||
import 'package:angel_poll/angel_poll.dart';
|
|
||||||
import 'package:angel_test/angel_test.dart';
|
|
||||||
import 'package:async/async.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
late srv.Service store;
|
|
||||||
late TestClient client;
|
|
||||||
late PollingService pollingService;
|
|
||||||
|
|
||||||
var created;
|
|
||||||
late StreamQueue onCreated;
|
|
||||||
late StreamQueue onModified;
|
|
||||||
late StreamQueue onRemoved;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
var app = srv.Angel(reflector: MirrorsReflector());
|
|
||||||
app.logger = Logger.detached('angel_poll')
|
|
||||||
..onRecord.listen((rec) {
|
|
||||||
print(rec);
|
|
||||||
if (rec.error != null) {
|
|
||||||
print(rec.error);
|
|
||||||
print(rec.stackTrace);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
store = app.use(
|
|
||||||
'/api/todos',
|
|
||||||
srv.MapService(
|
|
||||||
autoIdAndDateFields: false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
client = await connectTo(app);
|
|
||||||
|
|
||||||
pollingService = PollingService(
|
|
||||||
client.service('api/todos'),
|
|
||||||
const Duration(milliseconds: 100),
|
|
||||||
);
|
|
||||||
|
|
||||||
onCreated = StreamQueue(pollingService.onCreated);
|
|
||||||
onModified = StreamQueue(pollingService.onModified);
|
|
||||||
onRemoved = StreamQueue(pollingService.onRemoved);
|
|
||||||
|
|
||||||
created = await store.create({
|
|
||||||
'id': '0',
|
|
||||||
'text': 'Clean your room',
|
|
||||||
'completed': false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() {
|
|
||||||
onCreated.cancel();
|
|
||||||
onModified.cancel();
|
|
||||||
onRemoved.cancel();
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
group('events', () {
|
|
||||||
test('fires indexed', () async {
|
|
||||||
var indexed = await pollingService.index();
|
|
||||||
print(indexed);
|
|
||||||
expect(await pollingService.onIndexed.first, indexed);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('fires created', () async {
|
|
||||||
var result = await onCreated.next;
|
|
||||||
print(result);
|
|
||||||
expect(created, result);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('fires modified', () async {
|
|
||||||
await pollingService.index();
|
|
||||||
await store.modify('0', {
|
|
||||||
'text': 'go to school',
|
|
||||||
});
|
|
||||||
|
|
||||||
var result = await onModified.next;
|
|
||||||
print(result);
|
|
||||||
expect(result, Map.from({'': created})..['text'] = 'go to school');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('manual modify', () async {
|
|
||||||
await pollingService.index();
|
|
||||||
await pollingService.modify('0', {
|
|
||||||
'text': 'eat',
|
|
||||||
});
|
|
||||||
|
|
||||||
var result = await onModified.next;
|
|
||||||
print(result);
|
|
||||||
expect(result, Map.from({'': created})..['text'] = 'eat');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('fires removed', () async {
|
|
||||||
await pollingService.index();
|
|
||||||
var removed = await store.remove('0');
|
|
||||||
var result = await onRemoved.next;
|
|
||||||
print(result);
|
|
||||||
expect(result, removed);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
BIN
archived_packages/relations.zip
Normal file
BIN
archived_packages/relations.zip
Normal file
Binary file not shown.
93
archived_packages/relations/.gitignore
vendored
93
archived_packages/relations/.gitignore
vendored
|
@ -1,93 +0,0 @@
|
||||||
# See https://www.dartlang.org/tools/private-files.html
|
|
||||||
|
|
||||||
# Files and directories created by pub
|
|
||||||
.buildlog
|
|
||||||
.packages
|
|
||||||
.project
|
|
||||||
.pub/
|
|
||||||
.scripts-bin/
|
|
||||||
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
|
|
||||||
### Dart template
|
|
||||||
# See https://www.dartlang.org/tools/private-files.html
|
|
||||||
|
|
||||||
# Files and directories created by pub
|
|
||||||
|
|
||||||
# SDK 1.20 and later (no longer creates packages directories)
|
|
||||||
|
|
||||||
# Older SDK versions
|
|
||||||
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
|
|
||||||
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# Directory created by dartdoc
|
|
||||||
|
|
||||||
# Don't commit pubspec lock file
|
|
||||||
# (Library packages only! Remove pattern if developing an application package)
|
|
||||||
### JetBrains template
|
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
||||||
|
|
||||||
# User-specific stuff:
|
|
||||||
.idea/**/workspace.xml
|
|
||||||
.idea/**/tasks.xml
|
|
||||||
.idea/dictionaries
|
|
||||||
|
|
||||||
# Sensitive or high-churn files:
|
|
||||||
.idea/**/dataSources/
|
|
||||||
.idea/**/dataSources.ids
|
|
||||||
.idea/**/dataSources.xml
|
|
||||||
.idea/**/dataSources.local.xml
|
|
||||||
.idea/**/sqlDataSources.xml
|
|
||||||
.idea/**/dynamic.xml
|
|
||||||
.idea/**/uiDesigner.xml
|
|
||||||
|
|
||||||
# Gradle:
|
|
||||||
.idea/**/gradle.xml
|
|
||||||
.idea/**/libraries
|
|
||||||
|
|
||||||
# Mongo Explorer plugin:
|
|
||||||
.idea/**/mongoSettings.xml
|
|
||||||
|
|
||||||
## File-based project format:
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
## Plugin-specific files:
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
|
||||||
.idea_modules/
|
|
||||||
|
|
||||||
# JIRA plugin
|
|
||||||
atlassian-ide-plugin.xml
|
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
fabric.properties
|
|
|
@ -1 +0,0 @@
|
||||||
language: dart
|
|
|
@ -1,12 +0,0 @@
|
||||||
Primary Authors
|
|
||||||
===============
|
|
||||||
|
|
||||||
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
|
||||||
|
|
||||||
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
|
||||||
code base to support NNBD.
|
|
||||||
|
|
||||||
* __[Tobe O](thosakwe@gmail.com)__
|
|
||||||
|
|
||||||
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
|
||||||
is no longer involved with the project.
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
## 2.0.0
|
|
||||||
|
|
||||||
* Migrated to support Dart >= 2.12 NNBD
|
|
||||||
|
|
||||||
## 1.0.0
|
|
||||||
|
|
||||||
* Initial checkin
|
|
|
@ -1,29 +0,0 @@
|
||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2021, dukefirehawk.com
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,25 +0,0 @@
|
||||||
# relations
|
|
||||||
[![version 1.0.1](https://img.shields.io/badge/pub-v1.0.1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_relations)
|
|
||||||
[![build status](https://travis-ci.org/angel-dart/relations.svg)](https://travis-ci.org/angel-dart/relations)
|
|
||||||
|
|
||||||
Database-agnostic relations between Angel services.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
// Authors owning one book
|
|
||||||
app.service('authors').afterAll(
|
|
||||||
relations.hasOne('books', as: 'book', foreignKey: 'authorId'));
|
|
||||||
|
|
||||||
// Or multiple
|
|
||||||
app.service('authors').afterAll(
|
|
||||||
relations.hasMany('books', foreignKey: 'authorId'));
|
|
||||||
|
|
||||||
// Or, books belonging to authors
|
|
||||||
app.service('books').afterAll(relations.belongsTo('authors'));
|
|
||||||
```
|
|
||||||
|
|
||||||
Supports:
|
|
||||||
* `hasOne`
|
|
||||||
* `hasMany`
|
|
||||||
* `hasManyThrough`
|
|
||||||
* `belongsTo`
|
|
||||||
* `belongsToMany`
|
|
|
@ -1 +0,0 @@
|
||||||
include: package:lints/recommended.yaml
|
|
|
@ -1,9 +0,0 @@
|
||||||
/// Hooks to populate data returned from services, in a fashion
|
|
||||||
/// reminiscent of a relational database.
|
|
||||||
library angel_relations;
|
|
||||||
|
|
||||||
export 'src/belongs_to_many.dart';
|
|
||||||
export 'src/belongs_to.dart';
|
|
||||||
export 'src/has_many.dart';
|
|
||||||
export 'src/has_many_through.dart';
|
|
||||||
export 'src/has_one.dart';
|
|
|
@ -1,75 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:mirrors';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'plural.dart' as pluralize;
|
|
||||||
import 'no_service.dart';
|
|
||||||
|
|
||||||
/// Represents a relationship in which the current [service] "belongs to"
|
|
||||||
/// a single member of the service at [servicePath]. Use [as] to set the name
|
|
||||||
/// on the target object.
|
|
||||||
///
|
|
||||||
/// Defaults:
|
|
||||||
/// * [localKey]: `userId`
|
|
||||||
/// * [foreignKey]: `id`
|
|
||||||
HookedServiceEventListener belongsTo(Pattern servicePath,
|
|
||||||
{String? as,
|
|
||||||
String? foreignKey,
|
|
||||||
String? localKey,
|
|
||||||
Function(dynamic obj)? getForeignKey,
|
|
||||||
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
|
|
||||||
var localId = localKey;
|
|
||||||
var foreignName =
|
|
||||||
as?.isNotEmpty == true ? as! : pluralize.singular(servicePath.toString());
|
|
||||||
|
|
||||||
localId ??= foreignName + 'Id';
|
|
||||||
|
|
||||||
return (HookedServiceEvent e) async {
|
|
||||||
var ref = e.getService(servicePath);
|
|
||||||
if (ref == null) throw noService(servicePath);
|
|
||||||
|
|
||||||
dynamic _getForeignKey(obj) {
|
|
||||||
if (getForeignKey != null) {
|
|
||||||
return getForeignKey(obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
return obj[localId];
|
|
||||||
} else if (localId == null || localId == 'userId') {
|
|
||||||
return obj.userId;
|
|
||||||
} else {
|
|
||||||
return reflect(obj).getField(Symbol(localId)).reflectee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _assignForeignObject(foreign, obj) {
|
|
||||||
if (assignForeignObject != null) {
|
|
||||||
return assignForeignObject(foreign, obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
obj[foreignName] = foreign;
|
|
||||||
} else {
|
|
||||||
reflect(obj).setField(Symbol(foreignName), foreign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _normalize(obj) async {
|
|
||||||
if (obj != null) {
|
|
||||||
var id = await _getForeignKey(obj);
|
|
||||||
var indexed = await ref.index({
|
|
||||||
'query': {foreignKey ?? 'id': id}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (indexed is! List || indexed.isNotEmpty != true) {
|
|
||||||
await _assignForeignObject(null, obj);
|
|
||||||
} else {
|
|
||||||
var child = indexed.first;
|
|
||||||
await _assignForeignObject(child, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
|
||||||
//await Future.wait(e.result.map(_normalize));
|
|
||||||
await e.result.map(_normalize);
|
|
||||||
} else {
|
|
||||||
await _normalize(e.result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:mirrors';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'plural.dart' as pluralize;
|
|
||||||
import 'no_service.dart';
|
|
||||||
|
|
||||||
/// Represents a relationship in which the current [service] "belongs to"
|
|
||||||
/// multiple members of the service at [servicePath]. Use [as] to set the name
|
|
||||||
/// on the target object.
|
|
||||||
///
|
|
||||||
/// Defaults:
|
|
||||||
/// * [foreignKey]: `userId`
|
|
||||||
/// * [localKey]: `id`
|
|
||||||
HookedServiceEventListener belongsToMany(Pattern servicePath,
|
|
||||||
{String? as,
|
|
||||||
String? foreignKey,
|
|
||||||
String? localKey,
|
|
||||||
Function(dynamic obj)? getForeignKey,
|
|
||||||
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
|
|
||||||
var localId = localKey;
|
|
||||||
var foreignName =
|
|
||||||
as?.isNotEmpty == true ? as! : pluralize.plural(servicePath.toString());
|
|
||||||
|
|
||||||
localId ??= foreignName + 'Id';
|
|
||||||
|
|
||||||
return (HookedServiceEvent e) async {
|
|
||||||
var ref = e.getService(servicePath);
|
|
||||||
if (ref == null) throw noService(servicePath);
|
|
||||||
|
|
||||||
dynamic _getForeignKey(obj) {
|
|
||||||
if (getForeignKey != null) {
|
|
||||||
return getForeignKey(obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
return obj[localId];
|
|
||||||
} else if (localId == null || localId == 'userId') {
|
|
||||||
return obj.userId;
|
|
||||||
} else {
|
|
||||||
return reflect(obj).getField(Symbol(localId)).reflectee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _assignForeignObject(foreign, obj) {
|
|
||||||
if (assignForeignObject != null) {
|
|
||||||
return assignForeignObject(foreign as List?, obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
obj[foreignName] = foreign;
|
|
||||||
} else {
|
|
||||||
reflect(obj).setField(Symbol(foreignName), foreign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _normalize(obj) async {
|
|
||||||
if (obj != null) {
|
|
||||||
var id = await _getForeignKey(obj);
|
|
||||||
var indexed = await ref.index({
|
|
||||||
'query': {foreignKey ?? 'id': id}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (indexed is! List || indexed.isNotEmpty != true) {
|
|
||||||
await _assignForeignObject(null, obj);
|
|
||||||
} else {
|
|
||||||
var child = indexed is Iterable ? indexed.toList() : [indexed];
|
|
||||||
await _assignForeignObject(child, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
|
||||||
//await Future.wait(e.result.map(_normalize));
|
|
||||||
await e.result.map(_normalize);
|
|
||||||
} else {
|
|
||||||
await _normalize(e.result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:mirrors';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'plural.dart' as pluralize;
|
|
||||||
import 'no_service.dart';
|
|
||||||
|
|
||||||
/// Represents a relationship in which the current [service] "owns"
|
|
||||||
/// members of the service at [servicePath]. Use [as] to set the name
|
|
||||||
/// on the target object.
|
|
||||||
///
|
|
||||||
/// Defaults:
|
|
||||||
/// * [foreignKey]: `userId`
|
|
||||||
/// * [localKey]: `id`
|
|
||||||
HookedServiceEventListener hasMany(Pattern servicePath,
|
|
||||||
{String? as,
|
|
||||||
String? foreignKey,
|
|
||||||
String? localKey,
|
|
||||||
Function(dynamic obj)? getLocalKey,
|
|
||||||
Function(dynamic foreign, dynamic obj)? assignForeignObjects}) {
|
|
||||||
return (HookedServiceEvent e) async {
|
|
||||||
var ref = e.getService(servicePath);
|
|
||||||
var foreignName =
|
|
||||||
as?.isNotEmpty == true ? as : pluralize.plural(servicePath.toString());
|
|
||||||
if (ref == null) throw noService(servicePath);
|
|
||||||
|
|
||||||
dynamic _getLocalKey(obj) {
|
|
||||||
if (getLocalKey != null) {
|
|
||||||
return getLocalKey(obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
return obj[localKey ?? 'id'];
|
|
||||||
} else if (localKey == null || localKey == 'id') {
|
|
||||||
return obj.id;
|
|
||||||
} else {
|
|
||||||
return reflect(obj).getField(Symbol(localKey)).reflectee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _assignForeignObjects(foreign, obj) {
|
|
||||||
if (assignForeignObjects != null) {
|
|
||||||
return assignForeignObjects(foreign, obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
obj[foreignName] = foreign;
|
|
||||||
} else {
|
|
||||||
reflect(obj).setField(Symbol(foreignName!), foreign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _normalize(obj) async {
|
|
||||||
if (obj != null) {
|
|
||||||
var id = await _getLocalKey(obj);
|
|
||||||
var indexed = await ref.index({
|
|
||||||
'query': {foreignKey ?? 'userId': id}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (indexed is! List || indexed.isNotEmpty != true) {
|
|
||||||
await _assignForeignObjects([], obj);
|
|
||||||
} else {
|
|
||||||
await _assignForeignObjects(indexed, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
|
||||||
//await Future.wait(e.result.map(_normalize));
|
|
||||||
await e.result.map(_normalize);
|
|
||||||
} else {
|
|
||||||
await _normalize(e.result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:mirrors';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'plural.dart' as pluralize;
|
|
||||||
import 'no_service.dart';
|
|
||||||
|
|
||||||
HookedServiceEventListener hasManyThrough(String servicePath, String pivotPath,
|
|
||||||
{String? as,
|
|
||||||
String? localKey,
|
|
||||||
String? pivotKey,
|
|
||||||
String? foreignKey,
|
|
||||||
Function(dynamic obj)? getLocalKey,
|
|
||||||
Function(dynamic obj)? getPivotKey,
|
|
||||||
Function(dynamic obj)? getForeignKey,
|
|
||||||
Function(dynamic foreign, dynamic obj)? assignForeignObjects}) {
|
|
||||||
var foreignName =
|
|
||||||
as?.isNotEmpty == true ? as : pluralize.plural(servicePath.toString());
|
|
||||||
|
|
||||||
return (HookedServiceEvent e) async {
|
|
||||||
var pivotService = e.getService(pivotPath);
|
|
||||||
var foreignService = e.getService(servicePath);
|
|
||||||
|
|
||||||
if (pivotService == null) {
|
|
||||||
throw noService(pivotPath);
|
|
||||||
} else if (foreignService == null) throw noService(servicePath);
|
|
||||||
|
|
||||||
dynamic _assignForeignObjects(foreign, obj) {
|
|
||||||
if (assignForeignObjects != null) {
|
|
||||||
return assignForeignObjects(foreign, obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
obj[foreignName] = foreign;
|
|
||||||
} else {
|
|
||||||
reflect(obj).setField(Symbol(foreignName!), foreign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _getLocalKey(obj) {
|
|
||||||
if (getLocalKey != null) {
|
|
||||||
return getLocalKey(obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
return obj[localKey ?? 'id'];
|
|
||||||
} else if (localKey == null || localKey == 'id') {
|
|
||||||
return obj.id;
|
|
||||||
} else {
|
|
||||||
return reflect(obj).getField(Symbol(localKey)).reflectee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _getPivotKey(obj) {
|
|
||||||
if (getPivotKey != null) {
|
|
||||||
return getPivotKey(obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
return obj[pivotKey ?? 'id'];
|
|
||||||
} else if (pivotKey == null || pivotKey == 'id') {
|
|
||||||
return obj.id;
|
|
||||||
} else {
|
|
||||||
return reflect(obj).getField(Symbol(pivotKey)).reflectee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _normalize(obj) async {
|
|
||||||
// First, resolve pivot
|
|
||||||
var id = await _getLocalKey(obj);
|
|
||||||
var indexed = await pivotService.index({
|
|
||||||
'query': {pivotKey ?? 'userId': id}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (indexed is! List || indexed.isNotEmpty != true) {
|
|
||||||
await _assignForeignObjects([], obj);
|
|
||||||
} else {
|
|
||||||
// Now, resolve from foreign service
|
|
||||||
var mapped = await Future.wait(indexed.map((pivot) async {
|
|
||||||
var id = await _getPivotKey(obj);
|
|
||||||
var indexed = await foreignService.index({
|
|
||||||
'query': {foreignKey ?? 'postId': id}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (indexed is! List || indexed.isNotEmpty != true) {
|
|
||||||
await _assignForeignObjects([], pivot);
|
|
||||||
} else {
|
|
||||||
await _assignForeignObjects(indexed, pivot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pivot;
|
|
||||||
}));
|
|
||||||
await _assignForeignObjects(mapped, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
|
||||||
//await Future.wait(e.result.map(_normalize));
|
|
||||||
await e.result.map(_normalize);
|
|
||||||
} else {
|
|
||||||
await _normalize(e.result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:mirrors';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'plural.dart' as pluralize;
|
|
||||||
import 'no_service.dart';
|
|
||||||
|
|
||||||
/// Represents a relationship in which the current [service] "owns"
|
|
||||||
/// a single member of the service at [servicePath]. Use [as] to set the name
|
|
||||||
/// on the target object.
|
|
||||||
///
|
|
||||||
/// Defaults:
|
|
||||||
/// * [foreignKey]: `userId`
|
|
||||||
/// * [localKey]: `id`
|
|
||||||
HookedServiceEventListener hasOne(Pattern servicePath,
|
|
||||||
{String? as,
|
|
||||||
String? foreignKey,
|
|
||||||
String? localKey,
|
|
||||||
Function(dynamic obj)? getLocalKey,
|
|
||||||
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
|
|
||||||
return (HookedServiceEvent e) async {
|
|
||||||
var ref = e.getService(servicePath);
|
|
||||||
var foreignName = as?.isNotEmpty == true
|
|
||||||
? as
|
|
||||||
: pluralize.singular(servicePath.toString());
|
|
||||||
if (ref == null) throw noService(servicePath);
|
|
||||||
|
|
||||||
dynamic _getLocalKey(obj) {
|
|
||||||
if (getLocalKey != null) {
|
|
||||||
return getLocalKey(obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
return obj[localKey ?? 'id'];
|
|
||||||
} else if (localKey == null || localKey == 'id') {
|
|
||||||
return obj.id;
|
|
||||||
} else {
|
|
||||||
return reflect(obj).getField(Symbol(localKey)).reflectee;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _assignForeignObject(foreign, obj) {
|
|
||||||
if (assignForeignObject != null) {
|
|
||||||
return assignForeignObject(foreign, obj);
|
|
||||||
} else if (obj is Map) {
|
|
||||||
obj[foreignName] = foreign;
|
|
||||||
} else {
|
|
||||||
reflect(obj).setField(Symbol(foreignName!), foreign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _normalize(obj) async {
|
|
||||||
if (obj != null) {
|
|
||||||
var id = await _getLocalKey(obj);
|
|
||||||
|
|
||||||
var indexed = await ref.index({
|
|
||||||
'query': {foreignKey ?? 'userId': id}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (indexed is! List || indexed.isNotEmpty != true) {
|
|
||||||
await _assignForeignObject(null, obj);
|
|
||||||
} else {
|
|
||||||
var child = indexed.first;
|
|
||||||
await _assignForeignObject(child, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.result is Iterable) {
|
|
||||||
//await Future.wait(e.result.map(_normalize));
|
|
||||||
await e.result.map(_normalize);
|
|
||||||
} else {
|
|
||||||
await _normalize(e.result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
ArgumentError noService(Pattern path) =>
|
|
||||||
ArgumentError("No service exists at path '$path'.");
|
|
|
@ -1,23 +0,0 @@
|
||||||
String singular(String path) {
|
|
||||||
var str = path.trim().split('/').where((str) => str.isNotEmpty).last;
|
|
||||||
|
|
||||||
if (str.endsWith('ies')) {
|
|
||||||
return str.substring(0, str.length - 3) + 'y';
|
|
||||||
} else if (str.endsWith('s')) {
|
|
||||||
return str.substring(0, str.length - 1);
|
|
||||||
} else {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String plural(String path) {
|
|
||||||
var str = path.trim().split('/').where((str) => str.isNotEmpty).last;
|
|
||||||
|
|
||||||
if (str.endsWith('y')) {
|
|
||||||
return str.substring(0, str.length - 1) + 'ies';
|
|
||||||
} else if (str.endsWith('s')) {
|
|
||||||
return str;
|
|
||||||
} else {
|
|
||||||
return str + 's';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
name: angel_relations
|
|
||||||
version: 2.0.0
|
|
||||||
description: Database-agnostic relations between Angel services.
|
|
||||||
homepage: "https://github.com/angel-dart/relations.git"
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
|
||||||
dependencies:
|
|
||||||
angel_framework:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/framework
|
|
||||||
dev_dependencies:
|
|
||||||
angel_seeder:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/seeder
|
|
||||||
test: ^1.17.8
|
|
||||||
lints: ^1.0.0
|
|
|
@ -1,54 +0,0 @@
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_seeder/angel_seeder.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'common.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
late Angel app;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
app = Angel()..use('/authors', MapService())..use('/books', MapService());
|
|
||||||
|
|
||||||
await app.configure(seed(
|
|
||||||
'authors',
|
|
||||||
SeederConfiguration<Map>(
|
|
||||||
count: 10,
|
|
||||||
template: {'name': (Faker faker) => faker.person.name()},
|
|
||||||
callback: (Map author, seed) {
|
|
||||||
return seed(
|
|
||||||
'books',
|
|
||||||
SeederConfiguration(delete: false, count: 10, template: {
|
|
||||||
'authorId': author['id'],
|
|
||||||
'title': (Faker faker) =>
|
|
||||||
'I love to eat ${faker.food.dish()}'
|
|
||||||
}));
|
|
||||||
})));
|
|
||||||
|
|
||||||
// TODO: Missing method afterAll
|
|
||||||
//app.findService ('books').afterAll(relations.belongsTo('authors'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('index', () async {
|
|
||||||
var books = await app.findService('books')!.index();
|
|
||||||
print(books);
|
|
||||||
|
|
||||||
expect(books, allOf(isList, isNotEmpty));
|
|
||||||
|
|
||||||
for (var book in books.whereType<Map>()) {
|
|
||||||
expect(book.keys, contains('author'));
|
|
||||||
|
|
||||||
var author = book['author'] as Map;
|
|
||||||
expect(author['id'], equals(book['authorId']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('create', () async {
|
|
||||||
var warAndPeace = await app
|
|
||||||
.findService('books')!
|
|
||||||
.create(Book(title: 'War and Peace').toJson());
|
|
||||||
|
|
||||||
print(warAndPeace);
|
|
||||||
expect(warAndPeace.keys, contains('author'));
|
|
||||||
expect(warAndPeace['author'], isNull);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
//import 'package:json_god/json_god.dart' as god;
|
|
||||||
|
|
||||||
@deprecated
|
|
||||||
class CustomMapService extends Service {
|
|
||||||
final List<Map> _items = [];
|
|
||||||
|
|
||||||
Iterable<Map> tailor(Iterable<Map> items, Map? params) {
|
|
||||||
if (params == null) return items;
|
|
||||||
|
|
||||||
var r = items;
|
|
||||||
|
|
||||||
if (params['query'] is Map) {
|
|
||||||
var query = params['query'] as Map;
|
|
||||||
|
|
||||||
for (var key in query.keys) {
|
|
||||||
r = r.where((m) => m[key] == query[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<Map>> index([params]) async => tailor(_items, params).toList();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Map> read(id, [Map? params]) async {
|
|
||||||
return tailor(_items, params).firstWhere((m) => m['id'] == id,
|
|
||||||
orElse: (() => throw AngelHttpException.notFound()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Map> create(data, [params]) async {
|
|
||||||
var d = data is Map ? data : (jsonDecode(data as String) as Map?)!;
|
|
||||||
d['id'] = _items.length.toString();
|
|
||||||
_items.add(d);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future remove(id, [params]) async {
|
|
||||||
if (id == null) _items.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Author {
|
|
||||||
String? id, name;
|
|
||||||
|
|
||||||
Author({this.id, this.name});
|
|
||||||
|
|
||||||
Map toJson() => {'id': id, 'name': name};
|
|
||||||
}
|
|
||||||
|
|
||||||
class Book {
|
|
||||||
String? authorId, title;
|
|
||||||
|
|
||||||
Book({this.authorId, this.title});
|
|
||||||
|
|
||||||
Map toJson() => {'authorId': authorId, 'title': title};
|
|
||||||
}
|
|
||||||
|
|
||||||
class Chapter {
|
|
||||||
String? bookId, title;
|
|
||||||
int? pageCount;
|
|
||||||
|
|
||||||
Chapter({this.bookId, this.title, this.pageCount});
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
//import 'package:angel_relations/angel_relations.dart' as relations;
|
|
||||||
import 'package:angel_seeder/angel_seeder.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'common.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
late Angel app;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
app = Angel()..use('/authors', MapService())..use('/books', MapService());
|
|
||||||
|
|
||||||
await app.configure(seed(
|
|
||||||
'authors',
|
|
||||||
SeederConfiguration<Map>(
|
|
||||||
count: 10,
|
|
||||||
template: {'name': (Faker faker) => faker.person.name()},
|
|
||||||
callback: (Map author, seed) {
|
|
||||||
return seed(
|
|
||||||
'books',
|
|
||||||
SeederConfiguration(delete: false, count: 10, template: {
|
|
||||||
'authorId': author['id'],
|
|
||||||
'title': (Faker faker) =>
|
|
||||||
'I love to eat ${faker.food.dish()}'
|
|
||||||
}));
|
|
||||||
})));
|
|
||||||
|
|
||||||
// TODO: Missing afterAll method
|
|
||||||
// app
|
|
||||||
// .findService('authors')
|
|
||||||
// .afterAll(relations.hasMany('books', foreignKey: 'authorId'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('index', () async {
|
|
||||||
var authors = await app.findService('authors')!.index();
|
|
||||||
print(authors);
|
|
||||||
|
|
||||||
expect(authors, allOf(isList, isNotEmpty));
|
|
||||||
|
|
||||||
for (var author in authors.whereType<Map>()) {
|
|
||||||
expect(author.keys, contains('books'));
|
|
||||||
|
|
||||||
var books = author['books'] as List<Map>;
|
|
||||||
|
|
||||||
for (var book in books) {
|
|
||||||
expect(book['authorId'], equals(author['id']));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('create', () async {
|
|
||||||
var tolstoy = await app
|
|
||||||
.findService('authors')!
|
|
||||||
.create(Author(name: 'Leo Tolstoy').toJson());
|
|
||||||
|
|
||||||
print(tolstoy);
|
|
||||||
expect(tolstoy.keys, contains('books'));
|
|
||||||
expect(tolstoy['books'], allOf(isList, isEmpty));
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_seeder/angel_seeder.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'common.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
late Angel app;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
app = Angel()..use('/authors', MapService())..use('/books', MapService());
|
|
||||||
|
|
||||||
await app.configure(seed(
|
|
||||||
'authors',
|
|
||||||
SeederConfiguration<Map>(
|
|
||||||
count: 10,
|
|
||||||
template: {'name': (Faker faker) => faker.person.name()},
|
|
||||||
callback: (Map author, seed) {
|
|
||||||
return seed(
|
|
||||||
'books',
|
|
||||||
SeederConfiguration(delete: false, count: 10, template: {
|
|
||||||
'authorId': author['id'],
|
|
||||||
'title': (Faker faker) =>
|
|
||||||
'I love to eat ${faker.food.dish()}'
|
|
||||||
}));
|
|
||||||
})));
|
|
||||||
|
|
||||||
// TODO: Missing afterAll method
|
|
||||||
// app.findService('authors').afterAll(
|
|
||||||
// relations.hasOne('books', as: 'book', foreignKey: 'authorId'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('index', () async {
|
|
||||||
var authors = await app.findService('authors')!.index();
|
|
||||||
print(authors);
|
|
||||||
|
|
||||||
expect(authors, allOf(isList, isNotEmpty));
|
|
||||||
|
|
||||||
for (var author in authors.whereType<Map>()) {
|
|
||||||
expect(author.keys, contains('book'));
|
|
||||||
|
|
||||||
var book = author['book'] as Map;
|
|
||||||
print('Author: $author');
|
|
||||||
print('Book: $book');
|
|
||||||
expect(book['authorId'], equals(author['id']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test('create', () async {
|
|
||||||
var tolstoy = await app
|
|
||||||
.findService('authors')!
|
|
||||||
.create(Author(name: 'Leo Tolstoy').toJson());
|
|
||||||
|
|
||||||
print(tolstoy);
|
|
||||||
expect(tolstoy.keys, contains('book'));
|
|
||||||
expect(tolstoy['book'], isNull);
|
|
||||||
});
|
|
||||||
}
|
|
BIN
archived_packages/rethink.zip
Normal file
BIN
archived_packages/rethink.zip
Normal file
Binary file not shown.
31
archived_packages/rethink/.gitignore
vendored
31
archived_packages/rethink/.gitignore
vendored
|
@ -1,31 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
||||||
rethinkdb_data/
|
|
||||||
.idea
|
|
||||||
.dart_tool
|
|
|
@ -1,4 +0,0 @@
|
||||||
language: dart
|
|
||||||
addons:
|
|
||||||
rethinkdb: '2.3'
|
|
||||||
before_script: 'dart test/bootstrap.dart'
|
|
|
@ -1,12 +0,0 @@
|
||||||
Primary Authors
|
|
||||||
===============
|
|
||||||
|
|
||||||
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
|
||||||
|
|
||||||
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
|
||||||
code base to support NNBD.
|
|
||||||
|
|
||||||
* __[Tobe O](thosakwe@gmail.com)__
|
|
||||||
|
|
||||||
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
|
||||||
is no longer involved with the project.
|
|
|
@ -1,10 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
## 2.0.0
|
|
||||||
|
|
||||||
* Migrated to support Dart >= 2.12 NNBD
|
|
||||||
|
|
||||||
## 1.1.0
|
|
||||||
|
|
||||||
* Moved to `package:rethinkdb_driver`
|
|
||||||
* Fixed references to old hooked event names
|
|
|
@ -1,29 +0,0 @@
|
||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2021, dukefirehawk.com
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,87 +0,0 @@
|
||||||
# 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.
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
Add the following to your `pubspec.yaml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
dependencies:
|
|
||||||
angel_rethink: ^1.0.0
|
|
||||||
```
|
|
||||||
|
|
||||||
`package:rethinkdb_driver2` 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,
|
|
||||||
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<User>(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 `Query` (usually a table) and serializes data to and from Maps.
|
|
||||||
|
|
||||||
## RethinkTypedService<T>
|
|
||||||
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.
|
|
|
@ -1 +0,0 @@
|
||||||
include: package:lints/recommended.yaml
|
|
|
@ -1 +0,0 @@
|
||||||
export 'src/rethink_service.dart';
|
|
|
@ -1,251 +0,0 @@
|
||||||
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_dart/rethinkdb_dart.dart';
|
|
||||||
|
|
||||||
// Extends a RethinkDB query.
|
|
||||||
typedef QueryCallback = RqlQuery Function(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 buildQuery(RqlQuery initialQuery, Map params) {
|
|
||||||
if (params != null) {
|
|
||||||
params['broadcast'] = params.containsKey('broadcast')
|
|
||||||
? params['broadcast']
|
|
||||||
: (listenForChanges != true);
|
|
||||||
}
|
|
||||||
|
|
||||||
var q = _getQueryInner(initialQuery, params);
|
|
||||||
|
|
||||||
if (params?.containsKey('reql') == true &&
|
|
||||||
params['reql'] is QueryCallback) {
|
|
||||||
q = params['reql'](q) as RqlQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
return q ?? initialQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
RqlQuery _getQueryInner(RqlQuery query, Map params) {
|
|
||||||
if (params == null || !params.containsKey('query')) {
|
|
||||||
return query;
|
|
||||||
} else {
|
|
||||||
if (params['query'] is RqlQuery) {
|
|
||||||
return params['query'] as RqlQuery;
|
|
||||||
} else if (params['query'] is QueryCallback) {
|
|
||||||
return params['query'](table) as RqlQuery;
|
|
||||||
} else if (params['query'] is! Map || allowQuery != true) {
|
|
||||||
return query;
|
|
||||||
} else {
|
|
||||||
var q = params['query'] as Map;
|
|
||||||
return q.keys.fold<RqlQuery>(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({key.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));
|
|
||||||
return await result['generated_keys'].map(read);
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _serialize(data) {
|
|
||||||
if (data is Map) {
|
|
||||||
return data;
|
|
||||||
} else if (data is Iterable) {
|
|
||||||
return data.map(_serialize).toList();
|
|
||||||
} else {
|
|
||||||
return god.serializeObject(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic _squeeze(data) {
|
|
||||||
if (data is Map) {
|
|
||||||
return data.keys.fold<Map>({}, (map, k) => map..[k.toString()] = data[k]);
|
|
||||||
} else if (data is Iterable) {
|
|
||||||
return data.map(_squeeze).toList();
|
|
||||||
} else {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void onHooked(HookedService hookedService) {
|
|
||||||
if (listenForChanges == true) {
|
|
||||||
listenToQuery(table, hookedService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future listenToQuery(RqlQuery query, HookedService hookedService) async {
|
|
||||||
var feed =
|
|
||||||
await query.changes({'include_types': true}).run(connection) as Feed;
|
|
||||||
|
|
||||||
feed.listen((Map event) {
|
|
||||||
var type = event['type']?.toString();
|
|
||||||
var newVal = event['new_val'], oldVal = event['old_val'];
|
|
||||||
|
|
||||||
if (type == 'add') {
|
|
||||||
// Create
|
|
||||||
hookedService.fireEvent(
|
|
||||||
hookedService.afterCreated,
|
|
||||||
HookedServiceEvent(
|
|
||||||
true, null, null, this, HookedServiceEvent.created,
|
|
||||||
result: newVal));
|
|
||||||
} else if (type == 'change') {
|
|
||||||
// Update
|
|
||||||
hookedService.fireEvent(
|
|
||||||
hookedService.afterCreated,
|
|
||||||
HookedServiceEvent(
|
|
||||||
true, null, null, this, HookedServiceEvent.updated,
|
|
||||||
result: newVal, id: oldVal['id'], data: newVal));
|
|
||||||
} else if (type == 'remove') {
|
|
||||||
// Remove
|
|
||||||
hookedService.fireEvent(
|
|
||||||
hookedService.afterCreated,
|
|
||||||
HookedServiceEvent(
|
|
||||||
true, null, null, this, HookedServiceEvent.removed,
|
|
||||||
result: oldVal, id: oldVal['id']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Invalid override method
|
|
||||||
/*
|
|
||||||
@override
|
|
||||||
Future index([Map params]) async {
|
|
||||||
var query = buildQuery(table, params);
|
|
||||||
return await _sendQuery(query);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@override
|
|
||||||
Future read(id, [Map params]) async {
|
|
||||||
var query = buildQuery(table.get(id?.toString()), params);
|
|
||||||
var found = await _sendQuery(query);
|
|
||||||
//print('Found for $id: $found');
|
|
||||||
|
|
||||||
if (found == null) {
|
|
||||||
throw AngelHttpException.notFound(message: 'No record found for ID $id');
|
|
||||||
} else {
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future create(data, [Map params]) async {
|
|
||||||
if (table is! Table) throw AngelHttpException.methodNotAllowed();
|
|
||||||
|
|
||||||
var d = _serialize(data);
|
|
||||||
var q = table as Table;
|
|
||||||
var query = buildQuery(q.insert(_squeeze(d)), params);
|
|
||||||
return await _sendQuery(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
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 == 404) {
|
|
||||||
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 d = _serialize(data);
|
|
||||||
|
|
||||||
if (d is Map && d.containsKey('id')) {
|
|
||||||
try {
|
|
||||||
await read(d['id'], params);
|
|
||||||
} on AngelHttpException catch (e) {
|
|
||||||
if (e.statusCode == 404) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 = buildQuery(table.get(id), params).delete();
|
|
||||||
await _sendQuery(query);
|
|
||||||
return prior;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
name: angel_rethink
|
|
||||||
version: 2.0.0
|
|
||||||
description: RethinkDB-enabled services for the Angel framework.
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: ">=2.10.0 <3.0.0"
|
|
||||||
homepage: https://github.com/angel-dart/rethink
|
|
||||||
dependencies:
|
|
||||||
angel_framework:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/framework
|
|
||||||
json_god:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/json_god
|
|
||||||
rethinkdb_dart: ^2.3.2+6
|
|
||||||
dev_dependencies:
|
|
||||||
angel_client:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/client
|
|
||||||
angel_test:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/test
|
|
||||||
logging: ^1.0.0
|
|
||||||
test: ^1.15.7
|
|
||||||
lints: ^1.0.0
|
|
||||||
dependency_overrides:
|
|
||||||
crypto: ^3.0.0
|
|
|
@ -1,6 +0,0 @@
|
||||||
# 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`.
|
|
|
@ -1,11 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:rethinkdb_dart/rethinkdb_dart.dart';
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
var r = Rethinkdb();
|
|
||||||
await r.connect().then((conn) {
|
|
||||||
r.tableCreate('todos').run(conn);
|
|
||||||
print('Done');
|
|
||||||
exit(0);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
class Todo {
|
|
||||||
String title;
|
|
||||||
bool completed;
|
|
||||||
|
|
||||||
Todo({this.title, this.completed = false});
|
|
||||||
|
|
||||||
Map toJson() {
|
|
||||||
return {'title': title, 'completed': completed == true};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
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:logging/logging.dart';
|
|
||||||
import 'package:rethinkdb_dart/rethinkdb_dart.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
import 'common.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
Angel app;
|
|
||||||
TestClient client;
|
|
||||||
Rethinkdb r;
|
|
||||||
c.Service todoService;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
r = Rethinkdb();
|
|
||||||
var conn = await r.connect();
|
|
||||||
|
|
||||||
app = Angel();
|
|
||||||
app.use('/todos', RethinkService(conn, r.table('todos')));
|
|
||||||
|
|
||||||
app.errorHandler = (e, req, res) async {
|
|
||||||
print('Whoops: $e');
|
|
||||||
};
|
|
||||||
|
|
||||||
app.logger = Logger.detached('angel')..onRecord.listen(print);
|
|
||||||
|
|
||||||
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 = 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('modify', () async {
|
|
||||||
var todo = Todo(title: 'Clean your room');
|
|
||||||
var creation = await todoService.create(todo.toJson());
|
|
||||||
print('Creation: $creation');
|
|
||||||
|
|
||||||
var id = creation['id'];
|
|
||||||
var result = await todoService.modify(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 = 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));
|
|
||||||
});
|
|
||||||
}
|
|
BIN
archived_packages/seeder.zip
Normal file
BIN
archived_packages/seeder.zip
Normal file
Binary file not shown.
27
archived_packages/seeder/.gitignore
vendored
27
archived_packages/seeder/.gitignore
vendored
|
@ -1,27 +0,0 @@
|
||||||
# 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
|
|
|
@ -1 +0,0 @@
|
||||||
language: dart
|
|
|
@ -1,12 +0,0 @@
|
||||||
Primary Authors
|
|
||||||
===============
|
|
||||||
|
|
||||||
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
|
||||||
|
|
||||||
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
|
||||||
code base to support NNBD.
|
|
||||||
|
|
||||||
* __[Tobe O](thosakwe@gmail.com)__
|
|
||||||
|
|
||||||
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
|
||||||
is no longer involved with the project.
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
## 2.0.0
|
|
||||||
|
|
||||||
* Migrated to support Dart >= 2.12 NNBD
|
|
||||||
|
|
||||||
## 1.0.0
|
|
||||||
|
|
||||||
* Initial checkin
|
|
|
@ -1,29 +0,0 @@
|
||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2021, dukefirehawk.com
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,25 +0,0 @@
|
||||||
# angel_seeder
|
|
||||||
|
|
||||||
[![version 1.0.](https://img.shields.io/pub/v/angel_seeder.svg)](https://pub.dartlang.org/packages/angel_seeder)
|
|
||||||
[![build status](https://travis-ci.org/angel-dart/seeder.svg?branch=master)](https://travis-ci.org/angel-dart/seeder)
|
|
||||||
|
|
||||||
Straightforward data seeder for Angel services.
|
|
||||||
This is an almost exact port of [feathers-seeder](https://github.com/thosakwe/feathers-seeder),
|
|
||||||
so its documentation should almost exactly match up here.
|
|
||||||
Fortunately, I was also the one who made `feathers-seeder`, so if you ever need assistance,
|
|
||||||
file an issue.
|
|
||||||
|
|
||||||
# Example
|
|
||||||
```dart
|
|
||||||
var app = new Angel()..use('/todos', new TodoService());
|
|
||||||
|
|
||||||
await app.configure(seed(
|
|
||||||
'todos',
|
|
||||||
new SeederConfiguration<Todo>(delete: false, count: 10, template: {
|
|
||||||
'text': (Faker faker) => 'Clean your room, ${faker.person.name()}!',
|
|
||||||
'completed': false
|
|
||||||
})));
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE**: Don't *await* seeding at application startup; that's too slow.
|
|
||||||
Instead, run it asynchronously.
|
|
|
@ -1 +0,0 @@
|
||||||
include: package:lints/recommended.yaml
|
|
|
@ -1,141 +0,0 @@
|
||||||
import 'dart:math';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:faker/faker.dart';
|
|
||||||
export 'package:faker/faker.dart';
|
|
||||||
|
|
||||||
/// Generates data using a [Faker].
|
|
||||||
typedef FakerCallback = Function(Faker faker);
|
|
||||||
|
|
||||||
/// Used to seed nested objects.
|
|
||||||
typedef SeederCallback<T> = Function(T created,
|
|
||||||
Function(Pattern path, SeederConfiguration configuration, {bool? verbose}));
|
|
||||||
|
|
||||||
/// Seeds the given service in development.
|
|
||||||
AngelConfigurer seed<T>(
|
|
||||||
Pattern servicePath,
|
|
||||||
SeederConfiguration<T> configuration, {
|
|
||||||
bool verbose = false,
|
|
||||||
}) {
|
|
||||||
return (Angel app) async {
|
|
||||||
if (configuration.runInProduction != true) return;
|
|
||||||
|
|
||||||
if (!app.services.containsKey(servicePath)) {
|
|
||||||
throw ArgumentError(
|
|
||||||
"App does not contain a service at path '$servicePath'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configuration.disabled == true) {
|
|
||||||
print("Service '$servicePath' will not be seeded.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var service = app.findService(servicePath);
|
|
||||||
var faker = Faker();
|
|
||||||
|
|
||||||
Map _buildTemplate(Map data) {
|
|
||||||
return data.keys.fold({}, (map, key) {
|
|
||||||
var value = data[key];
|
|
||||||
|
|
||||||
if (value is FakerCallback) {
|
|
||||||
return map..[key] = value(faker);
|
|
||||||
} else if (value is Function) {
|
|
||||||
return map..[key] = value();
|
|
||||||
} else if (value is Map) {
|
|
||||||
return map..[key] = _buildTemplate(value);
|
|
||||||
} else {
|
|
||||||
return map..[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Null> Function(SeederConfiguration configuration) _buildSeeder(
|
|
||||||
Service? service,
|
|
||||||
{bool? verbose}) {
|
|
||||||
return (SeederConfiguration configuration) async {
|
|
||||||
if (configuration.delete == true) await service!.remove(null);
|
|
||||||
|
|
||||||
var count = configuration.count;
|
|
||||||
var rnd = Random();
|
|
||||||
if (count < 1) count = 1;
|
|
||||||
|
|
||||||
for (var i = 0; i < count; i++) {
|
|
||||||
Future _gen(template) async {
|
|
||||||
var data = template;
|
|
||||||
|
|
||||||
if (data is Map) {
|
|
||||||
data = _buildTemplate(data);
|
|
||||||
} else if (data is Faker) {
|
|
||||||
data = template(faker);
|
|
||||||
}
|
|
||||||
|
|
||||||
var params = <String, dynamic>{}..addAll(configuration.params);
|
|
||||||
var result = await service!.create(data, params);
|
|
||||||
|
|
||||||
if (configuration.callback != null) {
|
|
||||||
await configuration.callback!(result,
|
|
||||||
(Pattern path, SeederConfiguration configuration,
|
|
||||||
{bool? verbose}) {
|
|
||||||
return _buildSeeder(app.findService(path),
|
|
||||||
verbose: verbose == true)(configuration);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configuration.template != null) {
|
|
||||||
await _gen(configuration.template);
|
|
||||||
} else if (configuration.templates.isNotEmpty == true) {
|
|
||||||
var template = configuration.templates
|
|
||||||
.elementAt(rnd.nextInt(configuration.templates.length));
|
|
||||||
await _gen(template);
|
|
||||||
} else {
|
|
||||||
throw ArgumentError(
|
|
||||||
'Configuration for service \'$servicePath\' must define at least one template.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose == true) {
|
|
||||||
print('Created $count object(s) in service \'$servicePath\'.');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
await _buildSeeder(service, verbose: verbose == true)(configuration);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configures the seeder.
|
|
||||||
class SeederConfiguration<T> {
|
|
||||||
/// Optional callback on creation.
|
|
||||||
final SeederCallback<T>? callback;
|
|
||||||
|
|
||||||
/// Number of objects to seed.
|
|
||||||
final int count;
|
|
||||||
|
|
||||||
/// If `true`, all records in the service are deleted before seeding.
|
|
||||||
final bool delete;
|
|
||||||
|
|
||||||
/// If `true`, seeding will not occur.
|
|
||||||
final bool disabled;
|
|
||||||
|
|
||||||
/// Optional service parameters to be passed.
|
|
||||||
final Map<String, dynamic> params;
|
|
||||||
|
|
||||||
/// Unless this is `true`, the seeder will not run in production.
|
|
||||||
final bool runInProduction;
|
|
||||||
|
|
||||||
/// A data template to build from.
|
|
||||||
final template;
|
|
||||||
|
|
||||||
/// A set of templates to choose from.
|
|
||||||
final Iterable templates;
|
|
||||||
|
|
||||||
SeederConfiguration(
|
|
||||||
{this.callback,
|
|
||||||
this.count = 1,
|
|
||||||
this.delete = true,
|
|
||||||
this.disabled = false,
|
|
||||||
this.params = const {},
|
|
||||||
this.runInProduction = false,
|
|
||||||
this.template,
|
|
||||||
this.templates = const []});
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
name: angel_seeder
|
|
||||||
version: 2.0.0
|
|
||||||
description: Straightforward data seeder for Angel services.
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
|
||||||
homepage: https://github.com/angel-dart/seeder
|
|
||||||
dependencies:
|
|
||||||
angel_framework:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/framework
|
|
||||||
faker: ^2.0.0
|
|
||||||
dev_dependencies:
|
|
||||||
test: ^1.17.8
|
|
||||||
lints: ^1.0.0
|
|
|
@ -1,69 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_container/mirrors.dart';
|
|
||||||
import 'package:angel_seeder/angel_seeder.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
test('create one', () async {
|
|
||||||
var app = Angel(reflector: MirrorsReflector())
|
|
||||||
..use('/todos', TodoService());
|
|
||||||
|
|
||||||
await app.configure(seed(
|
|
||||||
'todos',
|
|
||||||
SeederConfiguration<Todo>(delete: false, count: 10, template: {
|
|
||||||
'text': (Faker faker) => 'Clean your room, ${faker.person.name()}!',
|
|
||||||
'completed': false
|
|
||||||
})));
|
|
||||||
|
|
||||||
var todos = await app.findService('todos')!.index();
|
|
||||||
print('Todos: \n${todos.map((todo) => " - $todo").join("\n")}');
|
|
||||||
|
|
||||||
expect(todos, isList);
|
|
||||||
expect(todos, hasLength(10));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class TodoService extends Service {
|
|
||||||
final List<Todo> todos = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<Todo>> index([params]) => myData();
|
|
||||||
|
|
||||||
Future<List<Todo>> myData() {
|
|
||||||
var completer = Completer<List<Todo>>();
|
|
||||||
completer.complete(todos);
|
|
||||||
return completer.future;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<Object> create(data, [params]) async {
|
|
||||||
if (data is Todo) {
|
|
||||||
todos.add(data..id = todos.length.toString());
|
|
||||||
return data;
|
|
||||||
} else if (data is Map) {
|
|
||||||
todos.add(Todo.fromJson(data)..id = todos.length.toString());
|
|
||||||
return data;
|
|
||||||
} else {
|
|
||||||
throw AngelHttpException.badRequest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Todo extends Model {
|
|
||||||
final String? text;
|
|
||||||
final bool? completed;
|
|
||||||
|
|
||||||
Todo({String? id, this.text, this.completed = false}) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
factory Todo.fromJson(Map data) => Todo(
|
|
||||||
id: data['id'] as String?,
|
|
||||||
text: data['text'] as String?,
|
|
||||||
completed: data['completed'] as bool?);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => '${completed! ? "Complete" : "Incomplete"}: $text';
|
|
||||||
}
|
|
BIN
archived_packages/typed_service.zip
Normal file
BIN
archived_packages/typed_service.zip
Normal file
Binary file not shown.
13
archived_packages/typed_service/.gitignore
vendored
13
archived_packages/typed_service/.gitignore
vendored
|
@ -1,13 +0,0 @@
|
||||||
# See https://www.dartlang.org/guides/libraries/private-files
|
|
||||||
|
|
||||||
# Files and directories created by pub
|
|
||||||
.dart_tool/
|
|
||||||
.packages
|
|
||||||
.pub/
|
|
||||||
build/
|
|
||||||
# If you're building an application, you may want to check-in your pubspec.lock
|
|
||||||
pubspec.lock
|
|
||||||
|
|
||||||
# Directory created by dartdoc
|
|
||||||
# If you don't generate documentation locally you can remove this line.
|
|
||||||
doc/api/
|
|
|
@ -1,12 +0,0 @@
|
||||||
Primary Authors
|
|
||||||
===============
|
|
||||||
|
|
||||||
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
|
||||||
|
|
||||||
Thomas is the current maintainer of the code base. He has refactored and migrated the
|
|
||||||
code base to support NNBD.
|
|
||||||
|
|
||||||
* __[Tobe O](thosakwe@gmail.com)__
|
|
||||||
|
|
||||||
Tobe has written much of the original code prior to NNBD migration. He has moved on and
|
|
||||||
is no longer involved with the project.
|
|
|
@ -1,16 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
## 2.0.0
|
|
||||||
|
|
||||||
* Migrated to support Dart >= 2.12 NNBD
|
|
||||||
|
|
||||||
## 1.0.1
|
|
||||||
|
|
||||||
* Explicitly extend `Service<Id, T>`.
|
|
||||||
* Override `readData`.
|
|
||||||
* Use `Service<Id, Map<String, dynamic>>` for `inner`, instead of just
|
|
||||||
`Service<Id, Map>`.
|
|
||||||
|
|
||||||
## 1.0.0
|
|
||||||
|
|
||||||
* Initial version.
|
|
|
@ -1,29 +0,0 @@
|
||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2021, dukefirehawk.com
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,29 +0,0 @@
|
||||||
# typed_service
|
|
||||||
Angel services that use reflection (via mirrors or codegen) to (de)serialize PODO's.
|
|
||||||
Useful for quick prototypes.
|
|
||||||
|
|
||||||
Typically, [`package:angel_serialize`](https://github.com/angel-dart/serialize)
|
|
||||||
is recommended.
|
|
||||||
|
|
||||||
## Brief Example
|
|
||||||
```dart
|
|
||||||
main() async {
|
|
||||||
var app = Angel();
|
|
||||||
var http = AngelHttp(app);
|
|
||||||
var service = TypedService<String, Todo>(MapService());
|
|
||||||
hierarchicalLoggingEnabled = true;
|
|
||||||
app.use('/api/todos', service);
|
|
||||||
|
|
||||||
app
|
|
||||||
..serializer = god.serialize
|
|
||||||
..logger = Logger.detached('typed_service')
|
|
||||||
..logger.onRecord.listen((rec) {
|
|
||||||
print(rec);
|
|
||||||
if (rec.error != null) print(rec.error);
|
|
||||||
if (rec.stackTrace != null) print(rec.stackTrace);
|
|
||||||
});
|
|
||||||
|
|
||||||
await http.startServer('127.0.0.1', 3000);
|
|
||||||
print('Listening at ${http.uri}');
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -1 +0,0 @@
|
||||||
include: package:lints/recommended.yaml
|
|
|
@ -1,5 +0,0 @@
|
||||||
Command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X POST -d '@example/data.json' -H 'content-type: application/json' http://localhost:3000/api/todos; echo
|
|
||||||
```
|
|
|
@ -1,22 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "0",
|
|
||||||
"createdAt": null,
|
|
||||||
"updatedAt": null,
|
|
||||||
"idAsInt": null,
|
|
||||||
"text": "Yes",
|
|
||||||
"completed": false,
|
|
||||||
"created_at": "2019-04-26T09:51:27.494884",
|
|
||||||
"updated_at": "2019-04-26T09:51:27.494884"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "1",
|
|
||||||
"createdAt": null,
|
|
||||||
"updatedAt": null,
|
|
||||||
"idAsInt": null,
|
|
||||||
"text": "nOPE",
|
|
||||||
"completed": false,
|
|
||||||
"created_at": "2019-04-26T09:51:37.847741",
|
|
||||||
"updated_at": "2019-04-26T09:51:37.847741"
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,42 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_file_service/angel_file_service.dart';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_framework/http.dart';
|
|
||||||
import 'package:angel_typed_service/angel_typed_service.dart';
|
|
||||||
import 'package:file/local.dart';
|
|
||||||
import 'package:json_god/json_god.dart' as god;
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
var app = Angel();
|
|
||||||
var http = AngelHttp(app);
|
|
||||||
var fs = LocalFileSystem();
|
|
||||||
var exampleDir = fs.file(Platform.script).parent;
|
|
||||||
var dataJson = exampleDir.childFile('data.json');
|
|
||||||
var service = TypedService<String, Todo>(JsonFileService(dataJson));
|
|
||||||
hierarchicalLoggingEnabled = true;
|
|
||||||
app.use('/api/todos', service);
|
|
||||||
|
|
||||||
app
|
|
||||||
..serializer = god.serialize
|
|
||||||
..logger = Logger.detached('typed_service')
|
|
||||||
..logger!.onRecord.listen((rec) {
|
|
||||||
print(rec);
|
|
||||||
if (rec.error != null) print(rec.error);
|
|
||||||
if (rec.stackTrace != null) print(rec.stackTrace);
|
|
||||||
});
|
|
||||||
|
|
||||||
await http.startServer('127.0.0.1', 3000);
|
|
||||||
print('Listening at ${http.uri}');
|
|
||||||
}
|
|
||||||
|
|
||||||
class Todo extends Model {
|
|
||||||
String? text;
|
|
||||||
bool? completed;
|
|
||||||
|
|
||||||
@override
|
|
||||||
DateTime? createdAt, updatedAt;
|
|
||||||
|
|
||||||
Todo({String? id, this.text, this.completed, this.createdAt, this.updatedAt})
|
|
||||||
: super(id: id);
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:mirrors';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:json_god/json_god.dart' as god;
|
|
||||||
|
|
||||||
/// An Angel service that uses reflection to (de)serialize Dart objects.
|
|
||||||
class TypedService<Id, T> extends Service<Id, T?> {
|
|
||||||
/// The inner service.
|
|
||||||
final Service<Id, Map<String, dynamic>> inner;
|
|
||||||
|
|
||||||
TypedService(this.inner) : super() {
|
|
||||||
if (!reflectType(T).isAssignableTo(reflectType(Model))) {
|
|
||||||
throw Exception(
|
|
||||||
'If you specify a type for TypedService, it must extend Model.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
FutureOr<T>? Function(RequestContext, ResponseContext) get readData =>
|
|
||||||
_readData;
|
|
||||||
|
|
||||||
T? _readData(RequestContext req, ResponseContext res) =>
|
|
||||||
deserialize(req.bodyAsMap);
|
|
||||||
|
|
||||||
/// Attempts to deserialize [x] into an instance of [T].
|
|
||||||
T? deserialize(x) {
|
|
||||||
// print('DESERIALIZE: $x (${x.runtimeType})');
|
|
||||||
if (x is T) {
|
|
||||||
return x;
|
|
||||||
} else if (x is Map) {
|
|
||||||
var data = x.keys.fold({}, (dynamic map, key) {
|
|
||||||
var value = x[key];
|
|
||||||
|
|
||||||
if ((key == 'createdAt' ||
|
|
||||||
key == 'updatedAt' ||
|
|
||||||
key == 'created_at' ||
|
|
||||||
key == 'updated_at') &&
|
|
||||||
value is String) {
|
|
||||||
return map..[key] = DateTime.parse(value);
|
|
||||||
} else {
|
|
||||||
return map..[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var result = god.deserializeDatum(data, outputType: T);
|
|
||||||
|
|
||||||
if (data['createdAt'] is DateTime) {
|
|
||||||
result.createdAt = data['createdAt'] as DateTime?;
|
|
||||||
} else if (data['created_at'] is DateTime) {
|
|
||||||
result.createdAt = data['created_at'] as DateTime?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data['updatedAt'] is DateTime) {
|
|
||||||
result.updatedAt = data['updatedAt'] as DateTime?;
|
|
||||||
} else if (data['updated_at'] is DateTime) {
|
|
||||||
result.updatedAt = data['updated_at'] as DateTime?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print('x: $x\nresult: $result');
|
|
||||||
return result as T?;
|
|
||||||
} else {
|
|
||||||
throw ArgumentError('Cannot convert $x to $T');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serializes [x] into a [Map].
|
|
||||||
Map<String, dynamic> serialize(x) {
|
|
||||||
if (x is Model) {
|
|
||||||
return (god.serializeObject(x) as Map).cast<String, dynamic>();
|
|
||||||
} else if (x is Map) {
|
|
||||||
return x.cast<String, dynamic>();
|
|
||||||
} else {
|
|
||||||
throw ArgumentError('Cannot serialize ${x.runtimeType}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<T?>> index([Map<String, dynamic>? params]) =>
|
|
||||||
inner.index(params).then((it) => it.map(deserialize).toList());
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> create(data, [Map<String, dynamic>? params]) =>
|
|
||||||
inner.create(serialize(data), params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> read(Id id, [Map<String, dynamic>? params]) =>
|
|
||||||
inner.read(id, params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> modify(Id id, T? data, [Map<String, dynamic>? params]) =>
|
|
||||||
inner.modify(id, serialize(data), params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> update(Id id, T? data, [Map<String, dynamic>? params]) =>
|
|
||||||
inner.update(id, serialize(data), params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> remove(Id id, [Map<String, dynamic>? params]) =>
|
|
||||||
inner.remove(id, params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
name: angel_typed_service
|
|
||||||
version: 2.0.0
|
|
||||||
description: Angel services that use reflection to (de)serialize Dart objects.
|
|
||||||
homepage: https://github.com/angel-dart/typed_service
|
|
||||||
publish_to: none
|
|
||||||
environment:
|
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
|
||||||
dependencies:
|
|
||||||
angel_framework:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/framework
|
|
||||||
json_god:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/json_god
|
|
||||||
|
|
||||||
dev_dependencies:
|
|
||||||
angel_file_service:
|
|
||||||
git:
|
|
||||||
url: https://github.com/dukefirehawk/angel.git
|
|
||||||
ref: sdk-2.12.x_nnbd
|
|
||||||
path: packages/file_service
|
|
||||||
file: ^6.0.0
|
|
||||||
logging: ^1.0.0
|
|
||||||
lints: ^1.0.0
|
|
||||||
test: ^1.15.7
|
|
|
@ -1,57 +0,0 @@
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_typed_service/angel_typed_service.dart';
|
|
||||||
import 'package:test/test.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
var svc = TypedService<String?, Todo>(MapService());
|
|
||||||
|
|
||||||
test('force model', () {
|
|
||||||
expect(() => TypedService<String?, int>(MapService()), throwsException);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('serialize', () {
|
|
||||||
expect(svc.serialize({'foo': 'bar'}), {'foo': 'bar'});
|
|
||||||
expect(() => svc.serialize(2), throwsArgumentError);
|
|
||||||
var now = DateTime.now();
|
|
||||||
var t = Todo(
|
|
||||||
id: '3', text: 'a', completed: false, createdAt: now, updatedAt: now);
|
|
||||||
var m = svc.serialize(t);
|
|
||||||
print(m);
|
|
||||||
expect(m..remove('_identityHashCode')..remove('idAsInt'), {
|
|
||||||
'id': '3',
|
|
||||||
'createdAt': now.toIso8601String(),
|
|
||||||
'updatedAt': now.toIso8601String(),
|
|
||||||
'text': 'a',
|
|
||||||
'completed': false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('deserialize date', () {
|
|
||||||
var now = DateTime.now();
|
|
||||||
var m = svc.deserialize({
|
|
||||||
'createdAt': now.toIso8601String(),
|
|
||||||
'updatedAt': now.toIso8601String()
|
|
||||||
})!;
|
|
||||||
expect(m, const TypeMatcher<Todo>());
|
|
||||||
expect(m.createdAt!.millisecondsSinceEpoch, now.millisecondsSinceEpoch);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('deserialize date w/ underscore', () {
|
|
||||||
var now = DateTime.now();
|
|
||||||
var m = svc.deserialize({
|
|
||||||
'created_at': now.toIso8601String(),
|
|
||||||
'updated_at': now.toIso8601String()
|
|
||||||
})!;
|
|
||||||
expect(m, const TypeMatcher<Todo>());
|
|
||||||
expect(m.createdAt!.millisecondsSinceEpoch, now.millisecondsSinceEpoch);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Todo extends Model {
|
|
||||||
String? text;
|
|
||||||
bool? completed;
|
|
||||||
@override
|
|
||||||
DateTime? createdAt, updatedAt;
|
|
||||||
Todo({String? id, this.text, this.completed, this.createdAt, this.updatedAt})
|
|
||||||
: super(id: id);
|
|
||||||
}
|
|
BIN
archived_packages/wings.zip
Normal file
BIN
archived_packages/wings.zip
Normal file
Binary file not shown.
|
@ -1,121 +0,0 @@
|
||||||
---
|
|
||||||
Language: Cpp
|
|
||||||
# BasedOnStyle: LLVM
|
|
||||||
AccessModifierOffset: -2
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignConsecutiveAssignments: false
|
|
||||||
AlignConsecutiveDeclarations: false
|
|
||||||
AlignEscapedNewlines: Right
|
|
||||||
AlignOperands: true
|
|
||||||
AlignTrailingComments: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
|
||||||
AllowShortBlocksOnASingleLine: false
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: MultiLine
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BraceWrapping:
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: false
|
|
||||||
AfterEnum: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInheritanceComma: false
|
|
||||||
BreakInheritanceList: BeforeColon
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializersBeforeComma: false
|
|
||||||
BreakConstructorInitializers: BeforeColon
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakStringLiterals: true
|
|
||||||
ColumnLimit: 80
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros:
|
|
||||||
- foreach
|
|
||||||
- Q_FOREACH
|
|
||||||
- BOOST_FOREACH
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
|
||||||
Priority: 2
|
|
||||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
|
||||||
Priority: 3
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 1
|
|
||||||
IncludeIsMainRegex: '(Test)?$'
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentWidth: 2
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBinPackProtocolList: Auto
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyBreakTemplateDeclaration: 10
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
|
||||||
PointerAlignment: Right
|
|
||||||
ReflowComments: true
|
|
||||||
SortIncludes: true
|
|
||||||
SortUsingDeclarations: true
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterTemplateKeyword: true
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpacesBeforeTrailingComments: 1
|
|
||||||
SpacesInAngles: false
|
|
||||||
SpacesInContainerLiterals: true
|
|
||||||
SpacesInCStyleCastParentheses: false
|
|
||||||
SpacesInParentheses: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
Standard: Cpp11
|
|
||||||
StatementMacros:
|
|
||||||
- Q_UNUSED
|
|
||||||
- QT_REQUIRE_VERSION
|
|
||||||
TabWidth: 8
|
|
||||||
UseTab: Never
|
|
||||||
...
|
|
||||||
|
|
67
archived_packages/wings/.gitignore
vendored
67
archived_packages/wings/.gitignore
vendored
|
@ -1,67 +0,0 @@
|
||||||
# See https://www.dartlang.org/guides/libraries/private-files
|
|
||||||
|
|
||||||
# Files and directories created by pub
|
|
||||||
.dart_tool/
|
|
||||||
.packages
|
|
||||||
build/
|
|
||||||
# If you're building an application, you may want to check-in your pubspec.lock
|
|
||||||
pubspec.lock
|
|
||||||
|
|
||||||
# Directory created by dartdoc
|
|
||||||
# If you don't generate documentation locally you can remove this line.
|
|
||||||
doc/api/
|
|
||||||
|
|
||||||
# Avoid committing generated Javascript files:
|
|
||||||
*.dart.js
|
|
||||||
*.info.json # Produced by the --dump-info flag.
|
|
||||||
*.js # When generated by dart2js. Don't specify *.js if your
|
|
||||||
# project includes source files written in JavaScript.
|
|
||||||
*.js_
|
|
||||||
*.js.deps
|
|
||||||
*.js.map
|
|
||||||
|
|
||||||
*.o
|
|
||||||
# *.dylib
|
|
||||||
*.a
|
|
||||||
# *.so
|
|
||||||
*.lib
|
|
||||||
*.obj
|
|
||||||
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
# Created by https://www.gitignore.io/api/cmake
|
|
||||||
# Edit at https://www.gitignore.io/?templates=cmake
|
|
||||||
|
|
||||||
### CMake ###
|
|
||||||
CMakeLists.txt.user
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles
|
|
||||||
CMakeScripts
|
|
||||||
Testing
|
|
||||||
Makefile
|
|
||||||
cmake_install.cmake
|
|
||||||
install_manifest.txt
|
|
||||||
compile_commands.json
|
|
||||||
CTestTestfile.cmake
|
|
||||||
_deps
|
|
||||||
|
|
||||||
### CMake Patch ###
|
|
||||||
# External projects
|
|
||||||
*-prefix/
|
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/cmake
|
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/vagrant
|
|
||||||
# Edit at https://www.gitignore.io/?templates=vagrant
|
|
||||||
|
|
||||||
### Vagrant ###
|
|
||||||
# General
|
|
||||||
.vagrant/
|
|
||||||
|
|
||||||
# Log files (if you are creating logs in debug mode, uncomment this)
|
|
||||||
# *.log
|
|
||||||
|
|
||||||
### Vagrant Patch ###
|
|
||||||
*.box
|
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/vagrant
|
|
6
archived_packages/wings/.gitmodules
vendored
6
archived_packages/wings/.gitmodules
vendored
|
@ -1,6 +0,0 @@
|
||||||
[submodule "cmake_dart_utils"]
|
|
||||||
path = cmake_dart_utils
|
|
||||||
url = https://github.com/thosakwe/cmake_dart_utils.git
|
|
||||||
[submodule "lib/src/http-parser"]
|
|
||||||
path = lib/src/http-parser
|
|
||||||
url = https://github.com/nodejs/http-parser.git
|
|
|
@ -1,6 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
project(angel_wings)
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake_dart_utils/cmake")
|
|
||||||
find_package(Dart REQUIRED)
|
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
|
||||||
add_subdirectory(lib/src)
|
|
|
@ -1,29 +0,0 @@
|
||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2021, dukefirehawk.com
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
@ -1,51 +0,0 @@
|
||||||
# wings
|
|
||||||
Native HTTP driver for Angel, for a nice speed boost.
|
|
||||||
|
|
||||||
Not ready for production.
|
|
||||||
|
|
||||||
## How does it work?
|
|
||||||
Typically, Angel uses the `AngelHttp` driver, which is wrapper over the `HttpServer` functionality in
|
|
||||||
`dart:io`, which in turns uses the `ServerSocket` and `Socket` functionality. This is great - Dart's standard
|
|
||||||
library comes with an HTTP server, which saves a lot of difficult in implementation.
|
|
||||||
|
|
||||||
However, abstraction tends to come with a cost. Wings seeks to minimize abstraction entirely. Rather than
|
|
||||||
using the built-in Dart network stack, Wings' HTTP server is implemented in C++ as a Dart native extension,
|
|
||||||
and the `AngelWings` driver listens to events from the extension and converts them directly into
|
|
||||||
`RequestContext` objects, without any additional abstraction within. This reduces the amount of computation
|
|
||||||
performed on each request, and helps to minimize response latency. Sending data from the response buffer in plain
|
|
||||||
Dart surprisingly is the most expensive operation, as is revealed by the Observatory.
|
|
||||||
|
|
||||||
By combining Dart's powerful VM with a native code server based on
|
|
||||||
[the same one used in Node.js](https://github.com/nodejs/http-parser),
|
|
||||||
`AngelWings` trims several milliseconds off every request, both saving resources and reducing
|
|
||||||
load times for high-traffic applications.
|
|
||||||
|
|
||||||
## How can I use it?
|
|
||||||
The intended way to use `AngelWings` is via
|
|
||||||
[`package:build_native`](https://github.com/thosakwe/build_native);
|
|
||||||
however, the situation surrounding distributing native extensions is yet far from ideal,
|
|
||||||
so this package includes pre-built binaries out-of-the-box.
|
|
||||||
|
|
||||||
Thanks to this, you can use it like any other Dart package, by installing it via Pub.
|
|
||||||
|
|
||||||
## Brief example
|
|
||||||
Using `AngelWings` is almost identical to using `AngelHttp`; however, it does
|
|
||||||
not support SSL, and therefore should be placed behind a reverse proxy like `nginx` in production.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
main() async {
|
|
||||||
var app = new Angel();
|
|
||||||
var wings = new AngelWings(app, shared: true, useZone: false);
|
|
||||||
|
|
||||||
app.injectEncoders({'gzip': gzip.encoder, 'deflate': zlib.encoder});
|
|
||||||
|
|
||||||
app.get('/hello', 'Hello, native world! This is Angel WINGS.');
|
|
||||||
|
|
||||||
var fs = const LocalFileSystem();
|
|
||||||
var vDir = new VirtualDirectory(app, fs, source: fs.directory('web'));
|
|
||||||
app.use(vDir.handleRequest);
|
|
||||||
|
|
||||||
await wings.startServer('127.0.0.1', 3000);
|
|
||||||
print('Listening at http://${wings.address.address}:${wings.port}');
|
|
||||||
}
|
|
||||||
```
|
|
6
archived_packages/wings/Vagrantfile
vendored
6
archived_packages/wings/Vagrantfile
vendored
|
@ -1,6 +0,0 @@
|
||||||
# -*- mode: ruby -*-
|
|
||||||
# vi: set ft=ruby :
|
|
||||||
Vagrant.configure("2") do |config|
|
|
||||||
config.vm.box = "ubuntu/bionic64"
|
|
||||||
config.vm.provision "shell", path: "provision.sh"
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
include: package:lints/recommended.yaml
|
|
|
@ -1,23 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'util.dart';
|
|
||||||
|
|
||||||
const AngelBenchmark emptyBenchmark = _EmptyBenchmark();
|
|
||||||
|
|
||||||
void main() => runBenchmarks([emptyBenchmark]);
|
|
||||||
|
|
||||||
class _EmptyBenchmark implements AngelBenchmark {
|
|
||||||
const _EmptyBenchmark();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get name => 'empty';
|
|
||||||
|
|
||||||
@override
|
|
||||||
FutureOr<void> rawHandler(HttpRequest req, HttpResponse res) {
|
|
||||||
return res.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void setupAngel(Angel app) {}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:isolate';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_framework/http.dart';
|
|
||||||
import 'package:angel_wings/angel_wings.dart';
|
|
||||||
import 'package:io/ansi.dart';
|
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
Future<Process> _runWrk(
|
|
||||||
{ProcessStartMode mode = ProcessStartMode.inheritStdio}) async {
|
|
||||||
return await Process.start('wrk', ['http://localhost:$testPort'], mode: mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _warmUp() async {
|
|
||||||
var wrk = await _runWrk();
|
|
||||||
await wrk.exitCode;
|
|
||||||
// await wrk.stderr.drain();
|
|
||||||
// await wrk.stdout.drain();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _10s() => Future.delayed(Duration(seconds: 10));
|
|
||||||
|
|
||||||
const testPort = 8877;
|
|
||||||
|
|
||||||
Future<void> runBenchmarks(Iterable<AngelBenchmark> benchmarks,
|
|
||||||
{Iterable<String> factories = const [
|
|
||||||
// 'angel_http',
|
|
||||||
'angel_wings',
|
|
||||||
]}) async {
|
|
||||||
for (var benchmark in benchmarks) {
|
|
||||||
print(magenta.wrap('Entering benchmark: ${benchmark.name}'));
|
|
||||||
|
|
||||||
// // Run dart:io
|
|
||||||
// print(lightGray.wrap('Booting dart:io server (waiting 10s)...'));
|
|
||||||
// var isolates = <Isolate>[];
|
|
||||||
// for (int i = 0; i < Platform.numberOfProcessors; i++) {
|
|
||||||
// isolates.add(await Isolate.spawn(_httpIsolate, benchmark));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// await _10s();
|
|
||||||
// print(lightGray.wrap('Warming up dart:io server...'));
|
|
||||||
// await _warmUp();
|
|
||||||
|
|
||||||
// stdout
|
|
||||||
// ..write(lightGray.wrap('Now running `wrk` for '))
|
|
||||||
// ..write(cyan.wrap(benchmark.name))
|
|
||||||
// ..writeln(lightGray.wrap(' (waiting 10s)...'));
|
|
||||||
// var wrk = await _runWrk(mode: ProcessStartMode.inheritStdio);
|
|
||||||
// await wrk.exitCode;
|
|
||||||
// isolates.forEach((i) => i.kill(priority: Isolate.immediate));
|
|
||||||
|
|
||||||
// Run Angel HTTP, Wings
|
|
||||||
for (var fac in factories) {
|
|
||||||
print(lightGray.wrap('Booting $fac server...'));
|
|
||||||
|
|
||||||
var isolates = <Isolate>[];
|
|
||||||
for (var i = 0; i < Platform.numberOfProcessors; i++) {
|
|
||||||
isolates
|
|
||||||
.add(await Isolate.spawn(_angelIsolate, Tuple2(benchmark, fac)));
|
|
||||||
}
|
|
||||||
|
|
||||||
await _10s();
|
|
||||||
print(lightGray.wrap('Warming up $fac server...'));
|
|
||||||
await _warmUp();
|
|
||||||
stdout
|
|
||||||
..write(lightGray.wrap('Now running `wrk` for '))
|
|
||||||
..write(cyan.wrap(benchmark.name))
|
|
||||||
..writeln(lightGray.wrap('...'));
|
|
||||||
var wrk = await _runWrk(mode: ProcessStartMode.inheritStdio);
|
|
||||||
await wrk.exitCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
void _httpIsolate(AngelBenchmark benchmark) {
|
|
||||||
Future(() async {
|
|
||||||
var raw = await HttpServer.bind(InternetAddress.loopbackIPv4, testPort,
|
|
||||||
shared: true);
|
|
||||||
raw.listen((r) => benchmark.rawHandler(r, r.response));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void _angelIsolate(Tuple2<AngelBenchmark, String> args) {
|
|
||||||
Future(() async {
|
|
||||||
var app = Angel();
|
|
||||||
late Driver driver;
|
|
||||||
|
|
||||||
if (args.item2 == 'angel_http') {
|
|
||||||
driver = AngelHttp.custom(app, startShared);
|
|
||||||
} else if (args.item2 == 'angel_wings') {
|
|
||||||
driver = AngelWings.custom(app, startSharedWings);
|
|
||||||
}
|
|
||||||
|
|
||||||
await app.configure(args.item1.setupAngel);
|
|
||||||
await driver.startServer(InternetAddress.loopbackIPv4, testPort);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AngelBenchmark {
|
|
||||||
const AngelBenchmark();
|
|
||||||
|
|
||||||
String get name;
|
|
||||||
|
|
||||||
FutureOr<void> setupAngel(Angel app);
|
|
||||||
|
|
||||||
FutureOr<void> rawHandler(HttpRequest req, HttpResponse res);
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:angel_static/angel_static.dart';
|
|
||||||
import 'package:angel_wings/angel_wings.dart';
|
|
||||||
import 'package:file/local.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:pretty_logging/pretty_logging.dart';
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
hierarchicalLoggingEnabled = true;
|
|
||||||
|
|
||||||
var logger = Logger.detached('wings')
|
|
||||||
..level = Level.ALL
|
|
||||||
..onRecord.listen(prettyLog);
|
|
||||||
var app = Angel(logger: logger);
|
|
||||||
var wings = AngelWings(app);
|
|
||||||
var fs = LocalFileSystem();
|
|
||||||
var vDir = CachingVirtualDirectory(app, fs,
|
|
||||||
source: fs.currentDirectory, allowDirectoryListing: true);
|
|
||||||
|
|
||||||
app.mimeTypeResolver.addExtension('yaml', 'text/x-yaml');
|
|
||||||
|
|
||||||
app.get('/', (req, res) => 'WINGS!!!');
|
|
||||||
app.post('/', (req, res) async {
|
|
||||||
await req.parseBody();
|
|
||||||
return req.bodyAsMap;
|
|
||||||
});
|
|
||||||
|
|
||||||
app.fallback(vDir.handleRequest);
|
|
||||||
app.fallback((req, res) => throw AngelHttpException.notFound());
|
|
||||||
|
|
||||||
await wings.startServer(InternetAddress.loopbackIPv4, 3000);
|
|
||||||
print('Listening at ${wings.uri}');
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue