2.0.0-dev.9

This commit is contained in:
Tobe O 2018-12-03 11:50:43 -05:00
parent 83eb36c4a7
commit 207cd50afe
18 changed files with 526 additions and 67 deletions

View file

@ -1,3 +1,13 @@
# 2.0.0-dev.9
* Permanent preamble fix
# 2.0.0-dev.8
* Escapes
# 2.0.0-dev.7
* Update `toSql`
* Add `isTrue` and `isFalse`
# 2.0.0-dev.6 # 2.0.0-dev.6
* Add `delete`, `insert` and `update` methods to `Query`. * Add `delete`, `insert` and `update` methods to `Query`.

View file

@ -19,7 +19,7 @@ class _FakeExecutor extends QueryExecutor {
const _FakeExecutor(); const _FakeExecutor();
@override @override
Future<List<List>> query(String query, returningFields) async { Future<List<List>> query(String query, [returningFields]) async {
var now = new DateTime.now(); var now = new DateTime.now();
print('_FakeExecutor received query: $query'); print('_FakeExecutor received query: $query');
return [ return [

View file

@ -223,6 +223,10 @@ class BooleanSqlExpressionBuilder implements SqlExpressionBuilder<bool> {
return '$_op $v'; return '$_op $v';
} }
Null get isTrue => equals(true);
Null get isFalse => equals(false);
void equals(bool value) { void equals(bool value) {
_change('=', value); _change('=', value);
} }

View file

@ -1,7 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'package:charcode/ascii.dart';
import 'annotations.dart'; import 'annotations.dart';
import 'builder.dart'; import 'builder.dart';
bool isAscii(int ch) => ch >= $nul && ch <= $del;
/// A base class for objects that compile to SQL queries, typically within an ORM. /// A base class for objects that compile to SQL queries, typically within an ORM.
abstract class QueryBase<T> { abstract class QueryBase<T> {
/// The list of fields returned by this query. /// The list of fields returned by this query.
@ -18,9 +21,7 @@ abstract class QueryBase<T> {
Future<List<T>> get(QueryExecutor executor) async { Future<List<T>> get(QueryExecutor executor) async {
var sql = compile(); var sql = compile();
return executor return executor.query(sql).then((it) => it.map(deserialize).toList());
.query(sql, fields)
.then((it) => it.map(deserialize).toList());
} }
Future<T> getOne(QueryExecutor executor) { Future<T> getOne(QueryExecutor executor) {
@ -47,14 +48,33 @@ class OrderBy {
String toSql(Object obj) { String toSql(Object obj) {
if (obj is DateTime) { if (obj is DateTime) {
return dateYmdHms.format(obj); return "'${dateYmdHms.format(obj)}'";
} else if (obj is bool) { } else if (obj is bool) {
return obj ? 'TRUE' : 'FALSE'; return obj ? 'TRUE' : 'FALSE';
} else if (obj == null) { } else if (obj == null) {
return 'NULL'; return 'NULL';
} else if (obj is String) { } else if (obj is String) {
// TODO: Proper escapes var b = new StringBuffer();
return obj; var it = obj.runes.iterator;
while (it.moveNext()) {
if (it.current == $nul)
continue; // Skip null byte
else if (isAscii(it.current)) {
b.writeCharCode(it.current);
} else if (it.currentSize == 1) {
b.write('\\u');
b.write(it.current.toRadixString(16).padLeft(4, '0'));
} else if (it.currentSize == 2) {
b.write('\\U');
b.write(it.current.toRadixString(16).padLeft(8, '0'));
} else {
throw new UnsupportedError(
'toSql() cannot encode a rune of size (${it.currentSize})');
}
}
return "'$b'";
} else { } else {
return obj.toString(); return obj.toString();
} }
@ -175,6 +195,7 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
@override @override
String compile({bool includeTableName: false, String preamble}) { String compile({bool includeTableName: false, String preamble}) {
var b = new StringBuffer(preamble ?? 'SELECT'); var b = new StringBuffer(preamble ?? 'SELECT');
b.write(' ');
var f = fields ?? ['*']; var f = fields ?? ['*'];
if (includeTableName) f = f.map((s) => '$tableName.$s').toList(); if (includeTableName) f = f.map((s) => '$tableName.$s').toList();
b.write(f.join(', ')); b.write(f.join(', '));
@ -210,15 +231,13 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
} }
Future<T> insert(QueryExecutor executor) { Future<T> insert(QueryExecutor executor) {
var sql = new StringBuffer('INSERT INTO $tableName ($fieldSet)'); var sql = values.compileInsert(tableName);
var valuesClause = values.compileForInsert();
if (valuesClause == null) { if (sql == null) {
throw new StateError('No values have been specified for update.'); throw new StateError('No values have been specified for update.');
} else { } else {
sql.write(' $valuesClause');
return executor return executor
.query(sql.toString(), fields) .query(sql, fields)
.then((it) => it.isEmpty ? null : deserialize(it.first)); .then((it) => it.isEmpty ? null : deserialize(it.first));
} }
} }
@ -249,10 +268,12 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
abstract class QueryValues { abstract class QueryValues {
Map<String, dynamic> toMap(); Map<String, dynamic> toMap();
String compileForInsert() { String compileInsert(String tableName) {
var data = toMap(); var data = toMap();
if (data.isEmpty) return null; if (data.isEmpty) return null;
var b = new StringBuffer('VALUES (');
var fieldSet = data.keys.join(', ');
var b = new StringBuffer('INSERT INTO $tableName ($fieldSet) VALUES (');
int i = 0; int i = 0;
for (var entry in data.entries) { for (var entry in data.entries) {
@ -318,9 +339,14 @@ abstract class QueryWhere {
if (tableName != null) key = '$tableName.$key'; if (tableName != null) key = '$tableName.$key';
if (builder.hasValue) { if (builder.hasValue) {
if (i++ > 0) b.write(' AND '); if (i++ > 0) b.write(' AND ');
if (builder is DateTimeSqlExpressionBuilder) {
if (tableName != null) b.write('$tableName.');
b.write(builder.compile());
} else {
b.write('$key ${builder.compile()}'); b.write('$key ${builder.compile()}');
} }
} }
}
for (var other in _and) { for (var other in _and) {
var sql = other.compile(); var sql = other.compile();
@ -411,5 +437,5 @@ class JoinOn {
abstract class QueryExecutor { abstract class QueryExecutor {
const QueryExecutor(); const QueryExecutor();
Future<List<List>> query(String query, List<String> returningFields); Future<List<List>> query(String query, [List<String> returningFields]);
} }

View file

@ -1,11 +1,12 @@
name: angel_orm name: angel_orm
version: 2.0.0-dev.6 version: 2.0.0-dev.9
description: Runtime support for Angel's ORM. Includes base classes for queries. description: Runtime support for Angel's ORM. Includes base classes for queries.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/orm homepage: https://github.com/angel-dart/orm
environment: environment:
sdk: '>=2.0.0-dev.1.2 <3.0.0' sdk: '>=2.0.0-dev.1.2 <3.0.0'
dependencies: dependencies:
charcode: ^1.0.0
intl: ^0.15.7 intl: ^0.15.7
meta: ^1.0.0 meta: ^1.0.0
string_scanner: ^1.0.0 string_scanner: ^1.0.0
@ -14,3 +15,4 @@ dev_dependencies:
angel_serialize: ^2.0.0 angel_serialize: ^2.0.0
angel_serialize_generator: ^2.0.0 angel_serialize_generator: ^2.0.0
build_runner: ^1.0.0 build_runner: ^1.0.0
test: ^1.0.0

View file

@ -0,0 +1,17 @@
import 'package:angel_orm/angel_orm.dart';
import 'package:test/test.dart';
void main() {
test('simple', () {
expect(toSql('ABC _!'), "'ABC _!'");
});
test('ignores null byte', () {
expect(toSql('a\x00bc'), "'abc'");
});
test('unicode', () {
expect(toSql(''), r"'\u6771'");
expect(toSql('𐐀'), r"'\U00010400'");
});
}

View file

@ -48,6 +48,7 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
// Create `FooQueryWhere` class // Create `FooQueryWhere` class
lib.body.add(buildQueryClass(ctx)); lib.body.add(buildQueryClass(ctx));
lib.body.add(buildWhereClass(ctx)); lib.body.add(buildWhereClass(ctx));
lib.body.add(buildValuesClass(ctx));
}); });
} }
@ -68,6 +69,17 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
]); ]);
}); });
// Add values
clazz.fields.add(new Field((b) {
var type = refer('${rc.pascalCase}QueryValues');
b
..name = 'values'
..modifier = FieldModifier.final$
..annotations.add(refer('override'))
..type = type
..assignment = type.newInstance([]).code;
}));
// Add tableName // Add tableName
clazz.methods.add(new Method((m) { clazz.methods.add(new Method((m) {
m m
@ -101,6 +113,15 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..assignment = queryWhereType.newInstance([]).code; ..assignment = queryWhereType.newInstance([]).code;
})); }));
clazz.methods.add(new Method((b) {
b
..name = 'newWhereClause'
..annotations.add(refer('override'))
..returns = queryWhereType
..body = new Block(
(b) => b.addExpression(queryWhereType.newInstance([]).returned));
}));
// Add deserialize() // Add deserialize()
clazz.methods.add(new Method((m) { clazz.methods.add(new Method((m) {
m m
@ -193,4 +214,66 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} }
}); });
} }
Class buildValuesClass(OrmBuildContext ctx) {
return new Class((clazz) {
var rc = ctx.buildContext.modelClassNameRecase;
clazz
..name = '${rc.pascalCase}QueryValues'
..extend = refer('MapQueryValues');
// Each field generates a getter for setter
for (var field in ctx.buildContext.fields) {
var name = ctx.buildContext.resolveFieldName(field.name);
var type = isSpecialId(field)
? refer('int')
: convertTypeReference(field.type);
clazz.methods.add(new Method((b) {
b
..name = field.name
..type = MethodType.getter
..returns = type
..body = new Block((b) => b.addExpression(
refer('values').index(literalString(name)).asA(type).returned));
}));
clazz.methods.add(new Method((b) {
b
..name = field.name
..type = MethodType.setter
..returns = refer('void')
..requiredParameters.add(new Parameter((b) => b
..name = 'value'
..type = type))
..body = refer('values')
.index(literalString(name))
.assign(refer('value'))
.code;
}));
}
// Add an copyFrom(model)
clazz.methods.add(new Method((b) {
b
..name = 'copyFrom'
..returns = refer('void')
..requiredParameters.add(new Parameter((b) => b
..name = 'model'
..type = ctx.buildContext.modelClassType))
..body = new Block((b) {
var args = <String, Expression>{};
for (var field in ctx.buildContext.fields) {
if (isSpecialId(field)) continue;
args[ctx.buildContext.resolveFieldName(field.name)] =
refer('model').property(field.name);
}
b.addExpression(
refer('values').property('addAll').call([literalMap(args)]));
});
}));
});
}
} }

View file

@ -1,6 +1,6 @@
name: angel_orm_generator name: angel_orm_generator
version: 2.0.0-dev version: 2.0.0-alpha
description: Code generators for Angel's ORM. description: Code generators for Angel's ORM. Generates query builder classes.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/orm homepage: https://github.com/angel-dart/orm
environment: environment:

View file

@ -10,8 +10,7 @@ Future<PostgresExecutor> connectToPostgres(Iterable<String> schemas) async {
await conn.open(); await conn.open();
for (var s in schemas) for (var s in schemas)
await conn await conn.execute(await new File('test/migrations/$s.sql').readAsString());
.execute(await new File('test/models/$s.up.g.sql').readAsString());
return new PostgresExecutor(conn); return new PostgresExecutor(conn);
} }
@ -24,9 +23,14 @@ class PostgresExecutor extends QueryExecutor {
Future close() => connection.close(); Future close() => connection.close();
@override @override
Future<List<List>> query(String query, List<String> returningFields) { Future<List<List>> query(String query, [List<String> returningFields]) {
if (returningFields != null) {
var fields = returningFields.join(', '); var fields = returningFields.join(', ');
var returning = 'RETURNING ($fields)'; var returning = 'RETURNING $fields';
return connection.query('$query $returning'); query = '$query $returning';
}
print('Running: $query');
return connection.query(query);
} }
} }

View file

@ -0,0 +1,9 @@
CREATE TEMPORARY TABLE "cars" (
id serial PRIMARY KEY,
make varchar(255) NOT NULL,
description TEXT NOT NULL,
family_friendly BOOLEAN NOT NULL,
recalled_at timestamp,
created_at timestamp,
updated_at timestamp
);

View file

@ -7,6 +7,9 @@ part of angel_orm.generator.models.author;
// ************************************************************************** // **************************************************************************
class AuthorQuery extends Query<Author, AuthorQueryWhere> { class AuthorQuery extends Query<Author, AuthorQueryWhere> {
@override
final AuthorQueryValues values = new AuthorQueryValues();
@override @override
final AuthorQueryWhere where = new AuthorQueryWhere(); final AuthorQueryWhere where = new AuthorQueryWhere();
@ -20,6 +23,11 @@ class AuthorQuery extends Query<Author, AuthorQueryWhere> {
return AuthorFields.allFields; return AuthorFields.allFields;
} }
@override
AuthorQueryWhere newWhereClause() {
return new AuthorQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Author( return new Author(
@ -49,6 +57,36 @@ class AuthorQueryWhere extends QueryWhere {
} }
} }
class AuthorQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
String get name {
return (values['name'] as String);
}
void set name(String value) => values['name'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Author model) {
values.addAll({
'name': model.name,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm.generator.models.car;
// ************************************************************************** // **************************************************************************
class CarQuery extends Query<Car, CarQueryWhere> { class CarQuery extends Query<Car, CarQueryWhere> {
@override
final CarQueryValues values = new CarQueryValues();
@override @override
final CarQueryWhere where = new CarQueryWhere(); final CarQueryWhere where = new CarQueryWhere();
@ -20,6 +23,11 @@ class CarQuery extends Query<Car, CarQueryWhere> {
return CarFields.allFields; return CarFields.allFields;
} }
@override
CarQueryWhere newWhereClause() {
return new CarQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Car( return new Car(
@ -69,6 +77,54 @@ class CarQueryWhere extends QueryWhere {
} }
} }
class CarQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
String get make {
return (values['make'] as String);
}
void set make(String value) => values['make'] = value;
String get description {
return (values['description'] as String);
}
void set description(String value) => values['description'] = value;
bool get familyFriendly {
return (values['family_friendly'] as bool);
}
void set familyFriendly(bool value) => values['family_friendly'] = value;
DateTime get recalledAt {
return (values['recalled_at'] as DateTime);
}
void set recalledAt(DateTime value) => values['recalled_at'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Car model) {
values.addAll({
'make': model.make,
'description': model.description,
'family_friendly': model.familyFriendly,
'recalled_at': model.recalledAt,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.customer;
// ************************************************************************** // **************************************************************************
class CustomerQuery extends Query<Customer, CustomerQueryWhere> { class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
@override
final CustomerQueryValues values = new CustomerQueryValues();
@override @override
final CustomerQueryWhere where = new CustomerQueryWhere(); final CustomerQueryWhere where = new CustomerQueryWhere();
@ -20,6 +23,11 @@ class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
return CustomerFields.allFields; return CustomerFields.allFields;
} }
@override
CustomerQueryWhere newWhereClause() {
return new CustomerQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Customer( return new Customer(
@ -45,6 +53,28 @@ class CustomerQueryWhere extends QueryWhere {
} }
} }
class CustomerQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Customer model) {
values
.addAll({'created_at': model.createdAt, 'updated_at': model.updatedAt});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.foot;
// ************************************************************************** // **************************************************************************
class FootQuery extends Query<Foot, FootQueryWhere> { class FootQuery extends Query<Foot, FootQueryWhere> {
@override
final FootQueryValues values = new FootQueryValues();
@override @override
final FootQueryWhere where = new FootQueryWhere(); final FootQueryWhere where = new FootQueryWhere();
@ -20,6 +23,11 @@ class FootQuery extends Query<Foot, FootQueryWhere> {
return FootFields.allFields; return FootFields.allFields;
} }
@override
FootQueryWhere newWhereClause() {
return new FootQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Foot( return new Foot(
@ -53,6 +61,42 @@ class FootQueryWhere extends QueryWhere {
} }
} }
class FootQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
int get legId {
return (values['leg_id'] as int);
}
void set legId(int value) => values['leg_id'] = value;
int get nToes {
return (values['n_toes'] as int);
}
void set nToes(int value) => values['n_toes'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Foot model) {
values.addAll({
'leg_id': model.legId,
'n_toes': model.nToes,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.fruit;
// ************************************************************************** // **************************************************************************
class FruitQuery extends Query<Fruit, FruitQueryWhere> { class FruitQuery extends Query<Fruit, FruitQueryWhere> {
@override
final FruitQueryValues values = new FruitQueryValues();
@override @override
final FruitQueryWhere where = new FruitQueryWhere(); final FruitQueryWhere where = new FruitQueryWhere();
@ -20,6 +23,11 @@ class FruitQuery extends Query<Fruit, FruitQueryWhere> {
return FruitFields.allFields; return FruitFields.allFields;
} }
@override
FruitQueryWhere newWhereClause() {
return new FruitQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Fruit( return new Fruit(
@ -53,6 +61,42 @@ class FruitQueryWhere extends QueryWhere {
} }
} }
class FruitQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
int get treeId {
return (values['tree_id'] as int);
}
void set treeId(int value) => values['tree_id'] = value;
String get commonName {
return (values['common_name'] as String);
}
void set commonName(String value) => values['common_name'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Fruit model) {
values.addAll({
'tree_id': model.treeId,
'common_name': model.commonName,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.order;
// ************************************************************************** // **************************************************************************
class OrderQuery extends Query<Order, OrderQueryWhere> { class OrderQuery extends Query<Order, OrderQueryWhere> {
@override
final OrderQueryValues values = new OrderQueryValues();
@override @override
final OrderQueryWhere where = new OrderQueryWhere(); final OrderQueryWhere where = new OrderQueryWhere();
@ -20,6 +23,11 @@ class OrderQuery extends Query<Order, OrderQueryWhere> {
return OrderFields.allFields; return OrderFields.allFields;
} }
@override
OrderQueryWhere newWhereClause() {
return new OrderQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Order( return new Order(
@ -69,6 +77,54 @@ class OrderQueryWhere extends QueryWhere {
} }
} }
class OrderQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
int get customerId {
return (values['customer_id'] as int);
}
void set customerId(int value) => values['customer_id'] = value;
int get employeeId {
return (values['employee_id'] as int);
}
void set employeeId(int value) => values['employee_id'] = value;
DateTime get orderDate {
return (values['order_date'] as DateTime);
}
void set orderDate(DateTime value) => values['order_date'] = value;
int get shipperId {
return (values['shipper_id'] as int);
}
void set shipperId(int value) => values['shipper_id'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void 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
});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.role;
// ************************************************************************** // **************************************************************************
class RoleQuery extends Query<Role, RoleQueryWhere> { class RoleQuery extends Query<Role, RoleQueryWhere> {
@override
final RoleQueryValues values = new RoleQueryValues();
@override @override
final RoleQueryWhere where = new RoleQueryWhere(); final RoleQueryWhere where = new RoleQueryWhere();
@ -20,6 +23,11 @@ class RoleQuery extends Query<Role, RoleQueryWhere> {
return RoleFields.allFields; return RoleFields.allFields;
} }
@override
RoleQueryWhere newWhereClause() {
return new RoleQueryWhere();
}
@override @override
deserialize(List row) { deserialize(List row) {
return new Role( return new Role(
@ -49,6 +57,36 @@ class RoleQueryWhere extends QueryWhere {
} }
} }
class RoleQueryValues extends MapQueryValues {
int get id {
return (values['id'] as int);
}
void set id(int value) => values['id'] = value;
String get name {
return (values['name'] as String);
}
void set name(String value) => values['name'] = value;
DateTime get createdAt {
return (values['created_at'] as DateTime);
}
void set createdAt(DateTime value) => values['created_at'] = value;
DateTime get updatedAt {
return (values['updated_at'] as DateTime);
}
void set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Role model) {
values.addAll({
'name': model.name,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
}
}
// ************************************************************************** // **************************************************************************
// JsonModelGenerator // JsonModelGenerator
// ************************************************************************** // **************************************************************************

View file

@ -12,24 +12,16 @@ main() {
test('to where', () { test('to where', () {
var query = new CarQuery(); var query = new CarQuery();
query.where query.where
..familyFriendly.equals(true) ..familyFriendly.isTrue
..recalledAt.lessThanOrEqualTo(y2k, includeTime: false); ..recalledAt.lessThanOrEqualTo(y2k, includeTime: false);
var whereClause = query.where.compile(tableName: 'cars'); var whereClause = query.where.compile(tableName: 'cars');
print('Where clause: $whereClause'); print('Where clause: $whereClause');
expect(whereClause, expect(whereClause,
'WHERE cars.family_friendly = TRUE AND cars.recalled_at <= \'2000-01-01\''); 'cars.family_friendly = TRUE AND cars.recalled_at <= \'2000-01-01\'');
}); });
test('parseRow', () { test('parseRow', () {
var row = [ var row = [0, 'Mazda', 'CX9', true, y2k, y2k, y2k];
0,
'Mazda',
'CX9',
true,
dateYmdHms.format(y2k),
dateYmdHms.format(y2k),
dateYmdHms.format(y2k)
];
print(row); print(row);
var car = new CarQuery().deserialize(row); var car = new CarQuery().deserialize(row);
print(car.toJson()); print(car.toJson());
@ -59,20 +51,22 @@ main() {
Car ferrari; Car ferrari;
setUp(() async { setUp(() async {
ferrari = await CarQuery.insert(connection, var query = new CarQuery();
make: 'Ferrari', query.values
description: 'Vroom vroom!', ..make = 'Ferrari東'
familyFriendly: false); ..description = 'Vroom vroom!'
..familyFriendly = false;
ferrari = await query.insert(connection);
}); });
tearDown(() => connection.close()); tearDown(() => connection.close());
test('where clause is applied', () async { test('where clause is applied', () async {
var query = new CarQuery()..where.familyFriendly.equals(true); var query = new CarQuery()..where.familyFriendly.isTrue;
var cars = await query.get(connection); var cars = await query.get(connection);
expect(cars, isEmpty); expect(cars, isEmpty);
var sportsCars = new CarQuery()..where.familyFriendly.notEquals(true); var sportsCars = new CarQuery()..where.familyFriendly.isFalse;
cars = await sportsCars.get(connection); cars = await sportsCars.get(connection);
print(cars.map((c) => c.toJson())); print(cars.map((c) => c.toJson()));
@ -85,22 +79,20 @@ main() {
test('union', () async { test('union', () async {
var query1 = new CarQuery()..where.make.like('%Fer%'); var query1 = new CarQuery()..where.make.like('%Fer%');
var query2 = new CarQuery()..where.familyFriendly.equals(true); var query2 = new CarQuery()..where.familyFriendly.isTrue;
var query3 = new CarQuery()..where.description.equals('Submarine'); var query3 = new CarQuery()..where.description.equals('Submarine');
query1 var union = query1.union(query2).unionAll(query3);
..union(query2) print(union.compile());
..unionAll(query3); var cars = await union.get(connection);
print(query1.compile());
var cars = await query1.get(connection);
expect(cars, hasLength(1)); expect(cars, hasLength(1));
}); });
test('or clause', () async { test('or clause', () async {
var query = new CarQuery() var query = new CarQuery()
..where.make.like('Fer%') ..where.make.like('Fer%')
..orWhere((where) => ..orWhere((where) => where
where..familyFriendly.equals(true)..make.equals('Honda')); ..familyFriendly.isTrue
..make.equals('Honda'));
print(query.compile()); print(query.compile());
var cars = await query.get(connection); var cars = await query.get(connection);
expect(cars, hasLength(1)); expect(cars, hasLength(1));
@ -132,25 +124,28 @@ main() {
test('delete stream', () async { test('delete stream', () async {
var query = new CarQuery() var query = new CarQuery()
..where.make.equals('Ferrari') ..where.make.equals('Ferrari東')
..orWhere((w) => w.familyFriendly.equals(true)); ..orWhere((w) => w.familyFriendly.isTrue);
print(query.compile(preamble: 'DELETE FROM "cars"')); print(query.compile(preamble: 'DELETE FROM "cars"'));
var cars = await query.get(connection);
var cars = await query.delete(connection);
expect(cars, hasLength(1)); expect(cars, hasLength(1));
expect(cars.first.toJson(), ferrari.toJson()); expect(cars.first.toJson(), ferrari.toJson());
}); });
test('update', () async { test('update', () async {
var query = new CarQuery()..where.id.equals(int.parse(ferrari.id)); var query = new CarQuery()
var cars = await query.update(connection, make: 'Hyundai'); ..where.id.equals(int.parse(ferrari.id))
..values.make = 'Hyundai';
var cars = await query.update(connection);
expect(cars, hasLength(1)); expect(cars, hasLength(1));
expect(cars.first.make, 'Hyundai'); expect(cars.first.make, 'Hyundai');
}); });
test('update car', () async { test('update car', () async {
var cloned = ferrari.copyWith(make: 'Angel'); var cloned = ferrari.copyWith(make: 'Angel');
var car = await CarQuery.updateCar(connection, cloned); var query = new CarQuery()..values.copyFrom(cloned);
var car = await query.updateOne(connection);
print(car.toJson()); print(car.toJson());
expect(car.toJson(), cloned.toJson()); expect(car.toJson(), cloned.toJson());
}); });
@ -159,11 +154,13 @@ main() {
test('insert', () async { test('insert', () async {
var recalledAt = new DateTime.now(); var recalledAt = new DateTime.now();
var car = await CarQuery.insert(connection, var query = new CarQuery();
make: 'Honda', query.values
description: 'Hello', ..make = 'Honda'
familyFriendly: true, ..description = 'Hello'
recalledAt: recalledAt); ..familyFriendly = true
..recalledAt = recalledAt;
var car = await query.insert(connection);
expect(car.id, isNotNull); expect(car.id, isNotNull);
expect(car.make, 'Honda'); expect(car.make, 'Honda');
expect(car.description, 'Hello'); expect(car.description, 'Hello');
@ -179,7 +176,8 @@ main() {
description: 'Herbie', description: 'Herbie',
familyFriendly: true, familyFriendly: true,
recalledAt: recalledAt); recalledAt: recalledAt);
var car = await CarQuery.insertCar(connection, beetle); var query = new CarQuery()..values.copyFrom(beetle);
var car = await query.insert(connection);
print(car.toJson()); print(car.toJson());
expect(car.make, beetle.make); expect(car.make, beetle.make);
expect(car.description, beetle.description); expect(car.description, beetle.description);