Compare commits

...

41 commits

Author SHA1 Message Date
thomashii
79152a1953 Upgraded to v8 2023-06-19 23:31:42 +08:00
thomashii
22cdff9319 Removed overrides dependency 2022-05-01 18:17:02 +08:00
thomashii
0933a7f727 Template for MariaDB 2022-05-01 17:46:14 +08:00
thomashii
985100c271 mysql orm template 2022-04-30 10:14:23 +08:00
Thomas Hii
4839e2cef5
Merge pull request #5 from dukefirehawk/v6/angel3-orm
V6/angel3 orm
2022-04-26 09:17:47 +08:00
thomashii
5ac098e3f5 Upgrade to SDK 2.16.x 2022-04-26 08:02:17 +08:00
Thomas Hii
31dea50201
Merge pull request #2 from L3odr0id/patch-1
Mistake in parameter name
2022-04-02 21:17:32 +08:00
L3odr0id
5eefbcb26f
Fix key name 2022-03-26 19:54:04 +03:00
thomashii
b1bd5c341e Update to support v6.0.0 2022-03-15 13:25:51 +08:00
Thomas Hii
b5fea5806d
Merge pull request #1 from outersky/angel3-orm
fix: Present<Message> should be Message
2022-02-11 23:22:38 +08:00
outersky
290b018ab9
fix README 2022-02-04 10:32:26 +08:00
outersky
65f62b75c0
fix: Present<Message> should be Message
Present<*> is not supported now by default
2022-02-04 10:26:20 +08:00
thomashii
3b67c9670d Updated ORM template 2021-09-25 18:45:23 +08:00
thomashii
7401143635 Updated pacakges 2021-08-19 08:29:50 +08:00
thomashii
8e00405e2e Updated packages 2021-08-19 08:20:07 +08:00
thomashii
b120ba505f Updated the ORM example 2021-07-25 17:11:58 +08:00
thomashii
fab33a543c Updated ORM 2021-07-17 12:52:48 +08:00
thomashii
a32652b683 Updated angel3-orm 2021-06-14 08:08:25 +08:00
thomashii
9eb81a541d Updated README 2021-06-11 12:28:14 +08:00
thomashii
9697137ae8 Updated README 2021-06-11 12:09:42 +08:00
thomashii
d11df03d97 Updated README 2021-06-11 12:08:20 +08:00
thomashii
636f33de37 Updated angel3_orm 2021-06-11 12:00:10 +08:00
thomashii
bf9bf67fa8 Migrated to NNBD 2021-05-16 16:25:29 +08:00
thomashii
a32bb29af6 Fixed to work with sdk 2.10.x 2021-03-09 00:17:42 +08:00
thomashii
10192bd29a ORM template for SDK 2.12.x 2021-03-07 20:52:36 +08:00
thomashii
233f10b384 Updated dependencies 2021-02-19 22:34:24 +08:00
Tobe O
54afecd3bc Merge branch 'master' into orm 2019-10-09 14:26:50 -04:00
Tobe O
1482cb2ff7 Merge branch 'master' into orm 2019-10-09 14:21:34 -04:00
Tobe O
007f926f1b Merge branch 'master' into orm 2019-05-01 19:33:06 -04:00
Tobe O
514b697b00 Use app logger for orm 2019-05-01 19:32:31 -04:00
Tobe O
ece9e5d4fa Merge branch 'master' into orm 2019-05-01 19:30:04 -04:00
Tobe O
0d0cb707c2 Use only stable deps 2019-04-29 13:57:47 -04:00
Tobe O
ffbc93c668 Merge branch 'master' into orm 2019-04-29 12:48:17 -04:00
Tobe O
5186ae8111 merge from master 2019-04-28 14:55:31 -04:00
Tobe O
91ff5f4e11 Formatting 2019-04-18 12:24:11 -04:00
Tobe O
772f74a908 merge from master 2019-04-18 12:23:23 -04:00
Tobe Osakwe
850ccb71b1
Update dev.dart 2019-02-06 23:00:45 -05:00
Tobe Osakwe
a3d80686b4
Update dev.dart 2019-02-06 16:59:05 -05:00
Tobe Osakwe
d42dd2befb
Update routes.dart 2019-01-23 14:45:44 -05:00
Tobe Osakwe
478d45bf47
Update pubspec.yaml 2019-01-23 14:43:27 -05:00
Tobe O
84f5ae5403 orm boilerplate 2.x 2019-01-11 19:44:28 -05:00
31 changed files with 635 additions and 258 deletions

View file

@ -1,10 +1,11 @@
.dart_tool .dart_tool
.idea .idea
.pub
.vscode .vscode
.metals
.git
.github
.packages
logs/ logs/
test/ test/
build/ build/
.analysis-options pubspec.lock
.packages
*.g.dart

3
.github/FUNDING.yml vendored
View file

@ -1,3 +0,0 @@
# These are supported funding model platforms
github: [thosakwe]

4
.gitignore vendored
View file

@ -78,7 +78,7 @@ crashlytics-build.properties
fabric.properties fabric.properties
### VSCode template ### VSCode template
.vscode/* .vscode/
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json !.vscode/launch.json
@ -88,3 +88,5 @@ logs/
*.pem *.pem
.DS_Store .DS_Store
server_log.txt server_log.txt
.metals/

View file

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</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>

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
<State>
<id>General</id>
</State>
<State>
<id>XPath</id>
</State>
</expanded-state>
<selected-state>
<State>
<id>AngularJS</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
</project>

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/angel.iml" filepath="$PROJECT_DIR$/.idea/angel.iml" />
</modules>
</component>
</project>

View file

@ -1,8 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="dev.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
<option name="VMOptions" value="--observe" />
<option name="filePath" value="$PROJECT_DIR$/bin/dev.dart" />
<option name="workingDirectory" value="$PROJECT_DIR$" />
<method />
</configuration>
</component>

View file

@ -1,11 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="prod.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
<option name="checkedMode" value="false" />
<option name="envs">
<entry key="ANGEL_ENV" value="production" />
</option>
<option name="filePath" value="$PROJECT_DIR$/bin/prod.dart" />
<option name="workingDirectory" value="$PROJECT_DIR$" />
<method />
</configuration>
</component>

5
CHANGELOG.md Normal file
View file

@ -0,0 +1,5 @@
# Change Log
## 1.0.0
* Initial version

View file

@ -1,14 +1,24 @@
FROM google/dart:latest FROM dart:latest
COPY ./ ./ # Copy all the source code
COPY ./config /app/config
COPY ./lib /app/lib
COPY ./bin /app/bin
COPY ./views /app/views
COPY ./web /app/web
COPY ./*.yaml /app/
# Install dependencies, pre-build WORKDIR /app
RUN pub get RUN dart pub upgrade
# Optionally build generaed sources. # Optionally build generated sources.
# RUN pub run build_runner build # RUN pub run build_runner build
# Set environment, start server # Set environment, start server in JIT mode
ENV ANGEL_ENV=production ENV ANGEL_ENV=production
EXPOSE 3000 EXPOSE 3000
CMD dart bin/prod.dart CMD dart ./bin/prod.dart -p 3000 -a 0.0.0.0
# Use -j flag to set higher number of isolates
#CMD dart ./bin/prod.dart -p 3000 -a 0.0.0.0 -j 50

42
LICENSE
View file

@ -1,21 +1,29 @@
The MIT License (MIT) BSD 3-Clause License
Copyright (c) 2016 angel-dart Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Redistribution and use in source and binary forms, with or without
of this software and associated documentation files (the "Software"), to deal modification, are permitted provided that the following conditions are met:
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 1. Redistributions of source code must retain the above copyright notice, this
copies or substantial portions of the Software. list of conditions and the following disclaimer.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2. Redistributions in binary form must reproduce the above copyright notice,
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, this list of conditions and the following disclaimer in the documentation
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE and/or other materials provided with the distribution.
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 3. Neither the name of the copyright holder nor the names of its
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE contributors may be used to endorse or promote products derived from
SOFTWARE. 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.

112
README.md
View file

@ -1,60 +1,86 @@
[![The Angel Framework](https://angel-dart.github.io/assets/images/logo.png)](https://angel-dart.dev) # ORM Starter Application for Angel3 framework
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/angel_dart/discussion) This is an ORM starter application for [Angel3 framework](https://angel3-framework.web.app) which is a full-stack Web framework in Dart. The default database is MariaDB. MySQL support is still in active development.
[![Pub](https://img.shields.io/pub/v/angel_framework.svg)](https://pub.dartlang.org/packages/angel_framework)
[![Build status](https://travis-ci.org/angel-dart/framework.svg?branch=master)](https://travis-ci.org/angel-dart/framework)
![License](https://img.shields.io/github/license/angel-dart/framework.svg)
**A polished, production-ready backend framework in Dart.**
*Note: This repo is an application boilerplate ,and not the underlying framework library.*
-----
## About
Angel is a full-stack Web framework in Dart. It aims to
streamline development by providing many common features
out-of-the-box in a consistent manner.
With features like the following, Angel is the all-in-one framework you should choose to build your next project:
* [GraphQL Support](https://github.com/angel-dart/graphql)
* [PostgreSQL ORM](https://github.com/angel-dart/orm)
* [Dependency Injection](https://docs.angel-dart.dev/guides/dependency-injection)
* And [much more](https://github.com/angel-dart)...
## Installation & Setup ## Installation & Setup
Once you have [Dart](https://www.dartlang.org/) installed, bootstrapping a project is as simple as running a few shell commands: 1. Download and install [Dart](https://dart.dev/get-dart).
2. Install `MariaDB` 10.2.x or later
3. Create a new user and database using MySQL Client. For example:
Install the [Angel CLI](https://github.com/angel-dart/cli): ```sql
MariaDB [(none)]> CREATE DATABASE appdb;
MariaDB [(none)]> CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'App1970#';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
```
```bash 4. Update the `mariadb` section in the `config/default.yaml` file with the newly created user and database name.
pub global activate angel_cli
```
Bootstrap a project: ```yaml
mariadb:
host: localhost
port: 3306
database_name: appdb
username: appuser
password: App1970#
```
```bash 5. Run the migration to generate `migrations` and `greetings` tables in the database.
angel init hello
```
You can even have your server run and be *hot-reloaded* on file changes: ```bash
dart bin/migrate.dart up
```
```bash ### Development
dart --observe bin/dev.dart
```
Next, check out the [detailed documentation](https://docs.angel-dart.dev/v/2.x) to learn to flesh out your project. 1. Run the following command to start Angel3 server in dev mode to *hot-reloaded* on file changes:
## Examples and Documentation ```bash
Visit the [documentation](https://docs.angel-dart.dev/v/2.x) dart --observe bin/dev.dart
for dozens of guides and resources, including video tutorials, ```
to get up and running as quickly as possible with Angel.
Examples and complete projects can be found 2. Modify the code and watch the changes applied to the application
[here](https://github.com/angel-dart/examples-v2).
3. Insert a message into DB:
You can also view the [API Documentation](http://www.dartdocs.org/documentation/angel_framework/latest). ```bash
curl -H "Content-Type: application/json" -X POST -d '{"message":"OK_Message" }' "http://localhost:3000/greetings/"
```
There is also an [Awesome Angel :fire:](https://github.com/angel-dart/awesome-angel) list. or
```bash
curl -X POST -d 'message=OK_Message2' "http://localhost:3000/greetings/"
```
4. Query DB:
```bash
curl http://localhost:3000/greetings/
```
### Production
1. Run the following command:
```bash
dart bin/prod.dart
```
2. Run as docker. Edit and run the provided `Dockerfile` to build the image.
### Building ORM Model
1. Run the followig command:
```bash
dart run build_runner build
```
## Resources
Visit the [Developer Guide](https://angel3-docs.dukefirehawk.com/guides) for dozens of guides and resources, including video tutorials, to get up and running as quickly as possible with Angel3.
Examples and complete projects can be found [here](https://angel3-framework.web.app/#/examples).
You can also view the [API Documentation](https://pub.dev/documentation/angel3_framework/latest/).

View file

@ -1,8 +1 @@
include: package:pedantic/analysis_options.yaml include: package:lints/recommended.yaml
analyzer:
strong-mode:
implicit-casts: false
linter:
rules:
- unnecessary_const
- unnecessary_new

View file

@ -1,17 +1,17 @@
import 'dart:io'; import 'dart:io';
import 'package:angel/src/pretty_logging.dart';
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
import 'package:angel_container/mirrors.dart'; import 'package:belatuk_pretty_logging/belatuk_pretty_logging.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_container/mirrors.dart';
import 'package:angel_hot/angel_hot.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_hot/angel3_hot.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
main() async { void main() async {
// Watch the config/ and web/ directories for changes, and hot-reload the server. // Watch the config/ and web/ directories for changes, and hot-reload the server.
hierarchicalLoggingEnabled = true; hierarchicalLoggingEnabled = true;
var hot = HotReloader(() async { var hot = HotReloader(() async {
var logger = Logger.detached('{{angel}}') var logger = Logger.detached('Angel3')
..level = Level.ALL ..level = Level.ALL
..onRecord.listen(prettyLog); ..onRecord.listen(prettyLog);
var app = Angel(logger: logger, reflector: MirrorsReflector()); var app = Angel(logger: logger, reflector: MirrorsReflector());
@ -24,5 +24,5 @@ main() async {
var server = await hot.startServer('127.0.0.1', 3000); var server = await hot.startServer('127.0.0.1', 3000);
print( print(
'{{angel}} server listening at http://${server.address.address}:${server.port}'); '[angel] server listening at http://${server.address.address}:${server.port}');
} }

40
bin/migrate.dart Normal file
View file

@ -0,0 +1,40 @@
import 'package:angel/src/config/plugins/orm.dart';
import 'package:angel/models.dart';
import 'package:angel3_configuration/angel3_configuration.dart';
import 'package:angel3_migration_runner/angel3_migration_runner.dart';
import 'package:angel3_migration_runner/mariadb.dart';
//import 'package:angel3_migration_runner/mysql.dart';
import 'package:file/local.dart';
import 'package:logging/logging.dart';
void main(List<String> args) async {
// Enable the logging
Logger.root.level = Level.INFO;
Logger.root.onRecord.listen((rec) {
print('${rec.time}: ${rec.level.name}: ${rec.loggerName}: ${rec.message}');
if (rec.error != null) {
print(rec.error);
print(rec.stackTrace);
}
});
var fs = LocalFileSystem();
var configuration = await loadStandaloneConfiguration(fs);
// MariaDB database
var connection = await connectToMariaDb(configuration);
var migrationRunner = MariaDbMigrationRunner(connection, migrations: [
GreetingMigration(),
]);
// MySQL database
/*
var connection = await connectToMysql(configuration);
var migrationRunner = MySqlMigrationRunner(connection, migrations: [
GreetingMigration(),
]);
*/
await runMigrations(migrationRunner, args);
}

View file

@ -1,6 +1,6 @@
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
import 'package:angel_container/mirrors.dart'; import 'package:angel3_container/mirrors.dart';
import 'package:angel_production/angel_production.dart'; import 'package:angel3_production/angel3_production.dart';
// NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any // NOTE: By default, the Runner class does not use the `MirrorsReflector`, or any
// reflector, by default. // reflector, by default.
@ -17,7 +17,7 @@ import 'package:angel_production/angel_production.dart';
// so use it if possible. // so use it if possible.
// //
// However, the following alternatives exist: // However, the following alternatives exist:
// * Generation via `package:angel_container_generator` // * Generation via `package:angel3_container_generator`
// * Creating an instance of `StaticReflector` // * Creating an instance of `StaticReflector`
// * Manually implementing the `Reflector` interface (cumbersome; not recommended) // * Manually implementing the `Reflector` interface (cumbersome; not recommended)
// //
@ -25,6 +25,5 @@ import 'package:angel_production/angel_production.dart';
// so in the meantime, visit the Angel chat for further questions: // so in the meantime, visit the Angel chat for further questions:
// //
// https://gitter.im/angel_dart/discussion // https://gitter.im/angel_dart/discussion
main(List<String> args) => void main(List<String> args) =>
Runner('{{angel}}', configureServer, reflector: MirrorsReflector()) Runner('Angel3', configureServer, reflector: MirrorsReflector()).run(args);
.run(args);

View file

@ -1,5 +1,14 @@
# Default server configuration. # Default server configuration.
jwt_secret: INSECURE_DEFAULT_SECRET jwt_secret: INSECURE_DEFAULT_SECRET
host: 127.0.0.1 host: 127.0.0.1
mongo_db: mongodb://localhost:27017/angel
port: 3000 port: 3000
mysql:
host: localhost
port: 3306
database_name: appdb
username: appuser
password: App1970#
use_ssl: false

View file

@ -1,8 +1,6 @@
/// Your very own web application! /// Your very own web application!
library angel;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'src/config/config.dart' as configuration; import 'src/config/config.dart' as configuration;
import 'src/routes/routes.dart' as routes; import 'src/routes/routes.dart' as routes;

1
lib/models.dart Normal file
View file

@ -0,0 +1 @@
export 'src/models/greeting.dart';

View file

@ -1,9 +1,6 @@
/// Configuration for this Angel instance. import 'package:angel3_configuration/angel3_configuration.dart';
library angel.src.config; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_jael/angel3_jael.dart';
import 'package:angel_configuration/angel_configuration.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_jael/angel_jael.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'plugins/plugins.dart' as plugins; import 'plugins/plugins.dart' as plugins;

View file

@ -0,0 +1,76 @@
import 'dart:async';
import 'dart:io';
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_orm_mysql/angel3_orm_mysql.dart';
import 'package:mysql1/mysql1.dart';
//import 'package:mysql_client/mysql_client.dart';
// For MariaDb
Future<void> configureServer(Angel app) async {
try {
var connection = await connectToMariaDb(app.configuration);
var executor = MariaDbExecutor(connection, logger: app.logger);
app
..container.registerSingleton<QueryExecutor>(executor)
..shutdownHooks.add((_) => connection.close());
} catch (e) {
app.logger.severe("Failed to connect to MariaDB. ORM disabled.", e);
}
}
// MariaDB connection
Future<MySqlConnection> connectToMariaDb(Map configuration) async {
var mariaDbConfig = configuration['mysql'] as Map? ?? {};
var settings = ConnectionSettings(
host: mariaDbConfig['host'] as String? ?? 'localhost',
port: mariaDbConfig['port'] as int? ?? 3306,
db: mariaDbConfig['database_name'] as String? ??
Platform.environment['USER'] ??
Platform.environment['USERNAME'] ??
'',
user: mariaDbConfig['username'] as String?,
password: mariaDbConfig['password'] as String?,
timeout: Duration(
seconds: mariaDbConfig['timeout_in_seconds'] as int? ?? 30000),
useSSL: mariaDbConfig['use_ssl'] as bool? ?? false);
var connection = await MySqlConnection.connect(settings);
return connection;
}
// For Mysql
/*
Future<void> configureServer(Angel app) async {
try {
var connection = await connectToMysql(app.configuration);
var executor = MySqlExecutor(connection, logger: app.logger);
app
..container.registerSingleton<QueryExecutor>(executor)
..shutdownHooks.add((_) => connection.close());
} catch (e) {
app.logger.severe("Failed to connect to MySQL. ORM disabled.", e);
}
}
// Mysql Connection
Future<MySQLConnection> connectToMysql(Map configuration) async {
var mysqlConfig = configuration['mysql'] as Map? ?? {};
var connection = await MySQLConnection.createConnection(
host: mysqlConfig['host'] as String? ?? 'localhost',
port: mysqlConfig['port'] as int? ?? 3306,
databaseName: mysqlConfig['database_name'] as String? ??
Platform.environment['USER'] ??
Platform.environment['USERNAME'] ??
'',
userName: mysqlConfig['username'] as String? ?? '',
password: mysqlConfig['password'] as String? ?? '',
secure: mysqlConfig['use_ssl'] as bool? ?? false);
await connection.connect(timeoutMs: 10000);
return connection;
}
*/

View file

@ -1,9 +1,8 @@
/// Custom plugins go here.
library angel.src.config.plugins;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'orm.dart' as orm;
Future configureServer(Angel app) async { Future configureServer(Angel app) async {
// Include any plugins you have made here. // Include any plugins you have made here.
await app.configure(orm.configureServer);
} }

View file

@ -0,0 +1,12 @@
import 'package:angel3_migration/angel3_migration.dart';
import 'package:angel3_serialize/angel3_serialize.dart';
import 'package:angel3_orm/angel3_orm.dart';
import 'package:optional/optional.dart';
part 'greeting.g.dart';
@serializable
@orm
abstract class _Greeting extends Model {
@SerializableField(isNullable: false)
String? get message;
}

View file

@ -0,0 +1,281 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'greeting.dart';
// **************************************************************************
// MigrationGenerator
// **************************************************************************
class GreetingMigration extends Migration {
@override
void up(Schema schema) {
schema.create('greetings', (table) {
table.serial('id').primaryKey();
table.timeStamp('created_at');
table.timeStamp('updated_at');
table.varChar('message', length: 255);
});
}
@override
void down(Schema schema) {
schema.drop('greetings');
}
}
// **************************************************************************
// OrmGenerator
// **************************************************************************
class GreetingQuery extends Query<Greeting, GreetingQueryWhere> {
GreetingQuery({Query? parent, Set<String>? trampoline})
: super(parent: parent) {
trampoline ??= <String>{};
trampoline.add(tableName);
_where = GreetingQueryWhere(this);
}
@override
final GreetingQueryValues values = GreetingQueryValues();
List<String> _selectedFields = [];
GreetingQueryWhere? _where;
@override
Map<String, String> get casts {
return {};
}
@override
String get tableName {
return 'greetings';
}
@override
List<String> get fields {
const _fields = ['id', 'created_at', 'updated_at', 'message'];
return _selectedFields.isEmpty
? _fields
: _fields.where((field) => _selectedFields.contains(field)).toList();
}
GreetingQuery select(List<String> selectedFields) {
_selectedFields = selectedFields;
return this;
}
@override
GreetingQueryWhere? get where {
return _where;
}
@override
GreetingQueryWhere newWhereClause() {
return GreetingQueryWhere(this);
}
Optional<Greeting> parseRow(List row) {
if (row.every((x) => x == null)) {
return Optional.empty();
}
var model = Greeting(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
message: fields.contains('message') ? (row[3] as String?) : null);
return Optional.of(model);
}
@override
Optional<Greeting> deserialize(List row) {
return parseRow(row);
}
}
class GreetingQueryWhere extends QueryWhere {
GreetingQueryWhere(GreetingQuery query)
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'),
updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'),
message = StringSqlExpressionBuilder(query, 'message');
final NumericSqlExpressionBuilder<int> id;
final DateTimeSqlExpressionBuilder createdAt;
final DateTimeSqlExpressionBuilder updatedAt;
final StringSqlExpressionBuilder message;
@override
List<SqlExpressionBuilder> get expressionBuilders {
return [id, createdAt, updatedAt, message];
}
}
class GreetingQueryValues extends MapQueryValues {
@override
Map<String, String> get casts {
return {};
}
String? get id {
return (values['id'] as String?);
}
set id(String? value) => values['id'] = value;
DateTime? get createdAt {
return (values['created_at'] as DateTime?);
}
set createdAt(DateTime? value) => values['created_at'] = value;
DateTime? get updatedAt {
return (values['updated_at'] as DateTime?);
}
set updatedAt(DateTime? value) => values['updated_at'] = value;
String? get message {
return (values['message'] as String?);
}
set message(String? value) => values['message'] = value;
void copyFrom(Greeting model) {
createdAt = model.createdAt;
updatedAt = model.updatedAt;
message = model.message;
}
}
// **************************************************************************
// JsonModelGenerator
// **************************************************************************
@generatedSerializable
class Greeting extends _Greeting {
Greeting({this.id, this.createdAt, this.updatedAt, required this.message});
/// A unique identifier corresponding to this item.
@override
String? id;
/// The time at which this item was created.
@override
DateTime? createdAt;
/// The last time at which this item was updated.
@override
DateTime? updatedAt;
@override
String? message;
Greeting copyWith(
{String? id, DateTime? createdAt, DateTime? updatedAt, String? message}) {
return Greeting(
id: id ?? this.id,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
message: message ?? this.message);
}
@override
bool operator ==(other) {
return other is _Greeting &&
other.id == id &&
other.createdAt == createdAt &&
other.updatedAt == updatedAt &&
other.message == message;
}
@override
int get hashCode {
return hashObjects([id, createdAt, updatedAt, message]);
}
@override
String toString() {
return 'Greeting(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, message=$message)';
}
Map<String, dynamic> toJson() {
return GreetingSerializer.toMap(this);
}
}
// **************************************************************************
// SerializerGenerator
// **************************************************************************
const GreetingSerializer greetingSerializer = GreetingSerializer();
class GreetingEncoder extends Converter<Greeting, Map> {
const GreetingEncoder();
@override
Map convert(Greeting model) => GreetingSerializer.toMap(model);
}
class GreetingDecoder extends Converter<Map, Greeting> {
const GreetingDecoder();
@override
Greeting convert(Map map) => GreetingSerializer.fromMap(map);
}
class GreetingSerializer extends Codec<Greeting, Map> {
const GreetingSerializer();
@override
GreetingEncoder get encoder => const GreetingEncoder();
@override
GreetingDecoder get decoder => const GreetingDecoder();
static Greeting fromMap(Map map) {
if (map['message'] == null) {
throw FormatException("Missing required field 'message' on Greeting.");
}
return Greeting(
id: map['id'] as String?,
createdAt: map['created_at'] != null
? (map['created_at'] is DateTime
? (map['created_at'] as DateTime)
: DateTime.parse(map['created_at'].toString()))
: null,
updatedAt: map['updated_at'] != null
? (map['updated_at'] is DateTime
? (map['updated_at'] as DateTime)
: DateTime.parse(map['updated_at'].toString()))
: null,
message: map['message'] as String?);
}
static Map<String, dynamic> toMap(_Greeting? model) {
if (model == null) {
throw FormatException("Required field [model] cannot be null");
}
return {
'id': model.id,
'created_at': model.createdAt?.toIso8601String(),
'updated_at': model.updatedAt?.toIso8601String(),
'message': model.message
};
}
}
abstract class GreetingFields {
static const List<String> allFields = <String>[
id,
createdAt,
updatedAt,
message
];
static const String id = 'id';
static const String createdAt = 'created_at';
static const String updatedAt = 'updated_at';
static const String message = 'message';
}

View file

@ -1,38 +0,0 @@
import 'package:angel_http_exception/angel_http_exception.dart';
import 'package:logging/logging.dart';
import 'package:io/ansi.dart';
/// Prints the contents of a [LogRecord] with pretty colors.
void prettyLog(LogRecord record) {
var code = chooseLogColor(record.level);
if (record.error == null) print(code.wrap(record.toString()));
if (record.error != null) {
var err = record.error;
if (err is AngelHttpException && err.statusCode != 500) return;
print(code.wrap(record.toString() + '\n'));
print(code.wrap(err.toString()));
if (record.stackTrace != null) {
print(code.wrap(record.stackTrace.toString()));
}
}
}
/// Chooses a color based on the logger [level].
AnsiCode chooseLogColor(Level level) {
if (level == Level.SHOUT)
return backgroundRed;
else if (level == Level.SEVERE)
return red;
else if (level == Level.WARNING)
return yellow;
else if (level == Level.INFO)
return cyan;
else if (level == Level.CONFIG ||
level == Level.FINE ||
level == Level.FINER ||
level == Level.FINEST) return lightGray;
return resetAll;
}

View file

@ -1,7 +1,5 @@
library angel.src.routes.controllers;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
Future configureServer(Angel app) async { Future configureServer(Angel app) async {
/// Controllers will not function unless wired to the application! /// Controllers will not function unless wired to the application!

View file

@ -1,16 +1,15 @@
/// This app's route configuration. import 'package:angel3_framework/angel3_framework.dart';
library angel.src.routes; import 'package:angel3_orm/angel3_orm.dart';
import 'package:angel3_static/angel3_static.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_static/angel_static.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'controllers/controllers.dart' as controllers; import 'controllers/controllers.dart' as controllers;
import '../models/greeting.dart';
/// Put your app routes here! /// Put your app routes here!
/// ///
/// See the wiki for information about routing, requests, and responses: /// See the wiki for information about routing, requests, and responses:
/// * https://github.com/angel-dart/angel/wiki/Basic-Routing /// * https://angel3-docs.dukefirehawk.com/guides/basic-routing
/// * https://github.com/angel-dart/angel/wiki/Requests-&-Responses /// * https://angel3-docs.dukefirehawk.com/guides/requests-and-responses
AngelConfigurer configureServer(FileSystem fileSystem) { AngelConfigurer configureServer(FileSystem fileSystem) {
return (Angel app) async { return (Angel app) async {
// Typically, you want to mount controllers first, after any global middleware. // Typically, you want to mount controllers first, after any global middleware.
@ -19,6 +18,33 @@ AngelConfigurer configureServer(FileSystem fileSystem) {
// Render `views/hello.jl` when a user visits the application root. // Render `views/hello.jl` when a user visits the application root.
app.get('/', (req, res) => res.render('hello')); app.get('/', (req, res) => res.render('hello'));
app.get('/greetings', (req, res) {
var executor = req.container!.make<QueryExecutor>();
var query = GreetingQuery();
return query.get(executor);
});
app.post('/greetings', (req, res) async {
await req.parseBody();
if (!req.bodyAsMap.containsKey('message')) {
throw AngelHttpException.badRequest(message: 'Missing "message".');
} else {
var executor = req.container!.make<QueryExecutor>();
var message = req.bodyAsMap['message'].toString();
var query = GreetingQuery()..values.message = message;
var optional = await query.insert(executor);
return optional.value;
}
});
app.get('/greetings/:message', (req, res) {
var message = req.params['message'] as String;
var executor = req.container!.make<QueryExecutor>();
var query = GreetingQuery()..where!.message.equals(message);
return query.get(executor);
});
// Mount static server at web in development. // Mount static server at web in development.
// The `CachingVirtualDirectory` variant of `VirtualDirectory` also sends `Cache-Control` headers. // The `CachingVirtualDirectory` variant of `VirtualDirectory` also sends `Cache-Control` headers.
// //
@ -27,7 +53,7 @@ AngelConfigurer configureServer(FileSystem fileSystem) {
// //
// Read the following two sources for documentation: // Read the following two sources for documentation:
// * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae // * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae
// * https://github.com/angel-dart/static // * https://pub.dev/packages/angel3_static
if (!app.environment.isProduction) { if (!app.environment.isProduction) {
var vDir = VirtualDirectory( var vDir = VirtualDirectory(
app, app,
@ -43,7 +69,7 @@ AngelConfigurer configureServer(FileSystem fileSystem) {
// Set our application up to handle different errors. // Set our application up to handle different errors.
// //
// Read the following for documentation: // Read the following for documentation:
// * https://github.com/angel-dart/angel/wiki/Error-Handling // * https://angel3-docs.dukefirehawk.com/guides/error-handling
var oldErrorHandler = app.errorHandler; var oldErrorHandler = app.errorHandler;
app.errorHandler = (e, req, res) async { app.errorHandler = (e, req, res) async {

View file

@ -1,8 +1,5 @@
/// Declare services here!
library angel.services;
import 'dart:async'; import 'dart:async';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
/// Configure our application to use *services*. /// Configure our application to use *services*.
/// Services must be wired to the app via `app.use`. /// Services must be wired to the app via `app.use`.

View file

@ -1,20 +1,31 @@
name: angel name: angel
description: An app that's going to be amazing pretty soon. version: 1.0.0
publish_to: none # Ensure we don't accidentally publish our private code! ;) description: An ORM starter application for Angel3 framework
publish_to: none
environment: environment:
sdk: '>=2.0.0-dev <3.0.0' sdk: '>=3.0.0 <4.0.0'
homepage: https://github.com/angel-dart/angel
dependencies: dependencies:
angel_auth: ^2.0.0 # Supports stateless authentication via JWT angel3_auth: ^8.0.0
angel_configuration: ^2.0.0 # Loads application configuration, along with support for .env files. angel3_configuration: ^8.0.0
angel_framework: ^2.0.0 # The core server library. angel3_framework: ^8.0.0
angel_jael: ^2.0.0 # Server-side templating engine angel3_jael: ^8.0.0
angel_production: ^1.0.0 # Production application runner. angel3_migration: ^8.0.0
angel_static: ^2.0.0 # Static file server angel3_orm: ^8.0.0
angel_validate: ^2.0.0 # Allows for validation of input data angel3_orm_mysql: ^8.0.0
angel3_serialize: ^8.0.0
angel3_production: ^8.0.0
angel3_static: ^8.0.0
angel3_validate: ^8.0.0
belatuk_pretty_logging: ^6.0.0
optional: ^6.0.0
logging: ^1.0.0
dev_dependencies: dev_dependencies:
angel_hot: ^2.0.0 # Hot-reloading support. :) angel3_hot: ^8.0.0
angel_test: ^2.0.0 # Utilities for testing Angel servers. angel3_migration_runner: ^8.0.0
io: ^0.3.2 # For pretty printing. angel3_orm_generator: ^8.0.0
pedantic: ^1.0.0 # Enforces Dart style conventions. angel3_serialize_generator: ^8.0.0
test: ^1.0.0 # For unit testing. angel3_test: ^8.0.0
build_runner: ^2.0.3
io: ^1.0.0
test: ^1.21.0
lints: ^2.1.1

View file

@ -1,6 +1,6 @@
import 'package:angel/angel.dart'; import 'package:angel/angel.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel_test/angel_test.dart'; import 'package:angel3_test/angel3_test.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
// Angel also includes facilities to make testing easier. // Angel also includes facilities to make testing easier.
@ -19,8 +19,8 @@ import 'package:test/test.dart';
// here: // here:
// https://github.com/dart-lang/test // https://github.com/dart-lang/test
main() async { void main() async {
TestClient client; late TestClient client;
setUp(() async { setUp(() async {
var app = Angel(); var app = Angel();
@ -35,7 +35,7 @@ main() async {
test('index returns 200', () async { test('index returns 200', () async {
// Request a resource at the given path. // Request a resource at the given path.
var response = await client.get('/'); var response = await client.get(Uri.parse('/'));
// Expect a 200 response. // Expect a 200 response.
expect(response, hasStatus(200)); expect(response, hasStatus(200));

View file

@ -3,8 +3,8 @@
<head> <head>
<title>{{ title ?? 'Angel' }}</title> <title>{{ title ?? 'Angel' }}</title>
<link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css"> <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Lato:100" >
<link rel="stylesheet" href="/css/site.css"> <link rel="stylesheet" type="text/css" href="/css/site.css">
<link rel="icon" href="/images/favicon.png"> <link rel="icon" href="/images/favicon.png">
</head> </head>
<body> <body>