enum tests
This commit is contained in:
parent
bc7021b598
commit
d356375af5
9 changed files with 353 additions and 38 deletions
|
@ -33,7 +33,7 @@ targets:
|
|||
- :_standalone
|
||||
sources:
|
||||
- test/models/book.dart
|
||||
# - test/models/has_car.dart
|
||||
- test/models/has_car.dart
|
||||
- test/models/leg.dart
|
||||
- test/models/order.dart
|
||||
- test/models/tree.dart
|
||||
|
|
|
@ -217,6 +217,7 @@ ColumnType inferColumnType(DartType type) {
|
|||
return ColumnType.timeStamp;
|
||||
if (const TypeChecker.fromRuntime(Map).isAssignableFromType(type))
|
||||
return ColumnType.jsonb;
|
||||
if (type is InterfaceType && type.element.isEnum) return ColumnType.int;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
var args = <String, Expression>{};
|
||||
|
||||
for (var field in ctx.effectiveFields) {
|
||||
var fType = field.type;
|
||||
Reference type = convertTypeReference(field.type);
|
||||
if (isSpecialId(ctx, field)) type = refer('int');
|
||||
|
||||
|
@ -157,6 +158,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
expr = refer('json')
|
||||
.property('decode')
|
||||
.call([expr.asA(refer('String'))]).asA(type);
|
||||
} else if (fType is InterfaceType && fType.element.isEnum) {
|
||||
expr = type.property('values').index(expr.asA(refer('int')));
|
||||
} else
|
||||
expr = expr.asA(type);
|
||||
|
||||
|
@ -481,6 +484,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
// Add builders for each field
|
||||
for (var field in ctx.effectiveFields) {
|
||||
var name = field.name;
|
||||
var args = <Expression>[];
|
||||
DartType type;
|
||||
Reference builderType;
|
||||
|
||||
|
@ -496,6 +500,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
builderType = new TypeReference((b) => b
|
||||
..symbol = 'NumericSqlExpressionBuilder'
|
||||
..types.add(refer(isSpecialId(ctx, field) ? 'int' : type.name)));
|
||||
} else if (type is InterfaceType && type.element.isEnum) {
|
||||
builderType = new TypeReference((b) => b
|
||||
..symbol = 'EnumSqlExpressionBuilder'
|
||||
..types.add(convertTypeReference(type)));
|
||||
args.add(CodeExpression(Code('(v) => v.index')));
|
||||
} else if (const TypeChecker.fromRuntime(String).isExactlyType(type)) {
|
||||
builderType = refer('StringSqlExpressionBuilder');
|
||||
} else if (const TypeChecker.fromRuntime(bool).isExactlyType(type)) {
|
||||
|
@ -532,7 +541,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
.assign(builderType.newInstance([
|
||||
refer('query'),
|
||||
literalString(ctx.buildContext.resolveFieldName(field.name))
|
||||
]))
|
||||
].followedBy(args)))
|
||||
.code,
|
||||
);
|
||||
}));
|
||||
|
@ -558,31 +567,45 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
|
||||
// Each field generates a getter for setter
|
||||
for (var field in ctx.effectiveFields) {
|
||||
var fType = field.type;
|
||||
var name = ctx.buildContext.resolveFieldName(field.name);
|
||||
var type = isSpecialId(ctx, field)
|
||||
? refer('int')
|
||||
: convertTypeReference(field.type);
|
||||
|
||||
clazz.methods.add(new Method((b) {
|
||||
var value = refer('values').index(literalString(name));
|
||||
|
||||
if (fType is InterfaceType && fType.element.isEnum) {
|
||||
var asInt = value.asA(refer('int'));
|
||||
var t = convertTypeReference(fType);
|
||||
value = t.property('values').index(asInt);
|
||||
} else {
|
||||
value = value.asA(type);
|
||||
}
|
||||
|
||||
b
|
||||
..name = field.name
|
||||
..type = MethodType.getter
|
||||
..returns = type
|
||||
..body = new Block((b) => b.addExpression(
|
||||
refer('values').index(literalString(name)).asA(type).returned));
|
||||
..body = new Block((b) => b.addExpression(value.returned));
|
||||
}));
|
||||
|
||||
clazz.methods.add(new Method((b) {
|
||||
Expression value = refer('value');
|
||||
|
||||
if (fType is InterfaceType && fType.element.isEnum) {
|
||||
value = value.property('index');
|
||||
}
|
||||
|
||||
b
|
||||
..name = field.name
|
||||
..type = MethodType.setter
|
||||
..requiredParameters.add(new Parameter((b) => b
|
||||
..name = 'value'
|
||||
..type = type))
|
||||
..body = refer('values')
|
||||
.index(literalString(name))
|
||||
.assign(refer('value'))
|
||||
.code;
|
||||
..body =
|
||||
refer('values').index(literalString(name)).assign(value).code;
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
36
angel_orm_generator/test/enum_and_nested_test.dart
Normal file
36
angel_orm_generator/test/enum_and_nested_test.dart
Normal file
|
@ -0,0 +1,36 @@
|
|||
import 'package:test/test.dart';
|
||||
import 'models/has_car.dart';
|
||||
import 'common.dart';
|
||||
|
||||
main() {
|
||||
PostgresExecutor executor;
|
||||
|
||||
setUp(() async {
|
||||
executor = await connectToPostgres(['has_car']);
|
||||
});
|
||||
|
||||
test('insert', () async {
|
||||
var query = HasCarQuery()..values.type = CarType.sedan;
|
||||
var result = await query.insert(executor);
|
||||
expect(result.type, CarType.sedan);
|
||||
});
|
||||
|
||||
group('query', () {
|
||||
HasCar initialValue;
|
||||
|
||||
setUp(() async {
|
||||
var query = HasCarQuery();
|
||||
query.values.type = CarType.sedan;
|
||||
initialValue = await query.insert(executor);
|
||||
});
|
||||
|
||||
test('query by enum', () async {
|
||||
// Check for mismatched type
|
||||
var query = HasCarQuery()..where.type.equals(CarType.atv);
|
||||
expect(await query.get(executor), isEmpty);
|
||||
|
||||
query = HasCarQuery()..where.type.equals(initialValue.type);
|
||||
expect(await query.getOne(executor), initialValue);
|
||||
});
|
||||
});
|
||||
}
|
6
angel_orm_generator/test/migrations/has_car.sql
Normal file
6
angel_orm_generator/test/migrations/has_car.sql
Normal file
|
@ -0,0 +1,6 @@
|
|||
CREATE TEMPORARY TABLE "has_cars" (
|
||||
id serial PRIMARY KEY,
|
||||
type int not null,
|
||||
created_at timestamp,
|
||||
updated_at timestamp
|
||||
);
|
|
@ -2,11 +2,24 @@ import 'package:angel_migration/angel_migration.dart';
|
|||
import 'package:angel_model/angel_model.dart';
|
||||
import 'package:angel_orm/angel_orm.dart';
|
||||
import 'package:angel_serialize/angel_serialize.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'car.dart';
|
||||
// part 'has_car.g.dart';
|
||||
part 'has_car.g.dart';
|
||||
|
||||
Map _carToMap(Car car) => car.toJson();
|
||||
|
||||
Car _carFromMap(map) => CarSerializer.fromMap(map as Map);
|
||||
|
||||
enum CarType { sedan, suv, atv }
|
||||
|
||||
@orm
|
||||
@serializable
|
||||
abstract class _PackageJson extends Model {
|
||||
Car get car;
|
||||
abstract class _HasCar extends Model {
|
||||
// TODO: Do this without explicit serializers
|
||||
// @SerializableField(
|
||||
// serializesTo: Map, serializer: #_carToMap, deserializer: #_carFromMap)
|
||||
// Car get car;
|
||||
|
||||
@SerializableField(isNullable: false)
|
||||
CarType get type;
|
||||
}
|
||||
|
|
234
angel_orm_generator/test/models/has_car.g.dart
Normal file
234
angel_orm_generator/test/models/has_car.g.dart
Normal file
|
@ -0,0 +1,234 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'has_car.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// MigrationGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class HasCarMigration extends Migration {
|
||||
@override
|
||||
up(Schema schema) {
|
||||
schema.create('has_cars', (table) {
|
||||
table.serial('id')..primaryKey();
|
||||
table.integer('type');
|
||||
table.timeStamp('created_at');
|
||||
table.timeStamp('updated_at');
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
down(Schema schema) {
|
||||
schema.drop('has_cars');
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// OrmGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class HasCarQuery extends Query<HasCar, HasCarQueryWhere> {
|
||||
HasCarQuery() {
|
||||
_where = new HasCarQueryWhere(this);
|
||||
}
|
||||
|
||||
@override
|
||||
final HasCarQueryValues values = new HasCarQueryValues();
|
||||
|
||||
HasCarQueryWhere _where;
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'has_cars';
|
||||
}
|
||||
|
||||
@override
|
||||
get fields {
|
||||
return const ['id', 'type', 'created_at', 'updated_at'];
|
||||
}
|
||||
|
||||
@override
|
||||
HasCarQueryWhere get where {
|
||||
return _where;
|
||||
}
|
||||
|
||||
@override
|
||||
HasCarQueryWhere newWhereClause() {
|
||||
return new HasCarQueryWhere(this);
|
||||
}
|
||||
|
||||
static HasCar parseRow(List row) {
|
||||
if (row.every((x) => x == null)) return null;
|
||||
var model = new HasCar(
|
||||
id: row[0].toString(),
|
||||
type: CarType.values[(row[1] as int)],
|
||||
createdAt: (row[2] as DateTime),
|
||||
updatedAt: (row[3] as DateTime));
|
||||
return model;
|
||||
}
|
||||
|
||||
@override
|
||||
deserialize(List row) {
|
||||
return parseRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
class HasCarQueryWhere extends QueryWhere {
|
||||
HasCarQueryWhere(HasCarQuery query)
|
||||
: id = new NumericSqlExpressionBuilder<int>(query, 'id'),
|
||||
type = new EnumSqlExpressionBuilder<CarType>(
|
||||
query, 'type', (v) => v.index),
|
||||
createdAt = new DateTimeSqlExpressionBuilder(query, 'created_at'),
|
||||
updatedAt = new DateTimeSqlExpressionBuilder(query, 'updated_at');
|
||||
|
||||
final NumericSqlExpressionBuilder<int> id;
|
||||
|
||||
final EnumSqlExpressionBuilder<CarType> type;
|
||||
|
||||
final DateTimeSqlExpressionBuilder createdAt;
|
||||
|
||||
final DateTimeSqlExpressionBuilder updatedAt;
|
||||
|
||||
@override
|
||||
get expressionBuilders {
|
||||
return [id, type, createdAt, updatedAt];
|
||||
}
|
||||
}
|
||||
|
||||
class HasCarQueryValues extends MapQueryValues {
|
||||
int get id {
|
||||
return (values['id'] as int);
|
||||
}
|
||||
|
||||
set id(int value) => values['id'] = value;
|
||||
CarType get type {
|
||||
return CarType.values[(values['type'] as int)];
|
||||
}
|
||||
|
||||
set type(CarType value) => values['type'] = value.index;
|
||||
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;
|
||||
void copyFrom(HasCar model) {
|
||||
values.addAll({
|
||||
'type': model.type,
|
||||
'created_at': model.createdAt,
|
||||
'updated_at': model.updatedAt
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// JsonModelGenerator
|
||||
// **************************************************************************
|
||||
|
||||
@generatedSerializable
|
||||
class HasCar extends _HasCar {
|
||||
HasCar({this.id, @required this.type, this.createdAt, this.updatedAt});
|
||||
|
||||
@override
|
||||
final String id;
|
||||
|
||||
@override
|
||||
final CarType type;
|
||||
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
||||
@override
|
||||
final DateTime updatedAt;
|
||||
|
||||
HasCar copyWith(
|
||||
{String id, CarType type, DateTime createdAt, DateTime updatedAt}) {
|
||||
return new HasCar(
|
||||
id: id ?? this.id,
|
||||
type: type ?? this.type,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
updatedAt: updatedAt ?? this.updatedAt);
|
||||
}
|
||||
|
||||
bool operator ==(other) {
|
||||
return other is _HasCar &&
|
||||
other.id == id &&
|
||||
other.type == type &&
|
||||
other.createdAt == createdAt &&
|
||||
other.updatedAt == updatedAt;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashObjects([id, type, createdAt, updatedAt]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return HasCarSerializer.toMap(this);
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// SerializerGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class HasCarSerializer {
|
||||
static HasCar fromMap(Map map) {
|
||||
if (map['type'] == null) {
|
||||
throw new FormatException("Missing required field 'type' on HasCar.");
|
||||
}
|
||||
|
||||
return new HasCar(
|
||||
id: map['id'] as String,
|
||||
type: map['type'] is CarType
|
||||
? (map['type'] as CarType)
|
||||
: (map['type'] is int ? CarType.values[map['type'] as int] : null),
|
||||
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);
|
||||
}
|
||||
|
||||
static Map<String, dynamic> toMap(_HasCar model) {
|
||||
if (model == null) {
|
||||
return null;
|
||||
}
|
||||
if (model.type == null) {
|
||||
throw new FormatException("Missing required field 'type' on HasCar.");
|
||||
}
|
||||
|
||||
return {
|
||||
'id': model.id,
|
||||
'type': model.type == null ? null : CarType.values.indexOf(model.type),
|
||||
'created_at': model.createdAt?.toIso8601String(),
|
||||
'updated_at': model.updatedAt?.toIso8601String()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class HasCarFields {
|
||||
static const List<String> allFields = const <String>[
|
||||
id,
|
||||
type,
|
||||
createdAt,
|
||||
updatedAt
|
||||
];
|
||||
|
||||
static const String id = 'id';
|
||||
|
||||
static const String type = 'type';
|
||||
|
||||
static const String createdAt = 'created_at';
|
||||
|
||||
static const String updatedAt = 'updated_at';
|
||||
}
|
|
@ -9,13 +9,13 @@ part 'order.g.dart';
|
|||
|
||||
@orm
|
||||
@serializable
|
||||
class _Order extends Model {
|
||||
@Join(Customer, CustomerFields.id)
|
||||
int customerId;
|
||||
abstract class _Order extends Model {
|
||||
@belongsTo
|
||||
Customer get customer;
|
||||
|
||||
int employeeId;
|
||||
int get employeeId;
|
||||
|
||||
DateTime orderDate;
|
||||
DateTime get orderDate;
|
||||
|
||||
int shipperId;
|
||||
int get shipperId;
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ class OrderMigration extends Migration {
|
|||
up(Schema schema) {
|
||||
schema.create('orders', (table) {
|
||||
table.serial('id')..primaryKey();
|
||||
table.integer('customer_id');
|
||||
table.integer('employee_id');
|
||||
table.timeStamp('order_date');
|
||||
table.integer('shipper_id');
|
||||
table.timeStamp('created_at');
|
||||
table.timeStamp('updated_at');
|
||||
table.integer('customer_id').references('customers', 'id');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ class OrderMigration extends Migration {
|
|||
class OrderQuery extends Query<Order, OrderQueryWhere> {
|
||||
OrderQuery() {
|
||||
_where = new OrderQueryWhere(this);
|
||||
leftJoin('customers', 'customer_id', 'id',
|
||||
additionalFields: const ['created_at', 'updated_at']);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -72,12 +74,15 @@ class OrderQuery extends Query<Order, OrderQueryWhere> {
|
|||
if (row.every((x) => x == null)) return null;
|
||||
var model = new Order(
|
||||
id: row[0].toString(),
|
||||
customerId: (row[1] as int),
|
||||
employeeId: (row[2] as int),
|
||||
orderDate: (row[3] as DateTime),
|
||||
shipperId: (row[4] as int),
|
||||
createdAt: (row[5] as DateTime),
|
||||
updatedAt: (row[6] as DateTime));
|
||||
if (row.length > 7) {
|
||||
model = model.copyWith(
|
||||
customer: CustomerQuery.parseRow(row.skip(7).toList()));
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
|
@ -163,13 +168,15 @@ class OrderQueryValues extends MapQueryValues {
|
|||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||
void copyFrom(Order model) {
|
||||
values.addAll({
|
||||
'customer_id': model.customerId,
|
||||
'employee_id': model.employeeId,
|
||||
'order_date': model.orderDate,
|
||||
'shipper_id': model.shipperId,
|
||||
'created_at': model.createdAt,
|
||||
'updated_at': model.updatedAt
|
||||
});
|
||||
if (model.customer != null) {
|
||||
values['customer_id'] = int.parse(model.customer.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +188,7 @@ class OrderQueryValues extends MapQueryValues {
|
|||
class Order extends _Order {
|
||||
Order(
|
||||
{this.id,
|
||||
this.customerId,
|
||||
this.customer,
|
||||
this.employeeId,
|
||||
this.orderDate,
|
||||
this.shipperId,
|
||||
|
@ -192,7 +199,7 @@ class Order extends _Order {
|
|||
final String id;
|
||||
|
||||
@override
|
||||
final int customerId;
|
||||
final Customer customer;
|
||||
|
||||
@override
|
||||
final int employeeId;
|
||||
|
@ -211,7 +218,7 @@ class Order extends _Order {
|
|||
|
||||
Order copyWith(
|
||||
{String id,
|
||||
int customerId,
|
||||
Customer customer,
|
||||
int employeeId,
|
||||
DateTime orderDate,
|
||||
int shipperId,
|
||||
|
@ -219,7 +226,7 @@ class Order extends _Order {
|
|||
DateTime updatedAt}) {
|
||||
return new Order(
|
||||
id: id ?? this.id,
|
||||
customerId: customerId ?? this.customerId,
|
||||
customer: customer ?? this.customer,
|
||||
employeeId: employeeId ?? this.employeeId,
|
||||
orderDate: orderDate ?? this.orderDate,
|
||||
shipperId: shipperId ?? this.shipperId,
|
||||
|
@ -230,7 +237,7 @@ class Order extends _Order {
|
|||
bool operator ==(other) {
|
||||
return other is _Order &&
|
||||
other.id == id &&
|
||||
other.customerId == customerId &&
|
||||
other.customer == customer &&
|
||||
other.employeeId == employeeId &&
|
||||
other.orderDate == orderDate &&
|
||||
other.shipperId == shipperId &&
|
||||
|
@ -240,15 +247,8 @@ class Order extends _Order {
|
|||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashObjects([
|
||||
id,
|
||||
customerId,
|
||||
employeeId,
|
||||
orderDate,
|
||||
shipperId,
|
||||
createdAt,
|
||||
updatedAt
|
||||
]);
|
||||
return hashObjects(
|
||||
[id, customer, employeeId, orderDate, shipperId, createdAt, updatedAt]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
|
@ -264,7 +264,9 @@ abstract class OrderSerializer {
|
|||
static Order fromMap(Map map) {
|
||||
return new Order(
|
||||
id: map['id'] as String,
|
||||
customerId: map['customer_id'] as int,
|
||||
customer: map['customer'] != null
|
||||
? CustomerSerializer.fromMap(map['customer'] as Map)
|
||||
: null,
|
||||
employeeId: map['employee_id'] as int,
|
||||
orderDate: map['order_date'] != null
|
||||
? (map['order_date'] is DateTime
|
||||
|
@ -290,7 +292,7 @@ abstract class OrderSerializer {
|
|||
}
|
||||
return {
|
||||
'id': model.id,
|
||||
'customer_id': model.customerId,
|
||||
'customer': CustomerSerializer.toMap(model.customer),
|
||||
'employee_id': model.employeeId,
|
||||
'order_date': model.orderDate?.toIso8601String(),
|
||||
'shipper_id': model.shipperId,
|
||||
|
@ -303,7 +305,7 @@ abstract class OrderSerializer {
|
|||
abstract class OrderFields {
|
||||
static const List<String> allFields = const <String>[
|
||||
id,
|
||||
customerId,
|
||||
customer,
|
||||
employeeId,
|
||||
orderDate,
|
||||
shipperId,
|
||||
|
@ -313,7 +315,7 @@ abstract class OrderFields {
|
|||
|
||||
static const String id = 'id';
|
||||
|
||||
static const String customerId = 'customer_id';
|
||||
static const String customer = 'customer';
|
||||
|
||||
static const String employeeId = 'employee_id';
|
||||
|
||||
|
|
Loading…
Reference in a new issue