Updated Generated Container

This commit is contained in:
thomashii@dukefirehawk.com 2023-03-11 12:44:22 +08:00
parent 05cbd71248
commit 08ba4f0609
31 changed files with 24278 additions and 6792 deletions

View file

@ -8,27 +8,38 @@
[![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)
**A polished, production-ready backend framework in Dart with NNBD support.**
**A polished, production-ready backend framework in Dart.**
-----
## 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:
* Static File Handling
* Basic Authentication
* PostgreSQL ORM
* Basic and OAuth2 Authentication
* ORM for PostgreSQL and MySQL
* MongoDB
* 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.
## 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:
@ -44,25 +55,19 @@ For more details, checkout [Project Status](https://github.com/dukefirehawk/ange
## 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 dependencies to the latest libraries
* Fixed ORM issues
* 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
### Create a new project by cloning from boilerplate templates

View file

@ -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

View 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}");
}

View 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}");
}

View 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}");
}

File diff suppressed because it is too large Load diff

View file

@ -12,9 +12,9 @@ void main() {
print('Reflection executed in ${stopwatch.elapsed.inMilliseconds} ms');
stopwatch.stop();
printAnnotationValue(String);
printAnnotationValue(Shape);
printAnnotationValue(Square);
//printAnnotationValue(String);
//printAnnotationValue(Shape);
//printAnnotationValue(Square);
}
class Shape {
@ -27,7 +27,7 @@ class Square {
print("Hii Welcome to flutter agency");
}
}
/*
void printAnnotationValue(final Type clazz) {
final DeclarationMirror clazzDeclaration = reflectClass(clazz);
final ClassMirror someAnnotationMirror = reflectClass(Person);
@ -41,3 +41,4 @@ void printAnnotationValue(final Type clazz) {
(annotationInstsanceMirror.first.reflectee as Person);
print(someAnnotationInstance.firstName);
}
*/

View file

@ -0,0 +1,9 @@
targets:
$default:
builders:
reflectable:
generate_for:
#- lib/**_controller.dart
- bin/**_controller.dart
options:
formatted: true

View file

@ -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() {}

View file

@ -30,18 +30,20 @@ dependencies:
tuple: ^2.0.0
uuid: ^3.0.1
collection: ^1.15.0
reflectable: ^4.0.2
dev_dependencies:
build_runner: ^2.1.2
http: ^0.13.1
io: ^1.0.0
test: ^1.21.0
lints: ^2.0.0
dependency_overrides:
angel3_container:
path: ../../../packages/container/angel_container
path: ../../../packages/container/angel_container
angel3_container_generator:
path: ../../../packages/container/angel_container_generator
# angel3_http_exception:
# path: ../http_exception
path: ../../../packages/container/angel_container_generator
angel3_framework:
path: ../../../packages/framework
# angel3_model:
# path: ../model
# angel3_route:

View 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!";
}

View file

@ -1,5 +1,9 @@
# Change Log
## 7.1.1
* Moved `defaultErrorMessage` to `ContainerConst` class to resolve reflectatable issue.
## 7.1.0
* Require Dart >= 2.18

View file

@ -6,3 +6,4 @@ export 'src/static/static.dart';
export 'src/exception.dart';
export 'src/reflector.dart';
export 'src/throwing.dart';
export 'src/container_const.dart';

View file

@ -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._();
}

View file

@ -1,3 +1,5 @@
import 'package:angel3_container/src/container_const.dart';
import 'empty/empty.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.
final String errorMessage;
/*
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.';
*/
const ThrowingReflector({this.errorMessage = defaultErrorMessage});
const ThrowingReflector(
{this.errorMessage = ContainerConst.defaultErrorMessage});
@override
String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);

View file

@ -1,5 +1,5 @@
name: angel3_container
version: 7.1.0
version: 7.1.1
description: Angel3 hierarchical DI container, and pluggable backends for reflection.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/container/angel_container

View file

@ -5,4 +5,27 @@
[![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)
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

View file

@ -5,8 +5,7 @@ import 'package:angel3_container_generator/angel3_container_generator.dart';
Future<void> main() async {
// Create a container instance.
var reflector = const GeneratedReflector();
Container container = Container(reflector);
Container container = Container(GeneratedReflector());
// Register a singleton.
container.registerSingleton<Engine>(Engine(40));

View file

@ -11,11 +11,11 @@ class ContainedReflectable extends Reflectable {
topLevelInvokeCapability,
typeAnnotationQuantifyCapability,
superclassQuantifyCapability,
instanceInvokeCapability,
libraryCapability,
invokingCapability,
newInstanceCapability,
metadataCapability,
reflectedTypeCapability,
typeCapability,
typingCapability);
}

View file

@ -29,7 +29,8 @@ void main() {
expect(album.title, 'flowers by stevie wonder');
});
testReflector(reflector);
// Skip as pkg:reflectable cannot reflect on closures at all (yet)
//testReflector(reflector);
}
@contained
@ -49,7 +50,6 @@ void testReflector(Reflector reflector) {
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
});
/*
group('reflectFunction', () {
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
@ -73,8 +73,7 @@ void testReflector(Reflector reflector) {
expect(p?.annotations, isEmpty);
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', () {
expect(container.make(Pokemon), blaziken);
@ -111,9 +110,9 @@ void testReflector(Reflector reflector) {
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
expect(
() => kantoPokemonType
kantoPokemonType
.isAssignableTo(container.reflector.reflectType(String)),
throwsUnsupportedError);
false);
});
}

View file

@ -1,5 +1,10 @@
# Change Log
## 7.0.4
* Updated `Expose` fields to non-nullable
* Updated `Controller` to use non-nullable field
## 7.0.3
* Fixed issue #83. Allow Http request to return null headers instead of throwing an exception.

View file

@ -64,13 +64,13 @@ class Controller {
}
var routable = Routable();
var m = router.mount(exposeDecl.path!, routable);
_mountPoint = m;
_mountPoint = router.mount(exposeDecl.path, routable);
//_mountPoint = m;
var typeMirror = reflector.reflectType(runtimeType);
// Pre-reflect methods
var instanceMirror = reflector.reflectInstance(this);
final handlers = <RequestHandler>[...exposeDecl.middleware!, ...middleware];
final handlers = <RequestHandler>[...exposeDecl.middleware, ...middleware];
final routeBuilder =
_routeBuilder(reflector, instanceMirror, routable, handlers);
await configureRoutes(routable);
@ -107,7 +107,7 @@ class Controller {
return;
} else {
// Otherwise, create an @Expose.
exposeDecl = Expose(null);
exposeDecl = Expose('');
}
}
@ -115,7 +115,7 @@ class Controller {
instanceMirror!.getField(methodName).reflectee as Function?;
var middleware = <RequestHandler>[
...handlers,
...exposeDecl.middleware!
...exposeDecl.middleware
];
var name =
exposeDecl.as?.isNotEmpty == true ? exposeDecl.as : methodName;
@ -127,7 +127,7 @@ class Controller {
method.parameters[1].type.reflectedType == ResponseContext) {
// Create a regular route
routeMappings[name ?? ''] = routable
.addRoute(exposeDecl.method, exposeDecl.path ?? '',
.addRoute(exposeDecl.method, exposeDecl.path,
(RequestContext req, ResponseContext res) {
var result = reflectedMethod!(req, res);
return result is RequestHandler ? result(req, res) : result;
@ -144,7 +144,7 @@ class Controller {
// If there is no path, reverse-engineer one.
var path = exposeDecl.path;
var httpMethod = exposeDecl.method;
if (path == null) {
if (path == '') {
// Try to build a route path by finding all potential
// path segments, and then joining them.
var parts = <String>[];

View file

@ -45,17 +45,17 @@ const NoExpose noExpose = NoExpose();
/// ```
class Expose {
final String method;
final String? path;
final Iterable<RequestHandler>? middleware;
final String path;
final Iterable<RequestHandler> middleware;
final String? as;
final List<String> allowNull;
static const Expose get = Expose(null, method: 'GET'),
post = Expose(null, method: 'POST'),
patch = Expose(null, method: 'PATCH'),
put = Expose(null, method: 'PUT'),
delete = Expose(null, method: 'DELETE'),
head = Expose(null, method: 'HEAD');
static const Expose get = Expose('', method: 'GET'),
post = Expose('', method: 'POST'),
patch = Expose('', method: 'PATCH'),
put = Expose('', method: 'PUT'),
delete = Expose('', method: 'DELETE'),
head = Expose('', method: 'HEAD');
const Expose(this.path,
{this.method = 'GET',
@ -64,8 +64,8 @@ class Expose {
this.allowNull = const []});
const Expose.method(this.method,
{this.middleware, this.as, this.allowNull = const []})
: path = null;
{this.middleware = const [], this.as, this.allowNull = const []})
: path = '';
}
/// Used to apply special dependency injections or functionality to a function parameter.
@ -89,7 +89,7 @@ class Parameter {
final dynamic defaultValue;
/// If `true` (default), then an error will be thrown if this parameter is not present.
final bool? required;
final bool required;
const Parameter(
{this.cookie,
@ -98,7 +98,7 @@ class Parameter {
this.session,
this.match,
this.defaultValue,
this.required});
this.required = true});
/// Returns an error that can be thrown when the parameter is not present.
Object? get error {

View file

@ -388,7 +388,7 @@ class Angel extends Routable {
}
static const String _reflectionErrorMessage =
'${ThrowingReflector.defaultErrorMessage} $_reflectionInfo';
'${ContainerConst.defaultErrorMessage} $_reflectionInfo';
static const String _reflectionInfo =
'Features like controllers, constructor dependency injection, and `ioc` require reflection, '

View file

@ -1,10 +1,10 @@
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.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/framework
environment:
sdk: '>=2.17.0 <3.0.0'
sdk: '>=2.18.0 <3.0.0'
dependencies:
angel3_container: ^7.0.0
angel3_http_exception: ^7.0.0
@ -35,9 +35,9 @@ dev_dependencies:
io: ^1.0.0
test: ^1.21.0
lints: ^2.0.0
# dependency_overrides:
# angel3_container:
# path: ../container/angel_container
dependency_overrides:
angel3_container:
path: ../container/angel_container
# angel3_http_exception:
# path: ../http_exception
# angel3_model:

View 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;
}

View 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';
}