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
* Add `delete`, `insert` and `update` methods to `Query`.

View file

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

View file

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

View file

@ -1,7 +1,10 @@
import 'dart:async';
import 'package:charcode/ascii.dart';
import 'annotations.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.
abstract class QueryBase<T> {
/// The list of fields returned by this query.
@ -18,9 +21,7 @@ abstract class QueryBase<T> {
Future<List<T>> get(QueryExecutor executor) async {
var sql = compile();
return executor
.query(sql, fields)
.then((it) => it.map(deserialize).toList());
return executor.query(sql).then((it) => it.map(deserialize).toList());
}
Future<T> getOne(QueryExecutor executor) {
@ -47,14 +48,33 @@ class OrderBy {
String toSql(Object obj) {
if (obj is DateTime) {
return dateYmdHms.format(obj);
return "'${dateYmdHms.format(obj)}'";
} else if (obj is bool) {
return obj ? 'TRUE' : 'FALSE';
} else if (obj == null) {
return 'NULL';
} else if (obj is String) {
// TODO: Proper escapes
return obj;
var b = new StringBuffer();
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 {
return obj.toString();
}
@ -174,7 +194,8 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
@override
String compile({bool includeTableName: false, String preamble}) {
var b = new StringBuffer(preamble ?? 'SELECT ');
var b = new StringBuffer(preamble ?? 'SELECT');
b.write(' ');
var f = fields ?? ['*'];
if (includeTableName) f = f.map((s) => '$tableName.$s').toList();
b.write(f.join(', '));
@ -210,21 +231,19 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
}
Future<T> insert(QueryExecutor executor) {
var sql = new StringBuffer('INSERT INTO $tableName ($fieldSet)');
var valuesClause = values.compileForInsert();
var sql = values.compileInsert(tableName);
if (valuesClause == null) {
if (sql == null) {
throw new StateError('No values have been specified for update.');
} else {
sql.write(' $valuesClause');
return executor
.query(sql.toString(), fields)
.query(sql, fields)
.then((it) => it.isEmpty ? null : deserialize(it.first));
}
}
Future<List<T>> update(QueryExecutor executor) async {
var sql = new StringBuffer('UPDATE $tableName');
var sql = new StringBuffer('UPDATE $tableName ');
var valuesClause = values.compileForUpdate();
if (valuesClause == null) {
@ -249,10 +268,12 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
abstract class QueryValues {
Map<String, dynamic> toMap();
String compileForInsert() {
String compileInsert(String tableName) {
var data = toMap();
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;
for (var entry in data.entries) {
@ -318,7 +339,12 @@ abstract class QueryWhere {
if (tableName != null) key = '$tableName.$key';
if (builder.hasValue) {
if (i++ > 0) b.write(' AND ');
b.write('$key ${builder.compile()}');
if (builder is DateTimeSqlExpressionBuilder) {
if (tableName != null) b.write('$tableName.');
b.write(builder.compile());
} else {
b.write('$key ${builder.compile()}');
}
}
}
@ -411,5 +437,5 @@ class JoinOn {
abstract class 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
version: 2.0.0-dev.6
version: 2.0.0-dev.9
description: Runtime support for Angel's ORM. Includes base classes for queries.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/orm
environment:
sdk: '>=2.0.0-dev.1.2 <3.0.0'
dependencies:
charcode: ^1.0.0
intl: ^0.15.7
meta: ^1.0.0
string_scanner: ^1.0.0
@ -13,4 +14,5 @@ dev_dependencies:
angel_model: ^1.0.0
angel_serialize: ^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
lib.body.add(buildQueryClass(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
clazz.methods.add(new Method((m) {
m
@ -101,6 +113,15 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..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()
clazz.methods.add(new Method((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
version: 2.0.0-dev
description: Code generators for Angel's ORM.
version: 2.0.0-alpha
description: Code generators for Angel's ORM. Generates query builder classes.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/orm
environment:

View file

@ -10,8 +10,7 @@ Future<PostgresExecutor> connectToPostgres(Iterable<String> schemas) async {
await conn.open();
for (var s in schemas)
await conn
.execute(await new File('test/models/$s.up.g.sql').readAsString());
await conn.execute(await new File('test/migrations/$s.sql').readAsString());
return new PostgresExecutor(conn);
}
@ -24,9 +23,14 @@ class PostgresExecutor extends QueryExecutor {
Future close() => connection.close();
@override
Future<List<List>> query(String query, List<String> returningFields) {
var fields = returningFields.join(', ');
var returning = 'RETURNING ($fields)';
return connection.query('$query $returning');
Future<List<List>> query(String query, [List<String> returningFields]) {
if (returningFields != null) {
var fields = returningFields.join(', ');
var returning = 'RETURNING $fields';
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> {
@override
final AuthorQueryValues values = new AuthorQueryValues();
@override
final AuthorQueryWhere where = new AuthorQueryWhere();
@ -20,6 +23,11 @@ class AuthorQuery extends Query<Author, AuthorQueryWhere> {
return AuthorFields.allFields;
}
@override
AuthorQueryWhere newWhereClause() {
return new AuthorQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm.generator.models.car;
// **************************************************************************
class CarQuery extends Query<Car, CarQueryWhere> {
@override
final CarQueryValues values = new CarQueryValues();
@override
final CarQueryWhere where = new CarQueryWhere();
@ -20,6 +23,11 @@ class CarQuery extends Query<Car, CarQueryWhere> {
return CarFields.allFields;
}
@override
CarQueryWhere newWhereClause() {
return new CarQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.customer;
// **************************************************************************
class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
@override
final CustomerQueryValues values = new CustomerQueryValues();
@override
final CustomerQueryWhere where = new CustomerQueryWhere();
@ -20,6 +23,11 @@ class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
return CustomerFields.allFields;
}
@override
CustomerQueryWhere newWhereClause() {
return new CustomerQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.foot;
// **************************************************************************
class FootQuery extends Query<Foot, FootQueryWhere> {
@override
final FootQueryValues values = new FootQueryValues();
@override
final FootQueryWhere where = new FootQueryWhere();
@ -20,6 +23,11 @@ class FootQuery extends Query<Foot, FootQueryWhere> {
return FootFields.allFields;
}
@override
FootQueryWhere newWhereClause() {
return new FootQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.fruit;
// **************************************************************************
class FruitQuery extends Query<Fruit, FruitQueryWhere> {
@override
final FruitQueryValues values = new FruitQueryValues();
@override
final FruitQueryWhere where = new FruitQueryWhere();
@ -20,6 +23,11 @@ class FruitQuery extends Query<Fruit, FruitQueryWhere> {
return FruitFields.allFields;
}
@override
FruitQueryWhere newWhereClause() {
return new FruitQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.order;
// **************************************************************************
class OrderQuery extends Query<Order, OrderQueryWhere> {
@override
final OrderQueryValues values = new OrderQueryValues();
@override
final OrderQueryWhere where = new OrderQueryWhere();
@ -20,6 +23,11 @@ class OrderQuery extends Query<Order, OrderQueryWhere> {
return OrderFields.allFields;
}
@override
OrderQueryWhere newWhereClause() {
return new OrderQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

@ -7,6 +7,9 @@ part of angel_orm_generator.test.models.role;
// **************************************************************************
class RoleQuery extends Query<Role, RoleQueryWhere> {
@override
final RoleQueryValues values = new RoleQueryValues();
@override
final RoleQueryWhere where = new RoleQueryWhere();
@ -20,6 +23,11 @@ class RoleQuery extends Query<Role, RoleQueryWhere> {
return RoleFields.allFields;
}
@override
RoleQueryWhere newWhereClause() {
return new RoleQueryWhere();
}
@override
deserialize(List row) {
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
// **************************************************************************

View file

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