Updated Generated Container
This commit is contained in:
parent
05cbd71248
commit
08ba4f0609
31 changed files with 24278 additions and 6792 deletions
45
README.md
45
README.md
|
@ -8,27 +8,38 @@
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/LICENSE)
|
||||||
[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos)
|
[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg?style=flat-square)](https://github.com/invertase/melos)
|
||||||
|
|
||||||
**A polished, production-ready backend framework in Dart with NNBD support.**
|
**A polished, production-ready backend framework in Dart.**
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
Angel3 is a fork of archived Angel framework to support Dart SDK 2.12.x or later. It is a full-stack Web framework in Dart that aims to streamline development by providing many common features out-of-the-box in a consistent manner. One of the main goal is to enable developers to build both frontend and backend in the same language, Dart. Angel3 framework is designed as a collection of plugins that enable developers to pick and choose the parts needed for their projects. A series of starter templates are also provided for quick start and trial run with Angel3 framework. Visit our [website](<https://angel3-framework.web.app/>) to learn more.
|
Angel3 started life as a fork of the archived `Angel framework` to support null-safety in Dart SDK 2.12.x and beyond. It is a full-stack Web framework in Dart that aims to streamline development by providing many common features out-of-the-box in a consistent manner. One of the main goal is to enable developers to build both frontend and backend in the same language, Dart. Angel3 framework is designed as a collection of plugins that enable developers to pick and choose the parts needed for their projects. A series of starter templates are also provided for quick start and trial run with Angel3 framework. Visit our [website](<https://angel3-framework.web.app/>) for more details.
|
||||||
|
|
||||||
The available features in Angel3 includes:
|
The available features in Angel3 includes:
|
||||||
|
|
||||||
* Static File Handling
|
* Basic and OAuth2 Authentication
|
||||||
* Basic Authentication
|
* ORM for PostgreSQL and MySQL
|
||||||
* PostgreSQL ORM
|
* MongoDB
|
||||||
* GraphQL
|
* GraphQL
|
||||||
* And much more...
|
* Proxy and Cache
|
||||||
|
* Static File Handling
|
||||||
|
* Server Side Rendering
|
||||||
|
* Websocket
|
||||||
|
|
||||||
See all the available [`packages`](https://angel3-docs.dukefirehawk.com/packages) for more information.
|
See all the available [`packages`](https://angel3-docs.dukefirehawk.com/packages) for more information.
|
||||||
|
|
||||||
## Important Notes
|
## Important Notes
|
||||||
|
|
||||||
The core Angel Framework migration to Angel3 Framework has completed and published under `angel3_` prefix on pub.dev. The migrated packages have passed all the test cases. The development work will now move onto the next phase which is to refactor and to improve on the features for better development and deployment experience.
|
The development work are currently focused on:
|
||||||
|
|
||||||
|
* Keeping the packages with `angel3_` prefix in sync with Dart SDK releases
|
||||||
|
* Remove and replace deprecated classes and methods while keeping backward compatible
|
||||||
|
* Refactor the code to use new language features
|
||||||
|
* Fix and resolve reported issues
|
||||||
|
* Performance tunning
|
||||||
|
* Improve on existing features, unit test, user guide and examples
|
||||||
|
* Add new features
|
||||||
|
|
||||||
The status of the code base is as follows:
|
The status of the code base is as follows:
|
||||||
|
|
||||||
|
@ -44,25 +55,19 @@ For more details, checkout [Project Status](https://github.com/dukefirehawk/ange
|
||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
### Release 7.0.0
|
### Release 8.0.0 (Upcoming)
|
||||||
|
|
||||||
|
* Updated all `angel3_` packages to 8.0.0
|
||||||
|
* Updated all `angel3_` packages to require dart >= 3.0.x
|
||||||
|
|
||||||
|
### Release 7.0.0 (Current)
|
||||||
|
|
||||||
|
* Updated all `angel3_` packages to 7.0.0
|
||||||
* Updated all `angel3_` packages to require dart >= 2.17.x
|
* Updated all `angel3_` packages to require dart >= 2.17.x
|
||||||
* Updated dependencies to the latest libraries
|
* Updated dependencies to the latest libraries
|
||||||
* Fixed ORM issues
|
* Fixed ORM issues
|
||||||
* Fixed `dart analyze .` warnings
|
* Fixed `dart analyze .` warnings
|
||||||
|
|
||||||
### Release 6.0.0
|
|
||||||
|
|
||||||
* Updated all `angel3_` packages to 6.0.0
|
|
||||||
* Updated all `angel3_` packages to require dart >= 2.16.x
|
|
||||||
* Updated ORM to support MariaDB 10.2.x (stable) and MySQL 8.x (beta)
|
|
||||||
* Updated code generator to use `analyzer` 3.x.x
|
|
||||||
* Updated exception handling
|
|
||||||
* Added default logger to generate standardised logging messages
|
|
||||||
* Added `melos` support
|
|
||||||
* Removed deprecated API
|
|
||||||
* [**Breaking**] `error` for `AngelHttpException` is no longer mandatory
|
|
||||||
|
|
||||||
## Installation and Setup
|
## Installation and Setup
|
||||||
|
|
||||||
### Create a new project by cloning from boilerplate templates
|
### Create a new project by cloning from boilerplate templates
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
import 'package:angel3_container/angel3_container.dart';
|
|
||||||
import 'package:angel3_container_generator/angel3_container_generator.dart';
|
|
||||||
import 'package:angel3_framework/angel3_framework.dart';
|
|
||||||
import 'package:angel3_framework/http.dart';
|
|
||||||
|
|
||||||
import 'example.reflectable.dart';
|
|
||||||
|
|
||||||
@Expose('/controller')
|
|
||||||
class MyController extends Controller {
|
|
||||||
@Expose('/')
|
|
||||||
a() => "Hello, world!";
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
initializeReflectable();
|
|
||||||
|
|
||||||
var reflector = const GeneratedReflector();
|
|
||||||
Container container = Container(reflector);
|
|
||||||
|
|
||||||
container.registerSingleton<MyController>(MyController());
|
|
||||||
|
|
||||||
var app = Angel(reflector: reflector);
|
|
||||||
var http = AngelHttp(app);
|
|
||||||
|
|
||||||
//await app.mountController<MyController>();
|
|
||||||
|
|
||||||
var server = await http.startServer('localhost', 3000);
|
|
||||||
print("Angel server listening at ${http.uri}");
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
46
experiment/container/example2/bin/example1.dart
Normal file
46
experiment/container/example2/bin/example1.dart
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import 'package:angel3_container/mirrors.dart';
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
import 'package:angel3_framework/http.dart';
|
||||||
|
|
||||||
|
@Expose('/controller', method: 'GET')
|
||||||
|
class MyController extends Controller {
|
||||||
|
@Expose('/', method: 'GET')
|
||||||
|
Future<String> route1(RequestContext req, ResponseContext res) async {
|
||||||
|
return "My route";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose('/sales', middleware: [process1])
|
||||||
|
class SalesController extends Controller {
|
||||||
|
@Expose('/', middleware: [process2])
|
||||||
|
Future<String> route1(RequestContext req, ResponseContext res) async {
|
||||||
|
return "Sales route";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process1(RequestContext req, ResponseContext res) {
|
||||||
|
res.write('Hello, ');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process2(RequestContext req, ResponseContext res) {
|
||||||
|
res.write('From Sales, ');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
// Using Mirror Reflector
|
||||||
|
var app = Angel(reflector: MirrorsReflector());
|
||||||
|
|
||||||
|
// My Controller
|
||||||
|
app.container.registerSingleton<MyController>(MyController());
|
||||||
|
await app.mountController<MyController>();
|
||||||
|
|
||||||
|
// Sales Controller
|
||||||
|
app.container.registerSingleton<SalesController>(SalesController());
|
||||||
|
await app.mountController<SalesController>();
|
||||||
|
|
||||||
|
var http = AngelHttp(app);
|
||||||
|
var server = await http.startServer('localhost', 3000);
|
||||||
|
print("Angel server listening at ${http.uri}");
|
||||||
|
}
|
63
experiment/container/example2/bin/example2.dart
Normal file
63
experiment/container/example2/bin/example2.dart
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import 'package:angel3_container/mirrors.dart';
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
import 'package:angel3_framework/http.dart';
|
||||||
|
|
||||||
|
class Todo extends Model {
|
||||||
|
String? text;
|
||||||
|
String? over;
|
||||||
|
|
||||||
|
Todo({this.text, this.over});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'text': text,
|
||||||
|
'over': over,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose('/todo', method: 'GET')
|
||||||
|
class TodoController extends Controller {
|
||||||
|
@Expose('/')
|
||||||
|
Todo todo(Todo singleton) => singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose('/controller', method: 'GET')
|
||||||
|
class MyController extends Controller {
|
||||||
|
@Expose('/', method: 'GET')
|
||||||
|
Future<String> route1(RequestContext req, ResponseContext res) async {
|
||||||
|
return "My route";
|
||||||
|
}
|
||||||
|
|
||||||
|
//Todo todo(Todo singleton) => singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose('/sales', middleware: [process1])
|
||||||
|
class SalesController extends Controller {
|
||||||
|
@Expose('/', middleware: [process2])
|
||||||
|
Future<String> route1(RequestContext req, ResponseContext res) async {
|
||||||
|
return "Sales route";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process1(RequestContext req, ResponseContext res) {
|
||||||
|
res.write('Hello, ');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process2(RequestContext req, ResponseContext res) {
|
||||||
|
res.write('From Sales, ');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
// Using Mirror Reflector
|
||||||
|
var app = Angel(reflector: MirrorsReflector());
|
||||||
|
|
||||||
|
await app.configure(MyController().configureServer);
|
||||||
|
await app.configure(SalesController().configureServer);
|
||||||
|
|
||||||
|
var http = AngelHttp(app);
|
||||||
|
var server = await http.startServer('localhost', 3000);
|
||||||
|
print("Angel server listening at ${http.uri}");
|
||||||
|
}
|
70
experiment/container/example2/bin/example3_controller.dart
Normal file
70
experiment/container/example2/bin/example3_controller.dart
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import 'package:angel3_container_generator/angel3_container_generator.dart';
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
import 'package:angel3_framework/http.dart';
|
||||||
|
|
||||||
|
import 'example3_controller.reflectable.dart';
|
||||||
|
|
||||||
|
@contained
|
||||||
|
@Expose('/controller', method: 'GET')
|
||||||
|
class MyController extends Controller {
|
||||||
|
@Expose('/')
|
||||||
|
Order order(Order singleton) => singleton;
|
||||||
|
|
||||||
|
//Todo todo(Todo singleton) => singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Todo extends Model {
|
||||||
|
String? text;
|
||||||
|
String? over;
|
||||||
|
|
||||||
|
Todo({this.text, this.over});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'text': text,
|
||||||
|
'over': over,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FoodItem {
|
||||||
|
final String name;
|
||||||
|
final num price;
|
||||||
|
|
||||||
|
FoodItem(this.name, this.price);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Order {
|
||||||
|
FoodItem item;
|
||||||
|
|
||||||
|
String? get name => item.name;
|
||||||
|
|
||||||
|
Order(this.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
//var reflector = const GeneratedReflector();
|
||||||
|
//Container container = Container(reflector);
|
||||||
|
//container.registerSingleton<SalesController>(SalesController());
|
||||||
|
|
||||||
|
// Useing GeneratedReflector
|
||||||
|
initializeReflectable();
|
||||||
|
var app = Angel(reflector: GeneratedReflector());
|
||||||
|
|
||||||
|
// Using MirrorReflector
|
||||||
|
//var app = Angel(reflector: MirrorsReflector());
|
||||||
|
//await app.configure(MyController().configureServer);
|
||||||
|
|
||||||
|
// My Controller
|
||||||
|
//app.container.registerSingleton<MyController>(MyController());
|
||||||
|
//await app.mountController<MyController>();
|
||||||
|
await app.configure(MyController().configureServer);
|
||||||
|
|
||||||
|
// Sales Controller
|
||||||
|
//app.container.registerSingleton<SalesController>(SalesController());
|
||||||
|
//await app.mountController<SalesController>();
|
||||||
|
|
||||||
|
var http = AngelHttp(app);
|
||||||
|
var server = await http.startServer('localhost', 3000);
|
||||||
|
print("Angel server listening at ${http.uri}");
|
||||||
|
}
|
10762
experiment/container/example2/bin/example3_controller.reflectable.dart
Normal file
10762
experiment/container/example2/bin/example3_controller.reflectable.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -12,9 +12,9 @@ void main() {
|
||||||
print('Reflection executed in ${stopwatch.elapsed.inMilliseconds} ms');
|
print('Reflection executed in ${stopwatch.elapsed.inMilliseconds} ms');
|
||||||
stopwatch.stop();
|
stopwatch.stop();
|
||||||
|
|
||||||
printAnnotationValue(String);
|
//printAnnotationValue(String);
|
||||||
printAnnotationValue(Shape);
|
//printAnnotationValue(Shape);
|
||||||
printAnnotationValue(Square);
|
//printAnnotationValue(Square);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Shape {
|
class Shape {
|
||||||
|
@ -27,7 +27,7 @@ class Square {
|
||||||
print("Hii Welcome to flutter agency");
|
print("Hii Welcome to flutter agency");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
void printAnnotationValue(final Type clazz) {
|
void printAnnotationValue(final Type clazz) {
|
||||||
final DeclarationMirror clazzDeclaration = reflectClass(clazz);
|
final DeclarationMirror clazzDeclaration = reflectClass(clazz);
|
||||||
final ClassMirror someAnnotationMirror = reflectClass(Person);
|
final ClassMirror someAnnotationMirror = reflectClass(Person);
|
||||||
|
@ -41,3 +41,4 @@ void printAnnotationValue(final Type clazz) {
|
||||||
(annotationInstsanceMirror.first.reflectee as Person);
|
(annotationInstsanceMirror.first.reflectee as Person);
|
||||||
print(someAnnotationInstance.firstName);
|
print(someAnnotationInstance.firstName);
|
||||||
}
|
}
|
||||||
|
*/
|
9
experiment/container/example2/build.yaml
Normal file
9
experiment/container/example2/build.yaml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
builders:
|
||||||
|
reflectable:
|
||||||
|
generate_for:
|
||||||
|
#- lib/**_controller.dart
|
||||||
|
- bin/**_controller.dart
|
||||||
|
options:
|
||||||
|
formatted: true
|
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:angel3_container_generator/angel3_container_generator.dart';
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
|
||||||
|
@Expose('/hr')
|
||||||
|
class HrController extends Controller {
|
||||||
|
@Expose('/')
|
||||||
|
landingPage() => "Hello, world!";
|
||||||
|
}
|
||||||
|
|
||||||
|
@contained
|
||||||
|
class SalesController extends Controller {
|
||||||
|
landingPage() => "Hello, world!";
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {}
|
|
@ -30,18 +30,20 @@ dependencies:
|
||||||
tuple: ^2.0.0
|
tuple: ^2.0.0
|
||||||
uuid: ^3.0.1
|
uuid: ^3.0.1
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
|
reflectable: ^4.0.2
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
build_runner: ^2.1.2
|
||||||
http: ^0.13.1
|
http: ^0.13.1
|
||||||
io: ^1.0.0
|
io: ^1.0.0
|
||||||
test: ^1.21.0
|
test: ^1.21.0
|
||||||
lints: ^2.0.0
|
lints: ^2.0.0
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
angel3_container:
|
angel3_container:
|
||||||
path: ../../../packages/container/angel_container
|
path: ../../../packages/container/angel_container
|
||||||
angel3_container_generator:
|
angel3_container_generator:
|
||||||
path: ../../../packages/container/angel_container_generator
|
path: ../../../packages/container/angel_container_generator
|
||||||
# angel3_http_exception:
|
angel3_framework:
|
||||||
# path: ../http_exception
|
path: ../../../packages/framework
|
||||||
# angel3_model:
|
# angel3_model:
|
||||||
# path: ../model
|
# path: ../model
|
||||||
# angel3_route:
|
# angel3_route:
|
||||||
|
|
14
experiment/container/example2/web/example.dart
Normal file
14
experiment/container/example2/web/example.dart
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import 'package:angel3_container_generator/angel3_container_generator.dart';
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
|
||||||
|
@Expose('/hr')
|
||||||
|
class HrController extends Controller {
|
||||||
|
@Expose('/')
|
||||||
|
landingPage() => "Hello, world!";
|
||||||
|
}
|
||||||
|
|
||||||
|
@contained
|
||||||
|
class SalesController extends Controller {
|
||||||
|
|
||||||
|
landingPage() => "Hello, world!";
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 7.1.1
|
||||||
|
|
||||||
|
* Moved `defaultErrorMessage` to `ContainerConst` class to resolve reflectatable issue.
|
||||||
|
|
||||||
## 7.1.0
|
## 7.1.0
|
||||||
|
|
||||||
* Require Dart >= 2.18
|
* Require Dart >= 2.18
|
||||||
|
|
|
@ -6,3 +6,4 @@ export 'src/static/static.dart';
|
||||||
export 'src/exception.dart';
|
export 'src/exception.dart';
|
||||||
export 'src/reflector.dart';
|
export 'src/reflector.dart';
|
||||||
export 'src/throwing.dart';
|
export 'src/throwing.dart';
|
||||||
|
export 'src/container_const.dart';
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
class ContainerConst {
|
||||||
|
static const String defaultErrorMessage =
|
||||||
|
'You attempted to perform a reflective action, but you are using `ThrowingReflector`, '
|
||||||
|
'a class which disables reflection. Consider using the `MirrorsReflector` '
|
||||||
|
'class if you need reflection.';
|
||||||
|
|
||||||
|
ContainerConst._();
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:angel3_container/src/container_const.dart';
|
||||||
|
|
||||||
import 'empty/empty.dart';
|
import 'empty/empty.dart';
|
||||||
import 'reflector.dart';
|
import 'reflector.dart';
|
||||||
|
|
||||||
|
@ -9,12 +11,15 @@ class ThrowingReflector extends Reflector {
|
||||||
/// The error message to give the end user when an [UnsupportedError] is thrown.
|
/// The error message to give the end user when an [UnsupportedError] is thrown.
|
||||||
final String errorMessage;
|
final String errorMessage;
|
||||||
|
|
||||||
|
/*
|
||||||
static const String defaultErrorMessage =
|
static const String defaultErrorMessage =
|
||||||
'You attempted to perform a reflective action, but you are using `ThrowingReflector`, '
|
'You attempted to perform a reflective action, but you are using `ThrowingReflector`, '
|
||||||
'a class which disables reflection. Consider using the `MirrorsReflector` '
|
'a class which disables reflection. Consider using the `MirrorsReflector` '
|
||||||
'class if you need reflection.';
|
'class if you need reflection.';
|
||||||
|
*/
|
||||||
|
|
||||||
const ThrowingReflector({this.errorMessage = defaultErrorMessage});
|
const ThrowingReflector(
|
||||||
|
{this.errorMessage = ContainerConst.defaultErrorMessage});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);
|
String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel3_container
|
name: angel3_container
|
||||||
version: 7.1.0
|
version: 7.1.1
|
||||||
description: Angel3 hierarchical DI container, and pluggable backends for reflection.
|
description: Angel3 hierarchical DI container, and pluggable backends for reflection.
|
||||||
homepage: https://angel3-framework.web.app/
|
homepage: https://angel3-framework.web.app/
|
||||||
repository: https://github.com/dukefirehawk/angel/tree/master/packages/container/angel_container
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/container/angel_container
|
||||||
|
|
0
packages/container/angel_container_generator/=
Normal file
0
packages/container/angel_container_generator/=
Normal file
|
@ -5,4 +5,27 @@
|
||||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/container/angel3_container_generator/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/container/angel3_container_generator/LICENSE)
|
||||||
|
|
||||||
A better IoC container generator for Angel3, ultimately allowing Angel3 to be used without `dart:mirrors`.
|
An alternative container for Angel3 that uses `reflectable` instead of `dart:mirrors` for reflection.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* Annotable the class with `@contained`.
|
||||||
|
* Run `dart run build_runner build <Your class directory>`
|
||||||
|
* Alternatively create a `build.xml` file with the following content
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
targets:
|
||||||
|
$default:
|
||||||
|
builders:
|
||||||
|
reflectable:
|
||||||
|
generate_for:
|
||||||
|
- bin/**_controller.dart
|
||||||
|
options:
|
||||||
|
formatted: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known limitation
|
||||||
|
|
||||||
|
* Reflection on functions/closures
|
||||||
|
* Reflection on private declarations
|
||||||
|
* Reflection on generic type
|
||||||
|
|
|
@ -5,8 +5,7 @@ import 'package:angel3_container_generator/angel3_container_generator.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
// Create a container instance.
|
// Create a container instance.
|
||||||
var reflector = const GeneratedReflector();
|
Container container = Container(GeneratedReflector());
|
||||||
Container container = Container(reflector);
|
|
||||||
|
|
||||||
// Register a singleton.
|
// Register a singleton.
|
||||||
container.registerSingleton<Engine>(Engine(40));
|
container.registerSingleton<Engine>(Engine(40));
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,11 +11,11 @@ class ContainedReflectable extends Reflectable {
|
||||||
topLevelInvokeCapability,
|
topLevelInvokeCapability,
|
||||||
typeAnnotationQuantifyCapability,
|
typeAnnotationQuantifyCapability,
|
||||||
superclassQuantifyCapability,
|
superclassQuantifyCapability,
|
||||||
instanceInvokeCapability,
|
|
||||||
libraryCapability,
|
libraryCapability,
|
||||||
invokingCapability,
|
invokingCapability,
|
||||||
newInstanceCapability,
|
metadataCapability,
|
||||||
reflectedTypeCapability,
|
reflectedTypeCapability,
|
||||||
|
typeCapability,
|
||||||
typingCapability);
|
typingCapability);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ void main() {
|
||||||
expect(album.title, 'flowers by stevie wonder');
|
expect(album.title, 'flowers by stevie wonder');
|
||||||
});
|
});
|
||||||
|
|
||||||
testReflector(reflector);
|
// Skip as pkg:reflectable cannot reflect on closures at all (yet)
|
||||||
|
//testReflector(reflector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@contained
|
@contained
|
||||||
|
@ -49,7 +50,6 @@ void testReflector(Reflector reflector) {
|
||||||
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
|
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
group('reflectFunction', () {
|
group('reflectFunction', () {
|
||||||
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
|
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
|
||||||
|
|
||||||
|
@ -73,8 +73,7 @@ void testReflector(Reflector reflector) {
|
||||||
expect(p?.annotations, isEmpty);
|
expect(p?.annotations, isEmpty);
|
||||||
expect(p?.type, reflector.reflectType(int));
|
expect(p?.type, reflector.reflectType(int));
|
||||||
});
|
});
|
||||||
}, skip: 'pkg:reflectable cannot reflect on closures at all (yet)');
|
}, skip: 'pkg:reflectable cannot reflect on closures at all (yet)');
|
||||||
*/
|
|
||||||
|
|
||||||
test('make on singleton type returns singleton', () {
|
test('make on singleton type returns singleton', () {
|
||||||
expect(container.make(Pokemon), blaziken);
|
expect(container.make(Pokemon), blaziken);
|
||||||
|
@ -111,9 +110,9 @@ void testReflector(Reflector reflector) {
|
||||||
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
|
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
() => kantoPokemonType
|
kantoPokemonType
|
||||||
.isAssignableTo(container.reflector.reflectType(String)),
|
.isAssignableTo(container.reflector.reflectType(String)),
|
||||||
throwsUnsupportedError);
|
false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,10 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 7.0.4
|
||||||
|
|
||||||
|
* Updated `Expose` fields to non-nullable
|
||||||
|
* Updated `Controller` to use non-nullable field
|
||||||
|
|
||||||
## 7.0.3
|
## 7.0.3
|
||||||
|
|
||||||
* Fixed issue #83. Allow Http request to return null headers instead of throwing an exception.
|
* Fixed issue #83. Allow Http request to return null headers instead of throwing an exception.
|
||||||
|
|
|
@ -64,13 +64,13 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
var routable = Routable();
|
var routable = Routable();
|
||||||
var m = router.mount(exposeDecl.path!, routable);
|
_mountPoint = router.mount(exposeDecl.path, routable);
|
||||||
_mountPoint = m;
|
//_mountPoint = m;
|
||||||
var typeMirror = reflector.reflectType(runtimeType);
|
var typeMirror = reflector.reflectType(runtimeType);
|
||||||
|
|
||||||
// Pre-reflect methods
|
// Pre-reflect methods
|
||||||
var instanceMirror = reflector.reflectInstance(this);
|
var instanceMirror = reflector.reflectInstance(this);
|
||||||
final handlers = <RequestHandler>[...exposeDecl.middleware!, ...middleware];
|
final handlers = <RequestHandler>[...exposeDecl.middleware, ...middleware];
|
||||||
final routeBuilder =
|
final routeBuilder =
|
||||||
_routeBuilder(reflector, instanceMirror, routable, handlers);
|
_routeBuilder(reflector, instanceMirror, routable, handlers);
|
||||||
await configureRoutes(routable);
|
await configureRoutes(routable);
|
||||||
|
@ -107,7 +107,7 @@ class Controller {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, create an @Expose.
|
// Otherwise, create an @Expose.
|
||||||
exposeDecl = Expose(null);
|
exposeDecl = Expose('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ class Controller {
|
||||||
instanceMirror!.getField(methodName).reflectee as Function?;
|
instanceMirror!.getField(methodName).reflectee as Function?;
|
||||||
var middleware = <RequestHandler>[
|
var middleware = <RequestHandler>[
|
||||||
...handlers,
|
...handlers,
|
||||||
...exposeDecl.middleware!
|
...exposeDecl.middleware
|
||||||
];
|
];
|
||||||
var name =
|
var name =
|
||||||
exposeDecl.as?.isNotEmpty == true ? exposeDecl.as : methodName;
|
exposeDecl.as?.isNotEmpty == true ? exposeDecl.as : methodName;
|
||||||
|
@ -127,7 +127,7 @@ class Controller {
|
||||||
method.parameters[1].type.reflectedType == ResponseContext) {
|
method.parameters[1].type.reflectedType == ResponseContext) {
|
||||||
// Create a regular route
|
// Create a regular route
|
||||||
routeMappings[name ?? ''] = routable
|
routeMappings[name ?? ''] = routable
|
||||||
.addRoute(exposeDecl.method, exposeDecl.path ?? '',
|
.addRoute(exposeDecl.method, exposeDecl.path,
|
||||||
(RequestContext req, ResponseContext res) {
|
(RequestContext req, ResponseContext res) {
|
||||||
var result = reflectedMethod!(req, res);
|
var result = reflectedMethod!(req, res);
|
||||||
return result is RequestHandler ? result(req, res) : result;
|
return result is RequestHandler ? result(req, res) : result;
|
||||||
|
@ -144,7 +144,7 @@ class Controller {
|
||||||
// If there is no path, reverse-engineer one.
|
// If there is no path, reverse-engineer one.
|
||||||
var path = exposeDecl.path;
|
var path = exposeDecl.path;
|
||||||
var httpMethod = exposeDecl.method;
|
var httpMethod = exposeDecl.method;
|
||||||
if (path == null) {
|
if (path == '') {
|
||||||
// Try to build a route path by finding all potential
|
// Try to build a route path by finding all potential
|
||||||
// path segments, and then joining them.
|
// path segments, and then joining them.
|
||||||
var parts = <String>[];
|
var parts = <String>[];
|
||||||
|
|
|
@ -45,17 +45,17 @@ const NoExpose noExpose = NoExpose();
|
||||||
/// ```
|
/// ```
|
||||||
class Expose {
|
class Expose {
|
||||||
final String method;
|
final String method;
|
||||||
final String? path;
|
final String path;
|
||||||
final Iterable<RequestHandler>? middleware;
|
final Iterable<RequestHandler> middleware;
|
||||||
final String? as;
|
final String? as;
|
||||||
final List<String> allowNull;
|
final List<String> allowNull;
|
||||||
|
|
||||||
static const Expose get = Expose(null, method: 'GET'),
|
static const Expose get = Expose('', method: 'GET'),
|
||||||
post = Expose(null, method: 'POST'),
|
post = Expose('', method: 'POST'),
|
||||||
patch = Expose(null, method: 'PATCH'),
|
patch = Expose('', method: 'PATCH'),
|
||||||
put = Expose(null, method: 'PUT'),
|
put = Expose('', method: 'PUT'),
|
||||||
delete = Expose(null, method: 'DELETE'),
|
delete = Expose('', method: 'DELETE'),
|
||||||
head = Expose(null, method: 'HEAD');
|
head = Expose('', method: 'HEAD');
|
||||||
|
|
||||||
const Expose(this.path,
|
const Expose(this.path,
|
||||||
{this.method = 'GET',
|
{this.method = 'GET',
|
||||||
|
@ -64,8 +64,8 @@ class Expose {
|
||||||
this.allowNull = const []});
|
this.allowNull = const []});
|
||||||
|
|
||||||
const Expose.method(this.method,
|
const Expose.method(this.method,
|
||||||
{this.middleware, this.as, this.allowNull = const []})
|
{this.middleware = const [], this.as, this.allowNull = const []})
|
||||||
: path = null;
|
: path = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to apply special dependency injections or functionality to a function parameter.
|
/// Used to apply special dependency injections or functionality to a function parameter.
|
||||||
|
@ -89,7 +89,7 @@ class Parameter {
|
||||||
final dynamic defaultValue;
|
final dynamic defaultValue;
|
||||||
|
|
||||||
/// If `true` (default), then an error will be thrown if this parameter is not present.
|
/// If `true` (default), then an error will be thrown if this parameter is not present.
|
||||||
final bool? required;
|
final bool required;
|
||||||
|
|
||||||
const Parameter(
|
const Parameter(
|
||||||
{this.cookie,
|
{this.cookie,
|
||||||
|
@ -98,7 +98,7 @@ class Parameter {
|
||||||
this.session,
|
this.session,
|
||||||
this.match,
|
this.match,
|
||||||
this.defaultValue,
|
this.defaultValue,
|
||||||
this.required});
|
this.required = true});
|
||||||
|
|
||||||
/// Returns an error that can be thrown when the parameter is not present.
|
/// Returns an error that can be thrown when the parameter is not present.
|
||||||
Object? get error {
|
Object? get error {
|
||||||
|
|
|
@ -388,7 +388,7 @@ class Angel extends Routable {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const String _reflectionErrorMessage =
|
static const String _reflectionErrorMessage =
|
||||||
'${ThrowingReflector.defaultErrorMessage} $_reflectionInfo';
|
'${ContainerConst.defaultErrorMessage} $_reflectionInfo';
|
||||||
|
|
||||||
static const String _reflectionInfo =
|
static const String _reflectionInfo =
|
||||||
'Features like controllers, constructor dependency injection, and `ioc` require reflection, '
|
'Features like controllers, constructor dependency injection, and `ioc` require reflection, '
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
name: angel3_framework
|
name: angel3_framework
|
||||||
version: 7.0.3
|
version: 7.0.4
|
||||||
description: A high-powered HTTP server extensible framework with dependency injection, routing and much more.
|
description: A high-powered HTTP server extensible framework with dependency injection, routing and much more.
|
||||||
homepage: https://angel3-framework.web.app/
|
homepage: https://angel3-framework.web.app/
|
||||||
repository: https://github.com/dukefirehawk/angel/tree/master/packages/framework
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/framework
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.17.0 <3.0.0'
|
sdk: '>=2.18.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
angel3_container: ^7.0.0
|
angel3_container: ^7.0.0
|
||||||
angel3_http_exception: ^7.0.0
|
angel3_http_exception: ^7.0.0
|
||||||
|
@ -35,9 +35,9 @@ dev_dependencies:
|
||||||
io: ^1.0.0
|
io: ^1.0.0
|
||||||
test: ^1.21.0
|
test: ^1.21.0
|
||||||
lints: ^2.0.0
|
lints: ^2.0.0
|
||||||
# dependency_overrides:
|
dependency_overrides:
|
||||||
# angel3_container:
|
angel3_container:
|
||||||
# path: ../container/angel_container
|
path: ../container/angel_container
|
||||||
# angel3_http_exception:
|
# angel3_http_exception:
|
||||||
# path: ../http_exception
|
# path: ../http_exception
|
||||||
# angel3_model:
|
# angel3_model:
|
||||||
|
|
17
packages/orm/angel_orm_test/lib/src/models/quotation.dart
Normal file
17
packages/orm/angel_orm_test/lib/src/models/quotation.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:angel3_migration/angel3_migration.dart';
|
||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:angel3_serialize/angel3_serialize.dart';
|
||||||
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
|
part 'quotation.g.dart';
|
||||||
|
|
||||||
|
@serializable
|
||||||
|
@orm
|
||||||
|
abstract class _Quotation {
|
||||||
|
@PrimaryKey(columnType: ColumnType.varChar)
|
||||||
|
String? get id;
|
||||||
|
|
||||||
|
String? get name;
|
||||||
|
|
||||||
|
double? get price;
|
||||||
|
}
|
282
packages/orm/angel_orm_test/lib/src/models/quotation.g.dart
Normal file
282
packages/orm/angel_orm_test/lib/src/models/quotation.g.dart
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'quotation.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// MigrationGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class QuotationMigration extends Migration {
|
||||||
|
@override
|
||||||
|
void up(Schema schema) {
|
||||||
|
schema.create(
|
||||||
|
'quotations',
|
||||||
|
(table) {
|
||||||
|
table
|
||||||
|
.varChar(
|
||||||
|
'id',
|
||||||
|
length: 255,
|
||||||
|
)
|
||||||
|
.primaryKey();
|
||||||
|
table.varChar(
|
||||||
|
'name',
|
||||||
|
length: 255,
|
||||||
|
);
|
||||||
|
table.double('price');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void down(Schema schema) {
|
||||||
|
schema.drop('quotations');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// OrmGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class QuotationQuery extends Query<Quotation, QuotationQueryWhere> {
|
||||||
|
QuotationQuery({
|
||||||
|
Query? parent,
|
||||||
|
Set<String>? trampoline,
|
||||||
|
}) : super(parent: parent) {
|
||||||
|
trampoline ??= <String>{};
|
||||||
|
trampoline.add(tableName);
|
||||||
|
_where = QuotationQueryWhere(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final QuotationQueryValues values = QuotationQueryValues();
|
||||||
|
|
||||||
|
List<String> _selectedFields = [];
|
||||||
|
|
||||||
|
QuotationQueryWhere? _where;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, String> get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tableName {
|
||||||
|
return 'quotations';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> get fields {
|
||||||
|
const _fields = [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'price',
|
||||||
|
];
|
||||||
|
return _selectedFields.isEmpty
|
||||||
|
? _fields
|
||||||
|
: _fields.where((field) => _selectedFields.contains(field)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QuotationQuery select(List<String> selectedFields) {
|
||||||
|
_selectedFields = selectedFields;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
QuotationQueryWhere? get where {
|
||||||
|
return _where;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
QuotationQueryWhere newWhereClause() {
|
||||||
|
return QuotationQueryWhere(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Quotation> parseRow(List row) {
|
||||||
|
if (row.every((x) => x == null)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
var model = Quotation(
|
||||||
|
id: fields.contains('id') ? (row[0] as String?) : null,
|
||||||
|
name: fields.contains('name') ? (row[1] as String?) : null,
|
||||||
|
price: fields.contains('price') ? mapToDouble(row[2]) : null,
|
||||||
|
);
|
||||||
|
return Optional.of(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Optional<Quotation> deserialize(List row) {
|
||||||
|
return parseRow(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuotationQueryWhere extends QueryWhere {
|
||||||
|
QuotationQueryWhere(QuotationQuery query)
|
||||||
|
: id = StringSqlExpressionBuilder(
|
||||||
|
query,
|
||||||
|
'id',
|
||||||
|
),
|
||||||
|
name = StringSqlExpressionBuilder(
|
||||||
|
query,
|
||||||
|
'name',
|
||||||
|
),
|
||||||
|
price = NumericSqlExpressionBuilder<double>(
|
||||||
|
query,
|
||||||
|
'price',
|
||||||
|
);
|
||||||
|
|
||||||
|
final StringSqlExpressionBuilder id;
|
||||||
|
|
||||||
|
final StringSqlExpressionBuilder name;
|
||||||
|
|
||||||
|
final NumericSqlExpressionBuilder<double> price;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<SqlExpressionBuilder> get expressionBuilders {
|
||||||
|
return [
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
price,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuotationQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
Map<String, String> get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
String? get id {
|
||||||
|
return (values['id'] as String?);
|
||||||
|
}
|
||||||
|
|
||||||
|
set id(String? value) => values['id'] = value;
|
||||||
|
String? get name {
|
||||||
|
return (values['name'] as String?);
|
||||||
|
}
|
||||||
|
|
||||||
|
set name(String? value) => values['name'] = value;
|
||||||
|
double? get price {
|
||||||
|
return (values['price'] as double?) ?? 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
set price(double? value) => values['price'] = value;
|
||||||
|
void copyFrom(Quotation model) {
|
||||||
|
id = model.id;
|
||||||
|
name = model.name;
|
||||||
|
price = model.price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonModelGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
@generatedSerializable
|
||||||
|
class Quotation extends _Quotation {
|
||||||
|
Quotation({
|
||||||
|
this.id,
|
||||||
|
this.name,
|
||||||
|
this.price,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? id;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? name;
|
||||||
|
|
||||||
|
@override
|
||||||
|
double? price;
|
||||||
|
|
||||||
|
Quotation copyWith({
|
||||||
|
String? id,
|
||||||
|
String? name,
|
||||||
|
double? price,
|
||||||
|
}) {
|
||||||
|
return Quotation(
|
||||||
|
id: id ?? this.id, name: name ?? this.name, price: price ?? this.price);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) {
|
||||||
|
return other is _Quotation &&
|
||||||
|
other.id == id &&
|
||||||
|
other.name == name &&
|
||||||
|
other.price == price;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return hashObjects([
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
price,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Quotation(id=$id, name=$name, price=$price)';
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return QuotationSerializer.toMap(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// SerializerGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
const QuotationSerializer quotationSerializer = QuotationSerializer();
|
||||||
|
|
||||||
|
class QuotationEncoder extends Converter<Quotation, Map> {
|
||||||
|
const QuotationEncoder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map convert(Quotation model) => QuotationSerializer.toMap(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuotationDecoder extends Converter<Map, Quotation> {
|
||||||
|
const QuotationDecoder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Quotation convert(Map map) => QuotationSerializer.fromMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuotationSerializer extends Codec<Quotation, Map> {
|
||||||
|
const QuotationSerializer();
|
||||||
|
|
||||||
|
@override
|
||||||
|
QuotationEncoder get encoder => const QuotationEncoder();
|
||||||
|
@override
|
||||||
|
QuotationDecoder get decoder => const QuotationDecoder();
|
||||||
|
static Quotation fromMap(Map map) {
|
||||||
|
return Quotation(
|
||||||
|
id: map['id'] as String?,
|
||||||
|
name: map['name'] as String?,
|
||||||
|
price: map['price'] as double?);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, dynamic> toMap(_Quotation? model) {
|
||||||
|
if (model == null) {
|
||||||
|
throw FormatException("Required field [model] cannot be null");
|
||||||
|
}
|
||||||
|
return {'id': model.id, 'name': model.name, 'price': model.price};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class QuotationFields {
|
||||||
|
static const List<String> allFields = <String>[
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
price,
|
||||||
|
];
|
||||||
|
|
||||||
|
static const String id = 'id';
|
||||||
|
|
||||||
|
static const String name = 'name';
|
||||||
|
|
||||||
|
static const String price = 'price';
|
||||||
|
}
|
Loading…
Reference in a new issue