enum tests

This commit is contained in:
Tobe O 2019-01-23 17:08:26 -05:00
parent bc7021b598
commit d356375af5
9 changed files with 353 additions and 38 deletions

View file

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

View file

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

View file

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

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

View file

@ -0,0 +1,6 @@
CREATE TEMPORARY TABLE "has_cars" (
id serial PRIMARY KEY,
type int not null,
created_at timestamp,
updated_at timestamp
);

View file

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

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

View file

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

View file

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