All static methods working...
This commit is contained in:
parent
2ecb60f16e
commit
2d6ec2ed17
16 changed files with 468 additions and 189 deletions
15
README.md
15
README.md
|
@ -5,16 +5,14 @@
|
||||||
**This project is currently in the early stages, and may change at any given
|
**This project is currently in the early stages, and may change at any given
|
||||||
time without warning.**
|
time without warning.**
|
||||||
|
|
||||||
Source-generated ORM for use with the Angel framework. Documentation is coming soon.
|
Source-generated PostgreSQL ORM for use with the
|
||||||
This ORM can work with virtually any database, thanks to the functionality exposed by
|
[Angel framework](https://angel-dart.github.io).
|
||||||
`package:query_builder`.
|
Now you can combine the power and flexibility of Angel with a strongly-typed ORM.
|
||||||
|
|
||||||
Currently supported:
|
Currently supported:
|
||||||
* PostgreSQL
|
* PostgreSQL
|
||||||
* MongoDB (planned)
|
|
||||||
* RethinkDB (planned)
|
|
||||||
* In-Memory (planned)
|
|
||||||
|
|
||||||
|
# Models
|
||||||
Your model, courtesy of `package:angel_serialize`:
|
Your model, courtesy of `package:angel_serialize`:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
|
@ -35,11 +33,12 @@ class _Car extends Model {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Models can still use the `@Alias()` annotation. `package:angel_orm` obeys it.
|
Models can use the `@Alias()` annotation; `package:angel_orm` obeys it.
|
||||||
|
|
||||||
After building, you'll have access to a `Query` class with strongly-typed methods that
|
After building, you'll have access to a `Query` class with strongly-typed methods that
|
||||||
allow to run asynchronous queries without a headache.
|
allow to run asynchronous queries without a headache.
|
||||||
You can run complex queries like:
|
|
||||||
|
MVC just got a whole lot easier:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
|
|
@ -96,7 +96,7 @@ PostgresBuildContext buildContext(
|
||||||
column = const Column(type: ColumnType.NUMERIC);
|
column = const Column(type: ColumnType.NUMERIC);
|
||||||
break;
|
break;
|
||||||
case 'bool':
|
case 'bool':
|
||||||
column = const Column(type: ColumnType.BIT);
|
column = const Column(type: ColumnType.BOOLEAN);
|
||||||
break;
|
break;
|
||||||
case 'DateTime':
|
case 'DateTime':
|
||||||
column = const Column(type: ColumnType.TIME_STAMP);
|
column = const Column(type: ColumnType.TIME_STAMP);
|
||||||
|
|
|
@ -19,14 +19,19 @@ import 'postgres_build_context.dart';
|
||||||
|
|
||||||
// TODO: HasOne, HasMany, BelongsTo
|
// TODO: HasOne, HasMany, BelongsTo
|
||||||
class SQLMigrationGenerator implements Builder {
|
class SQLMigrationGenerator implements Builder {
|
||||||
/// If "true" (default), then field names will automatically be (de)serialized as snake_case.
|
/// If `true` (default), then field names will automatically be (de)serialized as snake_case.
|
||||||
final bool autoSnakeCaseNames;
|
final bool autoSnakeCaseNames;
|
||||||
|
|
||||||
/// If "true" (default), then
|
/// If `true` (default), then the schema will automatically add id, created_at and updated_at fields.
|
||||||
final bool autoIdAndDateFields;
|
final bool autoIdAndDateFields;
|
||||||
|
|
||||||
|
/// If `true` (default: `false`), then the resulting schema will generate a `TEMPORARY` table.
|
||||||
|
final bool temporary;
|
||||||
|
|
||||||
const SQLMigrationGenerator(
|
const SQLMigrationGenerator(
|
||||||
{this.autoSnakeCaseNames: true, this.autoIdAndDateFields: true});
|
{this.autoSnakeCaseNames: true,
|
||||||
|
this.autoIdAndDateFields: true,
|
||||||
|
this.temporary: false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Map<String, List<String>> get buildExtensions => {
|
Map<String, List<String>> get buildExtensions => {
|
||||||
|
@ -80,7 +85,10 @@ class SQLMigrationGenerator implements Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildUpMigration(PostgresBuildContext ctx, StringBuffer buf) {
|
void buildUpMigration(PostgresBuildContext ctx, StringBuffer buf) {
|
||||||
buf.writeln('CREATE TABLE "${ctx.tableName}" (');
|
if (temporary == true)
|
||||||
|
buf.writeln('CREATE TEMPORARY TABLE "${ctx.tableName}" (');
|
||||||
|
else
|
||||||
|
buf.writeln('CREATE TABLE "${ctx.tableName}" (');
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ctx.columnInfo.forEach((name, col) {
|
ctx.columnInfo.forEach((name, col) {
|
||||||
|
|
|
@ -17,6 +17,8 @@ import 'package:angel_serialize/src/find_annotation.dart';
|
||||||
import 'build_context.dart';
|
import 'build_context.dart';
|
||||||
import 'postgres_build_context.dart';
|
import 'postgres_build_context.dart';
|
||||||
|
|
||||||
|
const List<String> RELATIONS = const ['and', 'or', 'not'];
|
||||||
|
|
||||||
// TODO: HasOne, HasMany, BelongsTo
|
// TODO: HasOne, HasMany, BelongsTo
|
||||||
class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
/// If "true" (default), then field names will automatically be (de)serialized as snake_case.
|
/// If "true" (default), then field names will automatically be (de)serialized as snake_case.
|
||||||
|
@ -102,7 +104,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
var connection = reference('connection');
|
var connection = reference('connection');
|
||||||
|
|
||||||
// Add or + not
|
// Add or + not
|
||||||
for (var relation in ['and', 'or', 'not']) {
|
for (var relation in RELATIONS) {
|
||||||
clazz.addField(varFinal('_$relation',
|
clazz.addField(varFinal('_$relation',
|
||||||
type: new TypeBuilder('List', genericTypes: [lib$core.String]),
|
type: new TypeBuilder('List', genericTypes: [lib$core.String]),
|
||||||
value: list([])));
|
value: list([])));
|
||||||
|
@ -112,8 +114,9 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
parameter('other', [new TypeBuilder(ctx.queryClassName)]));
|
parameter('other', [new TypeBuilder(ctx.queryClassName)]));
|
||||||
var otherWhere = reference('other').property('where');
|
var otherWhere = reference('other').property('where');
|
||||||
var compiled = reference('compiled');
|
var compiled = reference('compiled');
|
||||||
relationMethod.addStatement(
|
relationMethod.addStatement(varField('compiled',
|
||||||
varField('compiled', value: otherWhere.invoke('toWhereClause', [])));
|
value: otherWhere.invoke('toWhereClause', [],
|
||||||
|
namedArguments: {'keyword': literal(false)})));
|
||||||
relationMethod.addStatement(ifThen(compiled.notEquals(literal(null)), [
|
relationMethod.addStatement(ifThen(compiled.notEquals(literal(null)), [
|
||||||
reference('_$relation').invoke('add', [compiled])
|
reference('_$relation').invoke('add', [compiled])
|
||||||
]));
|
]));
|
||||||
|
@ -142,9 +145,12 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
// Add update()...
|
// Add update()...
|
||||||
clazz.addMethod(buildUpdateMethod(ctx));
|
clazz.addMethod(buildUpdateMethod(ctx));
|
||||||
|
|
||||||
// Add remove()...
|
// Add delete()...
|
||||||
clazz.addMethod(buildDeleteMethod(ctx));
|
clazz.addMethod(buildDeleteMethod(ctx));
|
||||||
|
|
||||||
|
// Add deleteOne()...
|
||||||
|
clazz.addMethod(buildDeleteOneMethod(ctx), asStatic: true);
|
||||||
|
|
||||||
// Add insert()...
|
// Add insert()...
|
||||||
clazz.addMethod(buildInsertMethod(ctx), asStatic: true);
|
clazz.addMethod(buildInsertMethod(ctx), asStatic: true);
|
||||||
|
|
||||||
|
@ -176,6 +182,16 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
buf.invoke('write', [literal(' ') + whereClause])
|
buf.invoke('write', [literal(' ') + whereClause])
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
for (var relation in RELATIONS) {
|
||||||
|
var ref = reference('_$relation');
|
||||||
|
var upper = relation.toUpperCase();
|
||||||
|
var joined = ref.invoke('join', [literal(',')]);
|
||||||
|
|
||||||
|
meth.addStatement(ifThen(ref.property('isNotEmpty'), [
|
||||||
|
buf.invoke('write', [literal(' $upper (') + joined + literal(')')])
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
meth.addStatement(buf.invoke('write', [literal(';')]));
|
meth.addStatement(buf.invoke('write', [literal(';')]));
|
||||||
meth.addStatement(buf.invoke('toString', []).asReturn());
|
meth.addStatement(buf.invoke('toString', []).asReturn());
|
||||||
|
|
||||||
|
@ -200,14 +216,18 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
var name = ctx.resolveFieldName(field.name);
|
var name = ctx.resolveFieldName(field.name);
|
||||||
var rowKey = row[literal(i++)];
|
var rowKey = row[literal(i++)];
|
||||||
|
|
||||||
if (field.type.isAssignableTo(ctx.dateTimeType)) {
|
/* if (field.type.isAssignableTo(ctx.dateTimeType)) {
|
||||||
// TODO: Handle DATE and not just DATETIME
|
// TODO: Handle DATE and not just DATETIME
|
||||||
data[name] = DATE_YMD_HMS.invoke('parse', [rowKey]);
|
data[name] = DATE_YMD_HMS.invoke('parse', [rowKey]);
|
||||||
} else if (field.name == 'id' && ctx.shimmed.containsKey('id')) {
|
|
||||||
data[name] = rowKey.invoke('toString', []);
|
|
||||||
} else if (field.type.isAssignableTo(ctx.typeProvider.boolType)) {
|
|
||||||
data[name] = rowKey.equals(literal(1));
|
|
||||||
} else
|
} else
|
||||||
|
*/
|
||||||
|
if (field.name == 'id' && ctx.shimmed.containsKey('id')) {
|
||||||
|
data[name] = rowKey.invoke('toString', []);
|
||||||
|
} /* else if (field.type.isAssignableTo(ctx.typeProvider.boolType)) {
|
||||||
|
// TODO: Find out what date is returned as
|
||||||
|
data[name] = rowKey.equals(literal(1));
|
||||||
|
}*/
|
||||||
|
else
|
||||||
data[name] = rowKey;
|
data[name] = rowKey;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -229,20 +249,9 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildGetMethod(PostgresBuildContext ctx) {
|
void _invokeStreamClosure(ExpressionBuilder future, MethodBuilder meth) {
|
||||||
var meth = new MethodBuilder('get',
|
var ctrl = reference('ctrl');
|
||||||
returnType: new TypeBuilder('Stream',
|
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
|
||||||
meth.addPositional(
|
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
|
||||||
var streamController = new TypeBuilder('StreamController',
|
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
|
||||||
var ctrl = reference('ctrl'), connection = reference('connection');
|
|
||||||
meth.addStatement(varField('ctrl',
|
|
||||||
type: streamController, value: streamController.newInstance([])));
|
|
||||||
|
|
||||||
// Invoke query...
|
// Invoke query...
|
||||||
var future = connection.invoke('query', [reference('toSql').call([])]);
|
|
||||||
var catchError = ctrl.property('addError');
|
var catchError = ctrl.property('addError');
|
||||||
var then = new MethodBuilder.closure()..addPositional(parameter('rows'));
|
var then = new MethodBuilder.closure()..addPositional(parameter('rows'));
|
||||||
then.addStatement(reference('rows')
|
then.addStatement(reference('rows')
|
||||||
|
@ -252,6 +261,22 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
meth.addStatement(
|
meth.addStatement(
|
||||||
future.invoke('then', [then]).invoke('catchError', [catchError]));
|
future.invoke('then', [then]).invoke('catchError', [catchError]));
|
||||||
meth.addStatement(ctrl.property('stream').asReturn());
|
meth.addStatement(ctrl.property('stream').asReturn());
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodBuilder buildGetMethod(PostgresBuildContext ctx) {
|
||||||
|
var meth = new MethodBuilder('get',
|
||||||
|
returnType: new TypeBuilder('Stream',
|
||||||
|
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||||
|
meth.addPositional(
|
||||||
|
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||||
|
var streamController = new TypeBuilder('StreamController',
|
||||||
|
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
||||||
|
meth.addStatement(varField('ctrl',
|
||||||
|
type: streamController, value: streamController.newInstance([])));
|
||||||
|
|
||||||
|
var future =
|
||||||
|
reference('connection').invoke('query', [reference('toSql').call([])]);
|
||||||
|
_invokeStreamClosure(future, meth);
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,26 +349,18 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
return substitutionValues;
|
return substitutionValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _executeQuery(StringBuffer buf, MethodBuilder meth,
|
ExpressionBuilder _executeQuery(ExpressionBuilder queryString,
|
||||||
Map<String, ExpressionBuilder> substitutionValues) {
|
MethodBuilder meth, Map<String, ExpressionBuilder> substitutionValues) {
|
||||||
var connection = reference('connection');
|
var connection = reference('connection');
|
||||||
var query = literal(buf.toString());
|
var query = queryString;
|
||||||
var result = reference('result');
|
return connection.invoke('query', [query],
|
||||||
meth.addStatement(varField('result',
|
namedArguments: {'substitutionValues': map(substitutionValues)});
|
||||||
value: connection.invoke('query', [
|
|
||||||
query
|
|
||||||
], namedArguments: {
|
|
||||||
'substitutionValues': map(substitutionValues)
|
|
||||||
}).asAwait()));
|
|
||||||
meth.addStatement(reference('parseRow').call([result]).asReturn());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildUpdateMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildUpdateMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('update',
|
var meth = new MethodBuilder('update',
|
||||||
modifier: MethodModifier.asAsync,
|
returnType: new TypeBuilder('Stream',
|
||||||
returnType: new TypeBuilder('Future',
|
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||||
meth.addPositional(parameter('id', [lib$core.int]));
|
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||||
_addAllNamed(meth, ctx);
|
_addAllNamed(meth, ctx);
|
||||||
|
@ -369,18 +386,49 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
buf.write('@${field.name}');
|
buf.write('@${field.name}');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
buf.write(') WHERE "id" = @id');
|
buf.write(') ');
|
||||||
|
|
||||||
_addReturning(buf, ctx);
|
var $buf = reference('buf');
|
||||||
|
var whereClause = reference('whereClause');
|
||||||
|
meth.addStatement(varField('buf',
|
||||||
|
value: lib$core.StringBuffer.newInstance([literal(buf.toString())])));
|
||||||
|
meth.addStatement(varField('whereClause',
|
||||||
|
value: reference('where').invoke('toWhereClause', [])));
|
||||||
|
|
||||||
|
meth.addStatement(ifThen(whereClause.equals(literal(null)), [
|
||||||
|
$buf.invoke('write', [literal('WHERE "id" = @id')]),
|
||||||
|
elseThen([
|
||||||
|
$buf.invoke('write', [whereClause])
|
||||||
|
])
|
||||||
|
]));
|
||||||
|
|
||||||
|
var buf2 = new StringBuffer();
|
||||||
|
_addReturning(buf2, ctx);
|
||||||
_ensureDates(meth, ctx);
|
_ensureDates(meth, ctx);
|
||||||
var substitutionValues = _buildSubstitutionValues(ctx);
|
var substitutionValues = _buildSubstitutionValues(ctx);
|
||||||
substitutionValues.putIfAbsent('id', () => reference('id'));
|
|
||||||
_executeQuery(buf, meth, substitutionValues);
|
var ctrlType = new TypeBuilder('StreamController',
|
||||||
|
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
||||||
|
meth.addStatement(varField('ctrl', value: ctrlType.newInstance([])));
|
||||||
|
var result = _executeQuery(
|
||||||
|
$buf.invoke('toString', []) + literal(buf2.toString()),
|
||||||
|
meth,
|
||||||
|
substitutionValues);
|
||||||
|
_invokeStreamClosure(result, meth);
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildDeleteMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildDeleteMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('delete',
|
var meth = new MethodBuilder('delete',
|
||||||
|
returnType: new TypeBuilder('Stream',
|
||||||
|
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||||
|
meth.addPositional(
|
||||||
|
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||||
|
return meth;
|
||||||
|
}
|
||||||
|
|
||||||
|
MethodBuilder buildDeleteOneMethod(PostgresBuildContext ctx) {
|
||||||
|
var meth = new MethodBuilder('deleteOne',
|
||||||
modifier: MethodModifier.asAsync,
|
modifier: MethodModifier.asAsync,
|
||||||
returnType: new TypeBuilder('Future',
|
returnType: new TypeBuilder('Future',
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]))
|
genericTypes: [new TypeBuilder(ctx.modelClassName)]))
|
||||||
|
@ -401,7 +449,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
// await connection.execute('...');
|
// await connection.execute('...');
|
||||||
meth.addStatement(varField('result',
|
meth.addStatement(varField('result',
|
||||||
value: connection.invoke('execute', [
|
value: connection.invoke('execute', [
|
||||||
literal('DELETE FROM "${ctx.tableName}" WHERE id = @id LIMIT 1;')
|
literal('DELETE FROM "${ctx.tableName}" WHERE id = @id;')
|
||||||
], namedArguments: {
|
], namedArguments: {
|
||||||
'substitutionValues': map({'id': id})
|
'substitutionValues': map({'id': id})
|
||||||
}).asAwait()));
|
}).asAwait()));
|
||||||
|
@ -453,15 +501,43 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
buf.write(')');
|
buf.write(');');
|
||||||
|
|
||||||
_addReturning(buf, ctx);
|
|
||||||
// meth.addStatement(lib$core.print.call([literal(buf.toString())]));
|
// meth.addStatement(lib$core.print.call([literal(buf.toString())]));
|
||||||
|
|
||||||
_ensureDates(meth, ctx);
|
_ensureDates(meth, ctx);
|
||||||
|
|
||||||
var substitutionValues = _buildSubstitutionValues(ctx);
|
var substitutionValues = _buildSubstitutionValues(ctx);
|
||||||
_executeQuery(buf, meth, substitutionValues);
|
|
||||||
|
// connection.execute...
|
||||||
|
var connection = reference('connection'), nRows = reference('nRows');
|
||||||
|
meth.addStatement(varField('nRows',
|
||||||
|
value: connection.invoke('execute', [
|
||||||
|
literal(buf.toString())
|
||||||
|
], namedArguments: {
|
||||||
|
'substitutionValues': map(substitutionValues)
|
||||||
|
}).asAwait()));
|
||||||
|
|
||||||
|
meth.addStatement(ifThen(nRows < literal(1), [
|
||||||
|
lib$core.StateError.newInstance([
|
||||||
|
literal('Insertion into "${ctx.tableName}" table failed.')
|
||||||
|
]).asThrow()
|
||||||
|
]));
|
||||||
|
|
||||||
|
// Query the last value...
|
||||||
|
/*
|
||||||
|
var currval = await connection.query("SELECT * FROM cars WHERE id = currval(pg_get_serial_sequence('cars', 'id'));");
|
||||||
|
print(currval);
|
||||||
|
return parseRow(currval[0]);
|
||||||
|
*/
|
||||||
|
|
||||||
|
var currVal = reference('currVal');
|
||||||
|
meth.addStatement(varField('currVal',
|
||||||
|
value: connection.invoke('query', [
|
||||||
|
literal(
|
||||||
|
'SELECT * FROM "${ctx.tableName}" WHERE id = currval(pg_get_serial_sequence(\'${ctx.tableName}\', \'id\'));')
|
||||||
|
]).asAwait()));
|
||||||
|
meth.addStatement(
|
||||||
|
reference('parseRow').call([currVal[literal(0)]]).asReturn());
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,28 +548,33 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
TypeBuilder queryBuilderType;
|
TypeBuilder queryBuilderType;
|
||||||
List<ExpressionBuilder> args = [];
|
List<ExpressionBuilder> args = [];
|
||||||
|
|
||||||
switch (field.type.name) {
|
if (field.name == 'id') {
|
||||||
case 'String':
|
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder',
|
||||||
queryBuilderType = new TypeBuilder('StringSqlExpressionBuilder');
|
genericTypes: [lib$core.int]);
|
||||||
break;
|
} else {
|
||||||
case 'int':
|
switch (field.type.name) {
|
||||||
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder',
|
case 'String':
|
||||||
genericTypes: [lib$core.int]);
|
queryBuilderType = new TypeBuilder('StringSqlExpressionBuilder');
|
||||||
break;
|
break;
|
||||||
case 'double':
|
case 'int':
|
||||||
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder',
|
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder',
|
||||||
genericTypes: [new TypeBuilder('double')]);
|
genericTypes: [lib$core.int]);
|
||||||
break;
|
break;
|
||||||
case 'num':
|
case 'double':
|
||||||
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder');
|
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder',
|
||||||
break;
|
genericTypes: [new TypeBuilder('double')]);
|
||||||
case 'bool':
|
break;
|
||||||
queryBuilderType = new TypeBuilder('BooleanSqlExpressionBuilder');
|
case 'num':
|
||||||
break;
|
queryBuilderType = new TypeBuilder('NumericSqlExpressionBuilder');
|
||||||
case 'DateTime':
|
break;
|
||||||
queryBuilderType = new TypeBuilder('DateTimeSqlExpressionBuilder');
|
case 'bool':
|
||||||
args.add(literal(ctx.resolveFieldName(field.name)));
|
queryBuilderType = new TypeBuilder('BooleanSqlExpressionBuilder');
|
||||||
break;
|
break;
|
||||||
|
case 'DateTime':
|
||||||
|
queryBuilderType = new TypeBuilder('DateTimeSqlExpressionBuilder');
|
||||||
|
args.add(literal(ctx.resolveFieldName(field.name)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryBuilderType == null)
|
if (queryBuilderType == null)
|
||||||
|
@ -505,6 +586,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
// Create "toWhereClause()"
|
// Create "toWhereClause()"
|
||||||
var toWhereClause =
|
var toWhereClause =
|
||||||
new MethodBuilder('toWhereClause', returnType: lib$core.String);
|
new MethodBuilder('toWhereClause', returnType: lib$core.String);
|
||||||
|
toWhereClause.addNamed(parameter('keyword', [lib$core.bool]));
|
||||||
|
|
||||||
// List<String> expressions = [];
|
// List<String> expressions = [];
|
||||||
toWhereClause.addStatement(varFinal('expressions',
|
toWhereClause.addStatement(varFinal('expressions',
|
||||||
|
@ -525,13 +607,16 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var kw = reference('keyword')
|
||||||
|
.notEquals(literal(false))
|
||||||
|
.ternary(literal('WHERE '), literal(''))
|
||||||
|
.parentheses();
|
||||||
|
|
||||||
// return expressions.isEmpty ? null : ('WHERE ' + expressions.join(' AND '));
|
// return expressions.isEmpty ? null : ('WHERE ' + expressions.join(' AND '));
|
||||||
toWhereClause.addStatement(expressions
|
toWhereClause.addStatement(expressions
|
||||||
.property('isEmpty')
|
.property('isEmpty')
|
||||||
.ternary(
|
.ternary(literal(null),
|
||||||
literal(null),
|
(kw + expressions.invoke('join', [literal(' AND ')])).parentheses())
|
||||||
(literal('WHERE ') + expressions.invoke('join', [literal(' AND ')]))
|
|
||||||
.parentheses())
|
|
||||||
.asReturn());
|
.asReturn());
|
||||||
|
|
||||||
clazz.addMethod(toWhereClause);
|
clazz.addMethod(toWhereClause);
|
||||||
|
|
|
@ -220,9 +220,9 @@ class AngelQueryBuilderGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
//
|
//
|
||||||
// var requestedKeys = whereFields.keys.isNotEmpty ? whereFields.keys : [<all fields...>];
|
// var requestedKeys = whereFields.keys.isNotEmpty ? whereFields.keys : [<all fields...>];
|
||||||
|
|
||||||
var allModelFields = clazz.fields
|
//var allModelFields = clazz.fields
|
||||||
.map((f) => aliases.containsKey(f.name) ? aliases[f.name] : f.name);
|
// .map((f) => aliases.containsKey(f.name) ? aliases[f.name] : f.name);
|
||||||
var whereFieldsKeys = reference('whereFields').property('keys');
|
//var whereFieldsKeys = reference('whereFields').property('keys');
|
||||||
|
|
||||||
// return new Stream<>.fromFuture(...)
|
// return new Stream<>.fromFuture(...)
|
||||||
meth.addStatement(lib$async.Stream.newInstance([
|
meth.addStatement(lib$async.Stream.newInstance([
|
||||||
|
|
|
@ -58,6 +58,8 @@ class ColumnType {
|
||||||
final String name;
|
final String name;
|
||||||
const ColumnType._(this.name);
|
const ColumnType._(this.name);
|
||||||
|
|
||||||
|
static const ColumnType BOOLEAN = const ColumnType._('boolean');
|
||||||
|
|
||||||
static const ColumnType SMALL_SERIAL = const ColumnType._('smallserial');
|
static const ColumnType SMALL_SERIAL = const ColumnType._('smallserial');
|
||||||
static const ColumnType SERIAL = const ColumnType._('serial');
|
static const ColumnType SERIAL = const ColumnType._('serial');
|
||||||
static const ColumnType BIG_SERIAL = const ColumnType._('bigserial');
|
static const ColumnType BIG_SERIAL = const ColumnType._('bigserial');
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
|
||||||
final DateFormat DATE_YMD = new DateFormat('yyyy-MM-dd');
|
final DateFormat DATE_YMD = new DateFormat('yyyy-MM-dd');
|
||||||
final DateFormat DATE_YMD_HMS = new DateFormat('yyyy-MM-dd HH:mm:ss');
|
final DateFormat DATE_YMD_HMS = new DateFormat('yyyy-MM-dd HH:mm:ss');
|
||||||
|
|
||||||
|
@ -78,7 +77,8 @@ class StringSqlExpressionBuilder implements SqlExpressionBuilder {
|
||||||
@override
|
@override
|
||||||
String compile() {
|
String compile() {
|
||||||
if (_value == null) return null;
|
if (_value == null) return null;
|
||||||
return '$_op `$_value`';
|
var v = _value.replaceAll("'", "\\'");
|
||||||
|
return "$_op '$v'";
|
||||||
}
|
}
|
||||||
|
|
||||||
void isEmpty() => equals('');
|
void isEmpty() => equals('');
|
||||||
|
@ -113,7 +113,7 @@ class BooleanSqlExpressionBuilder implements SqlExpressionBuilder {
|
||||||
@override
|
@override
|
||||||
String compile() {
|
String compile() {
|
||||||
if (_value == null) return null;
|
if (_value == null) return null;
|
||||||
var v = _value ? 1 : 0;
|
var v = _value ? 'TRUE' : 'FALSE';
|
||||||
return '$_op $v';
|
return '$_op $v';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ class DateTimeSqlExpressionBuilder implements SqlExpressionBuilder {
|
||||||
|
|
||||||
bool _change(String _op, DateTime dt, bool time) {
|
bool _change(String _op, DateTime dt, bool time) {
|
||||||
var dateString = time ? DATE_YMD_HMS.format(dt) : DATE_YMD.format(dt);
|
var dateString = time ? DATE_YMD_HMS.format(dt) : DATE_YMD.format(dt);
|
||||||
_raw = '`$columnName` $_op \'$dateString\'';
|
_raw = '"$columnName" $_op \'$dateString\'';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,12 +184,12 @@ class DateTimeSqlExpressionBuilder implements SqlExpressionBuilder {
|
||||||
String compile() {
|
String compile() {
|
||||||
if (_raw?.isNotEmpty == true) return _raw;
|
if (_raw?.isNotEmpty == true) return _raw;
|
||||||
List<String> parts = [];
|
List<String> parts = [];
|
||||||
if (year.hasValue) parts.add('YEAR(`$columnName`) ${year.compile()}');
|
if (year.hasValue) parts.add('YEAR("$columnName") ${year.compile()}');
|
||||||
if (month.hasValue) parts.add('MONTH(`$columnName`) ${month.compile()}');
|
if (month.hasValue) parts.add('MONTH("$columnName") ${month.compile()}');
|
||||||
if (day.hasValue) parts.add('DAY(`$columnName`) ${day.compile()}');
|
if (day.hasValue) parts.add('DAY("$columnName") ${day.compile()}');
|
||||||
if (hour.hasValue) parts.add('HOUR(`$columnName`) ${hour.compile()}');
|
if (hour.hasValue) parts.add('HOUR("$columnName") ${hour.compile()}');
|
||||||
if (minute.hasValue) parts.add('MINUTE(`$columnName`) ${minute.compile()}');
|
if (minute.hasValue) parts.add('MINUTE("$columnName") ${minute.compile()}');
|
||||||
if (second.hasValue) parts.add('SECOND(`$columnName`) ${second.compile()}');
|
if (second.hasValue) parts.add('SECOND("$columnName") ${second.compile()}');
|
||||||
|
|
||||||
return parts.isEmpty ? null : parts.join(' AND ');
|
return parts.isEmpty ? null : parts.join(' AND ');
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,27 +4,11 @@ import 'package:postgres/postgres.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'models/car.dart';
|
import 'models/car.dart';
|
||||||
import 'models/car.orm.g.dart';
|
import 'models/car.orm.g.dart';
|
||||||
|
import 'common.dart';
|
||||||
|
|
||||||
final DateTime MILENNIUM = new DateTime.utc(2000, 1, 1);
|
final DateTime MILENNIUM = new DateTime.utc(2000, 1, 1);
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
PostgreSQLConnection connection;
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
connection = new PostgreSQLConnection('127.0.0.1', 0, '');
|
|
||||||
await connection.open();
|
|
||||||
|
|
||||||
// Create temp table
|
|
||||||
var query = await new File('test/models/car.sql').readAsString();
|
|
||||||
await connection.execute(query);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
// Drop `cars`
|
|
||||||
await connection.execute('DROP TABLE `cars`;');
|
|
||||||
await connection.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('to where', () {
|
test('to where', () {
|
||||||
var query = new CarQuery();
|
var query = new CarQuery();
|
||||||
query.where
|
query.where
|
||||||
|
@ -33,7 +17,7 @@ main() {
|
||||||
var whereClause = query.where.toWhereClause();
|
var whereClause = query.where.toWhereClause();
|
||||||
print('Where clause: $whereClause');
|
print('Where clause: $whereClause');
|
||||||
expect(whereClause,
|
expect(whereClause,
|
||||||
"WHERE `family_friendly` = 1 AND `recalled_at` <= '00-01-01'");
|
'WHERE "family_friendly" = TRUE AND "recalled_at" <= \'2000-01-01\'');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('parseRow', () {
|
test('parseRow', () {
|
||||||
|
@ -41,7 +25,7 @@ main() {
|
||||||
0,
|
0,
|
||||||
'Mazda',
|
'Mazda',
|
||||||
'CX9',
|
'CX9',
|
||||||
1,
|
true,
|
||||||
DATE_YMD_HMS.format(MILENNIUM),
|
DATE_YMD_HMS.format(MILENNIUM),
|
||||||
DATE_YMD_HMS.format(MILENNIUM),
|
DATE_YMD_HMS.format(MILENNIUM),
|
||||||
DATE_YMD_HMS.format(MILENNIUM)
|
DATE_YMD_HMS.format(MILENNIUM)
|
||||||
|
@ -61,5 +45,89 @@ main() {
|
||||||
startsWith(car.updatedAt.toIso8601String()));
|
startsWith(car.updatedAt.toIso8601String()));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insert', () async {});
|
group('queries', () {
|
||||||
|
PostgreSQLConnection connection;
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
connection = await connectToPostgres();
|
||||||
|
});
|
||||||
|
|
||||||
|
group('selects', () {
|
||||||
|
test('select all', () async {
|
||||||
|
var cars = await CarQuery.getAll(connection).toList();
|
||||||
|
expect(cars, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('with data', () {
|
||||||
|
Car ferrari;
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
ferrari = await CarQuery.insert(connection,
|
||||||
|
make: 'Ferrari',
|
||||||
|
description: 'Vroom vroom!',
|
||||||
|
familyFriendly: false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('where clause is applied', () async {
|
||||||
|
var query = new CarQuery()..where.familyFriendly.equals(true);
|
||||||
|
var cars = await query.get(connection).toList();
|
||||||
|
expect(cars, isEmpty);
|
||||||
|
|
||||||
|
var sportsCars = new CarQuery()..where.familyFriendly.notEquals(true);
|
||||||
|
cars = await sportsCars.get(connection).toList();
|
||||||
|
print(cars.map((c) => c.toJson()).toList());
|
||||||
|
|
||||||
|
var car = cars.first;
|
||||||
|
expect(car.make, ferrari.make);
|
||||||
|
expect(car.description, ferrari.description);
|
||||||
|
expect(car.familyFriendly, ferrari.familyFriendly);
|
||||||
|
expect(car.recalledAt, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('and clause', () async {
|
||||||
|
var query = new CarQuery()
|
||||||
|
..where.make.like('Fer%')
|
||||||
|
..and(new CarQuery()..where.familyFriendly.equals(true));
|
||||||
|
print(query.toSql());
|
||||||
|
var cars = await query.get(connection).toList();
|
||||||
|
expect(cars, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('get one', () async {
|
||||||
|
var car = await CarQuery.getOne(int.parse(ferrari.id), connection);
|
||||||
|
expect(car.toJson(), ferrari.toJson());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete one', () async {
|
||||||
|
var car = await CarQuery.deleteOne(int.parse(ferrari.id), connection);
|
||||||
|
expect(car.toJson(), ferrari.toJson());
|
||||||
|
|
||||||
|
var cars = await CarQuery.getAll(connection).toList();
|
||||||
|
expect(cars, isEmpty);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete', () async {
|
||||||
|
var query = new CarQuery();
|
||||||
|
var cars = await query.delete(connection).toList();
|
||||||
|
expect(cars, hasLength(1));
|
||||||
|
expect(cars.first.toJson(), ferrari.toJson());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('insert', () async {
|
||||||
|
var recalledAt = new DateTime.now();
|
||||||
|
var car = await CarQuery.insert(connection,
|
||||||
|
make: 'Honda',
|
||||||
|
description: 'Hello',
|
||||||
|
familyFriendly: true,
|
||||||
|
recalledAt: recalledAt);
|
||||||
|
expect(car.id, isNotNull);
|
||||||
|
expect(car.make, 'Honda');
|
||||||
|
expect(car.description, 'Hello');
|
||||||
|
expect(car.familyFriendly, isTrue);
|
||||||
|
expect(DATE_YMD_HMS.format(car.recalledAt), DATE_YMD_HMS.format(recalledAt));
|
||||||
|
expect(car.createdAt, allOf(isNotNull, equals(car.updatedAt)));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
15
test/common.dart
Normal file
15
test/common.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:postgres/postgres.dart';
|
||||||
|
|
||||||
|
Future<PostgreSQLConnection> connectToPostgres() async {
|
||||||
|
var conn = new PostgreSQLConnection('127.0.0.1', 5432, 'angel_orm_test',
|
||||||
|
username: Platform.environment['POSTGRES_USERNAME'] ?? 'postgres',
|
||||||
|
password: Platform.environment['POSTGRES_PASSWORD'] ?? 'password');
|
||||||
|
await conn.open();
|
||||||
|
|
||||||
|
var query = await new File('test/models/car.up.g.sql').readAsString();
|
||||||
|
await conn.execute(query);
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
|
@ -20,21 +20,21 @@ class AuthorQuery {
|
||||||
final AuthorQueryWhere where = new AuthorQueryWhere();
|
final AuthorQueryWhere where = new AuthorQueryWhere();
|
||||||
|
|
||||||
void and(AuthorQuery other) {
|
void and(AuthorQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_and.add(compiled);
|
_and.add(compiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void or(AuthorQuery other) {
|
void or(AuthorQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_or.add(compiled);
|
_or.add(compiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void not(AuthorQuery other) {
|
void not(AuthorQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_not.add(compiled);
|
_not.add(compiled);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,15 @@ class AuthorQuery {
|
||||||
if (whereClause != null) {
|
if (whereClause != null) {
|
||||||
buf.write(' ' + whereClause);
|
buf.write(' ' + whereClause);
|
||||||
}
|
}
|
||||||
|
if (_and.isNotEmpty) {
|
||||||
|
buf.write(' AND (' + _and.join(',') + ')');
|
||||||
|
}
|
||||||
|
if (_or.isNotEmpty) {
|
||||||
|
buf.write(' OR (' + _or.join(',') + ')');
|
||||||
|
}
|
||||||
|
if (_not.isNotEmpty) {
|
||||||
|
buf.write(' NOT (' + _not.join(',') + ')');
|
||||||
|
}
|
||||||
buf.write(';');
|
buf.write(';');
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
@ -54,8 +63,8 @@ class AuthorQuery {
|
||||||
return new Author.fromJson({
|
return new Author.fromJson({
|
||||||
'id': row[0].toString(),
|
'id': row[0].toString(),
|
||||||
'name': row[1],
|
'name': row[1],
|
||||||
'created_at': DATE_YMD_HMS.parse(row[2]),
|
'created_at': row[2],
|
||||||
'updated_at': DATE_YMD_HMS.parse(row[3])
|
'updated_at': row[3]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,24 +82,39 @@ class AuthorQuery {
|
||||||
substitutionValues: {'id': id}).then((rows) => parseRow(rows.first));
|
substitutionValues: {'id': id}).then((rows) => parseRow(rows.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Author> update(int id, PostgreSQLConnection connection,
|
Stream<Author> update(PostgreSQLConnection connection,
|
||||||
{String name, DateTime createdAt, DateTime updatedAt}) async {
|
{String name, DateTime createdAt, DateTime updatedAt}) {
|
||||||
|
var buf = new StringBuffer(
|
||||||
|
'UPDATE "authors" SET ("name", "created_at", "updated_at") = (@name, @createdAt, @updatedAt) ');
|
||||||
|
var whereClause = where.toWhereClause();
|
||||||
|
if (whereClause == null) {
|
||||||
|
buf.write('WHERE "id" = @id');
|
||||||
|
} else {
|
||||||
|
buf.write(whereClause);
|
||||||
|
}
|
||||||
var __ormNow__ = new DateTime.now();
|
var __ormNow__ = new DateTime.now();
|
||||||
var result = await connection.query(
|
var ctrl = new StreamController<Author>();
|
||||||
'UPDATE "authors" SET ("name", "created_at", "updated_at") = (@name, @createdAt, @updatedAt) WHERE "id" = @id RETURNING ("id", "name", "created_at", "updated_at");',
|
connection.query(
|
||||||
|
buf.toString() +
|
||||||
|
' RETURNING ("id", "name", "created_at", "updated_at");',
|
||||||
substitutionValues: {
|
substitutionValues: {
|
||||||
'name': name,
|
'name': name,
|
||||||
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
||||||
'updatedAt': updatedAt != null ? updatedAt : __ormNow__,
|
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
||||||
'id': id
|
}).then((rows) {
|
||||||
});
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
return parseRow(result);
|
ctrl.close();
|
||||||
|
}).catchError(ctrl.addError);
|
||||||
|
return ctrl.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Author> delete(int id, PostgreSQLConnection connection) async {
|
Stream<Author> delete(PostgreSQLConnection connection) async {}
|
||||||
|
|
||||||
|
static Future<Author> deleteOne(
|
||||||
|
int id, PostgreSQLConnection connection) async {
|
||||||
var __ormBeforeDelete__ = await AuthorQuery.getOne(id, connection);
|
var __ormBeforeDelete__ = await AuthorQuery.getOne(id, connection);
|
||||||
var result = await connection.execute(
|
var result = await connection.execute(
|
||||||
'DELETE FROM "authors" WHERE id = @id LIMIT 1;',
|
'DELETE FROM "authors" WHERE id = @id;',
|
||||||
substitutionValues: {'id': id});
|
substitutionValues: {'id': id});
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
new StateError('DELETE query deleted ' +
|
new StateError('DELETE query deleted ' +
|
||||||
|
@ -103,14 +127,19 @@ class AuthorQuery {
|
||||||
static Future<Author> insert(PostgreSQLConnection connection,
|
static Future<Author> insert(PostgreSQLConnection connection,
|
||||||
{String name, DateTime createdAt, DateTime updatedAt}) async {
|
{String name, DateTime createdAt, DateTime updatedAt}) async {
|
||||||
var __ormNow__ = new DateTime.now();
|
var __ormNow__ = new DateTime.now();
|
||||||
var result = await connection.query(
|
var nRows = await connection.execute(
|
||||||
'INSERT INTO "authors" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt) RETURNING ("id", "name", "created_at", "updated_at");',
|
'INSERT INTO "authors" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt);',
|
||||||
substitutionValues: {
|
substitutionValues: {
|
||||||
'name': name,
|
'name': name,
|
||||||
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
||||||
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
||||||
});
|
});
|
||||||
return parseRow(result);
|
if (nRows < 1) {
|
||||||
|
throw new StateError('Insertion into "authors" table failed.');
|
||||||
|
}
|
||||||
|
var currVal = await connection.query(
|
||||||
|
'SELECT * FROM "authors" WHERE id = currval(pg_get_serial_sequence(\'authors\', \'id\'));');
|
||||||
|
return parseRow(currVal[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Stream<Author> getAll(PostgreSQLConnection connection) =>
|
static Stream<Author> getAll(PostgreSQLConnection connection) =>
|
||||||
|
@ -118,7 +147,8 @@ class AuthorQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AuthorQueryWhere {
|
class AuthorQueryWhere {
|
||||||
final StringSqlExpressionBuilder id = new StringSqlExpressionBuilder();
|
final NumericSqlExpressionBuilder<int> id =
|
||||||
|
new NumericSqlExpressionBuilder<int>();
|
||||||
|
|
||||||
final StringSqlExpressionBuilder name = new StringSqlExpressionBuilder();
|
final StringSqlExpressionBuilder name = new StringSqlExpressionBuilder();
|
||||||
|
|
||||||
|
@ -128,7 +158,7 @@ class AuthorQueryWhere {
|
||||||
final DateTimeSqlExpressionBuilder updatedAt =
|
final DateTimeSqlExpressionBuilder updatedAt =
|
||||||
new DateTimeSqlExpressionBuilder('updated_at');
|
new DateTimeSqlExpressionBuilder('updated_at');
|
||||||
|
|
||||||
String toWhereClause() {
|
String toWhereClause({bool keyword}) {
|
||||||
final List<String> expressions = [];
|
final List<String> expressions = [];
|
||||||
if (id.hasValue) {
|
if (id.hasValue) {
|
||||||
expressions.add('"id" ' + id.compile());
|
expressions.add('"id" ' + id.compile());
|
||||||
|
@ -142,6 +172,8 @@ class AuthorQueryWhere {
|
||||||
if (updatedAt.hasValue) {
|
if (updatedAt.hasValue) {
|
||||||
expressions.add(updatedAt.compile());
|
expressions.add(updatedAt.compile());
|
||||||
}
|
}
|
||||||
return expressions.isEmpty ? null : ('WHERE ' + expressions.join(' AND '));
|
return expressions.isEmpty
|
||||||
|
? null
|
||||||
|
: ((keyword != false ? 'WHERE ' : '') + expressions.join(' AND '));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
CREATE TABLE "authors" (
|
CREATE TEMPORARY TABLE "authors" (
|
||||||
"id" serial,
|
"id" serial,
|
||||||
"name" varchar,
|
"name" varchar,
|
||||||
"created_at" timestamp,
|
"created_at" timestamp,
|
||||||
|
|
|
@ -21,21 +21,21 @@ class BookQuery {
|
||||||
final BookQueryWhere where = new BookQueryWhere();
|
final BookQueryWhere where = new BookQueryWhere();
|
||||||
|
|
||||||
void and(BookQuery other) {
|
void and(BookQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_and.add(compiled);
|
_and.add(compiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void or(BookQuery other) {
|
void or(BookQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_or.add(compiled);
|
_or.add(compiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void not(BookQuery other) {
|
void not(BookQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_not.add(compiled);
|
_not.add(compiled);
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,15 @@ class BookQuery {
|
||||||
if (whereClause != null) {
|
if (whereClause != null) {
|
||||||
buf.write(' ' + whereClause);
|
buf.write(' ' + whereClause);
|
||||||
}
|
}
|
||||||
|
if (_and.isNotEmpty) {
|
||||||
|
buf.write(' AND (' + _and.join(',') + ')');
|
||||||
|
}
|
||||||
|
if (_or.isNotEmpty) {
|
||||||
|
buf.write(' OR (' + _or.join(',') + ')');
|
||||||
|
}
|
||||||
|
if (_not.isNotEmpty) {
|
||||||
|
buf.write(' NOT (' + _not.join(',') + ')');
|
||||||
|
}
|
||||||
buf.write(';');
|
buf.write(';');
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
@ -55,8 +64,8 @@ class BookQuery {
|
||||||
return new Book.fromJson({
|
return new Book.fromJson({
|
||||||
'id': row[0].toString(),
|
'id': row[0].toString(),
|
||||||
'name': row[1],
|
'name': row[1],
|
||||||
'created_at': DATE_YMD_HMS.parse(row[2]),
|
'created_at': row[2],
|
||||||
'updated_at': DATE_YMD_HMS.parse(row[3]),
|
'updated_at': row[3],
|
||||||
'author': row.length < 5 ? null : AuthorQuery.parseRow(row[4])
|
'author': row.length < 5 ? null : AuthorQuery.parseRow(row[4])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -75,24 +84,37 @@ class BookQuery {
|
||||||
substitutionValues: {'id': id}).then((rows) => parseRow(rows.first));
|
substitutionValues: {'id': id}).then((rows) => parseRow(rows.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Book> update(int id, PostgreSQLConnection connection,
|
Stream<Book> update(PostgreSQLConnection connection,
|
||||||
{String name, DateTime createdAt, DateTime updatedAt}) async {
|
{String name, DateTime createdAt, DateTime updatedAt}) {
|
||||||
|
var buf = new StringBuffer(
|
||||||
|
'UPDATE "books" SET ("name", "created_at", "updated_at") = (@name, @createdAt, @updatedAt) ');
|
||||||
|
var whereClause = where.toWhereClause();
|
||||||
|
if (whereClause == null) {
|
||||||
|
buf.write('WHERE "id" = @id');
|
||||||
|
} else {
|
||||||
|
buf.write(whereClause);
|
||||||
|
}
|
||||||
var __ormNow__ = new DateTime.now();
|
var __ormNow__ = new DateTime.now();
|
||||||
var result = await connection.query(
|
var ctrl = new StreamController<Book>();
|
||||||
'UPDATE "books" SET ("name", "created_at", "updated_at") = (@name, @createdAt, @updatedAt) WHERE "id" = @id RETURNING ("id", "name", "created_at", "updated_at");',
|
connection.query(
|
||||||
|
buf.toString() +
|
||||||
|
' RETURNING ("id", "name", "created_at", "updated_at");',
|
||||||
substitutionValues: {
|
substitutionValues: {
|
||||||
'name': name,
|
'name': name,
|
||||||
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
||||||
'updatedAt': updatedAt != null ? updatedAt : __ormNow__,
|
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
||||||
'id': id
|
}).then((rows) {
|
||||||
});
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
return parseRow(result);
|
ctrl.close();
|
||||||
|
}).catchError(ctrl.addError);
|
||||||
|
return ctrl.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Book> delete(int id, PostgreSQLConnection connection) async {
|
Stream<Book> delete(PostgreSQLConnection connection) async {}
|
||||||
|
|
||||||
|
static Future<Book> deleteOne(int id, PostgreSQLConnection connection) async {
|
||||||
var __ormBeforeDelete__ = await BookQuery.getOne(id, connection);
|
var __ormBeforeDelete__ = await BookQuery.getOne(id, connection);
|
||||||
var result = await connection.execute(
|
var result = await connection.execute('DELETE FROM "books" WHERE id = @id;',
|
||||||
'DELETE FROM "books" WHERE id = @id LIMIT 1;',
|
|
||||||
substitutionValues: {'id': id});
|
substitutionValues: {'id': id});
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
new StateError('DELETE query deleted ' +
|
new StateError('DELETE query deleted ' +
|
||||||
|
@ -105,14 +127,19 @@ class BookQuery {
|
||||||
static Future<Book> insert(PostgreSQLConnection connection,
|
static Future<Book> insert(PostgreSQLConnection connection,
|
||||||
{String name, DateTime createdAt, DateTime updatedAt}) async {
|
{String name, DateTime createdAt, DateTime updatedAt}) async {
|
||||||
var __ormNow__ = new DateTime.now();
|
var __ormNow__ = new DateTime.now();
|
||||||
var result = await connection.query(
|
var nRows = await connection.execute(
|
||||||
'INSERT INTO "books" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt) RETURNING ("id", "name", "created_at", "updated_at");',
|
'INSERT INTO "books" ("name", "created_at", "updated_at") VALUES (@name, @createdAt, @updatedAt);',
|
||||||
substitutionValues: {
|
substitutionValues: {
|
||||||
'name': name,
|
'name': name,
|
||||||
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
||||||
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
||||||
});
|
});
|
||||||
return parseRow(result);
|
if (nRows < 1) {
|
||||||
|
throw new StateError('Insertion into "books" table failed.');
|
||||||
|
}
|
||||||
|
var currVal = await connection.query(
|
||||||
|
'SELECT * FROM "books" WHERE id = currval(pg_get_serial_sequence(\'books\', \'id\'));');
|
||||||
|
return parseRow(currVal[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Stream<Book> getAll(PostgreSQLConnection connection) =>
|
static Stream<Book> getAll(PostgreSQLConnection connection) =>
|
||||||
|
@ -120,7 +147,8 @@ class BookQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BookQueryWhere {
|
class BookQueryWhere {
|
||||||
final StringSqlExpressionBuilder id = new StringSqlExpressionBuilder();
|
final NumericSqlExpressionBuilder<int> id =
|
||||||
|
new NumericSqlExpressionBuilder<int>();
|
||||||
|
|
||||||
final StringSqlExpressionBuilder name = new StringSqlExpressionBuilder();
|
final StringSqlExpressionBuilder name = new StringSqlExpressionBuilder();
|
||||||
|
|
||||||
|
@ -130,7 +158,7 @@ class BookQueryWhere {
|
||||||
final DateTimeSqlExpressionBuilder updatedAt =
|
final DateTimeSqlExpressionBuilder updatedAt =
|
||||||
new DateTimeSqlExpressionBuilder('updated_at');
|
new DateTimeSqlExpressionBuilder('updated_at');
|
||||||
|
|
||||||
String toWhereClause() {
|
String toWhereClause({bool keyword}) {
|
||||||
final List<String> expressions = [];
|
final List<String> expressions = [];
|
||||||
if (id.hasValue) {
|
if (id.hasValue) {
|
||||||
expressions.add('"id" ' + id.compile());
|
expressions.add('"id" ' + id.compile());
|
||||||
|
@ -144,6 +172,8 @@ class BookQueryWhere {
|
||||||
if (updatedAt.hasValue) {
|
if (updatedAt.hasValue) {
|
||||||
expressions.add(updatedAt.compile());
|
expressions.add(updatedAt.compile());
|
||||||
}
|
}
|
||||||
return expressions.isEmpty ? null : ('WHERE ' + expressions.join(' AND '));
|
return expressions.isEmpty
|
||||||
|
? null
|
||||||
|
: ((keyword != false ? 'WHERE ' : '') + expressions.join(' AND '));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
CREATE TABLE "books" (
|
CREATE TEMPORARY TABLE "books" (
|
||||||
"id" serial,
|
"id" serial,
|
||||||
"name" varchar,
|
"name" varchar,
|
||||||
"created_at" timestamp,
|
"created_at" timestamp,
|
||||||
|
|
|
@ -20,21 +20,21 @@ class CarQuery {
|
||||||
final CarQueryWhere where = new CarQueryWhere();
|
final CarQueryWhere where = new CarQueryWhere();
|
||||||
|
|
||||||
void and(CarQuery other) {
|
void and(CarQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_and.add(compiled);
|
_and.add(compiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void or(CarQuery other) {
|
void or(CarQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_or.add(compiled);
|
_or.add(compiled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void not(CarQuery other) {
|
void not(CarQuery other) {
|
||||||
var compiled = other.where.toWhereClause();
|
var compiled = other.where.toWhereClause(keyword: false);
|
||||||
if (compiled != null) {
|
if (compiled != null) {
|
||||||
_not.add(compiled);
|
_not.add(compiled);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,15 @@ class CarQuery {
|
||||||
if (whereClause != null) {
|
if (whereClause != null) {
|
||||||
buf.write(' ' + whereClause);
|
buf.write(' ' + whereClause);
|
||||||
}
|
}
|
||||||
|
if (_and.isNotEmpty) {
|
||||||
|
buf.write(' AND (' + _and.join(',') + ')');
|
||||||
|
}
|
||||||
|
if (_or.isNotEmpty) {
|
||||||
|
buf.write(' OR (' + _or.join(',') + ')');
|
||||||
|
}
|
||||||
|
if (_not.isNotEmpty) {
|
||||||
|
buf.write(' NOT (' + _not.join(',') + ')');
|
||||||
|
}
|
||||||
buf.write(';');
|
buf.write(';');
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
@ -55,10 +64,10 @@ class CarQuery {
|
||||||
'id': row[0].toString(),
|
'id': row[0].toString(),
|
||||||
'make': row[1],
|
'make': row[1],
|
||||||
'description': row[2],
|
'description': row[2],
|
||||||
'family_friendly': row[3] == 1,
|
'family_friendly': row[3],
|
||||||
'recalled_at': DATE_YMD_HMS.parse(row[4]),
|
'recalled_at': row[4],
|
||||||
'created_at': DATE_YMD_HMS.parse(row[5]),
|
'created_at': row[5],
|
||||||
'updated_at': DATE_YMD_HMS.parse(row[6])
|
'updated_at': row[6]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,32 +85,54 @@ class CarQuery {
|
||||||
substitutionValues: {'id': id}).then((rows) => parseRow(rows.first));
|
substitutionValues: {'id': id}).then((rows) => parseRow(rows.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Car> update(int id, PostgreSQLConnection connection,
|
Stream<Car> update(PostgreSQLConnection connection,
|
||||||
{String make,
|
{String make,
|
||||||
String description,
|
String description,
|
||||||
bool familyFriendly,
|
bool familyFriendly,
|
||||||
DateTime recalledAt,
|
DateTime recalledAt,
|
||||||
DateTime createdAt,
|
DateTime createdAt,
|
||||||
DateTime updatedAt}) async {
|
DateTime updatedAt}) {
|
||||||
|
var buf = new StringBuffer(
|
||||||
|
'UPDATE "cars" SET ("make", "description", "family_friendly", "recalled_at", "created_at", "updated_at") = (@make, @description, @familyFriendly, @recalledAt, @createdAt, @updatedAt) ');
|
||||||
|
var whereClause = where.toWhereClause();
|
||||||
|
if (whereClause == null) {
|
||||||
|
buf.write('WHERE "id" = @id');
|
||||||
|
} else {
|
||||||
|
buf.write(whereClause);
|
||||||
|
}
|
||||||
var __ormNow__ = new DateTime.now();
|
var __ormNow__ = new DateTime.now();
|
||||||
var result = await connection.query(
|
var ctrl = new StreamController<Car>();
|
||||||
'UPDATE "cars" SET ("make", "description", "family_friendly", "recalled_at", "created_at", "updated_at") = (@make, @description, @familyFriendly, @recalledAt, @createdAt, @updatedAt) WHERE "id" = @id RETURNING ("id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at");',
|
connection.query(
|
||||||
|
buf.toString() +
|
||||||
|
' RETURNING ("id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at");',
|
||||||
substitutionValues: {
|
substitutionValues: {
|
||||||
'make': make,
|
'make': make,
|
||||||
'description': description,
|
'description': description,
|
||||||
'familyFriendly': familyFriendly,
|
'familyFriendly': familyFriendly,
|
||||||
'recalledAt': recalledAt,
|
'recalledAt': recalledAt,
|
||||||
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
||||||
'updatedAt': updatedAt != null ? updatedAt : __ormNow__,
|
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
||||||
'id': id
|
}).then((rows) {
|
||||||
});
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
return parseRow(result);
|
ctrl.close();
|
||||||
|
}).catchError(ctrl.addError);
|
||||||
|
return ctrl.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Car> delete(int id, PostgreSQLConnection connection) async {
|
Stream<Car> delete(PostgreSQLConnection connection) {
|
||||||
|
var query = 'DELETE FROM "cars" RETURNING ("id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at");';
|
||||||
|
StreamController<Car> ctrl = new StreamController<Car>();
|
||||||
|
connection.execute(query).then((rows) {
|
||||||
|
print('Rows: $rows');
|
||||||
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
|
ctrl.close();
|
||||||
|
}).catchError(ctrl.addError);
|
||||||
|
return ctrl.stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Car> deleteOne(int id, PostgreSQLConnection connection) async {
|
||||||
var __ormBeforeDelete__ = await CarQuery.getOne(id, connection);
|
var __ormBeforeDelete__ = await CarQuery.getOne(id, connection);
|
||||||
var result = await connection.execute(
|
var result = await connection.execute('DELETE FROM "cars" WHERE id = @id;',
|
||||||
'DELETE FROM "cars" WHERE id = @id LIMIT 1;',
|
|
||||||
substitutionValues: {'id': id});
|
substitutionValues: {'id': id});
|
||||||
if (result != 1) {
|
if (result != 1) {
|
||||||
new StateError('DELETE query deleted ' +
|
new StateError('DELETE query deleted ' +
|
||||||
|
@ -119,8 +150,8 @@ class CarQuery {
|
||||||
DateTime createdAt,
|
DateTime createdAt,
|
||||||
DateTime updatedAt}) async {
|
DateTime updatedAt}) async {
|
||||||
var __ormNow__ = new DateTime.now();
|
var __ormNow__ = new DateTime.now();
|
||||||
var result = await connection.query(
|
var nRows = await connection.execute(
|
||||||
'INSERT INTO "cars" ("make", "description", "family_friendly", "recalled_at", "created_at", "updated_at") VALUES (@make, @description, @familyFriendly, @recalledAt, @createdAt, @updatedAt) RETURNING ("id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at");',
|
'INSERT INTO "cars" ("make", "description", "family_friendly", "recalled_at", "created_at", "updated_at") VALUES (@make, @description, @familyFriendly, @recalledAt, @createdAt, @updatedAt);',
|
||||||
substitutionValues: {
|
substitutionValues: {
|
||||||
'make': make,
|
'make': make,
|
||||||
'description': description,
|
'description': description,
|
||||||
|
@ -129,7 +160,12 @@ class CarQuery {
|
||||||
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
'createdAt': createdAt != null ? createdAt : __ormNow__,
|
||||||
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
'updatedAt': updatedAt != null ? updatedAt : __ormNow__
|
||||||
});
|
});
|
||||||
return parseRow(result);
|
if (nRows < 1) {
|
||||||
|
throw new StateError('Insertion into "cars" table failed.');
|
||||||
|
}
|
||||||
|
var currVal = await connection.query(
|
||||||
|
'SELECT * FROM "cars" WHERE id = currval(pg_get_serial_sequence(\'cars\', \'id\'));');
|
||||||
|
return parseRow(currVal[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Stream<Car> getAll(PostgreSQLConnection connection) =>
|
static Stream<Car> getAll(PostgreSQLConnection connection) =>
|
||||||
|
@ -137,7 +173,8 @@ class CarQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CarQueryWhere {
|
class CarQueryWhere {
|
||||||
final StringSqlExpressionBuilder id = new StringSqlExpressionBuilder();
|
final NumericSqlExpressionBuilder<int> id =
|
||||||
|
new NumericSqlExpressionBuilder<int>();
|
||||||
|
|
||||||
final StringSqlExpressionBuilder make = new StringSqlExpressionBuilder();
|
final StringSqlExpressionBuilder make = new StringSqlExpressionBuilder();
|
||||||
|
|
||||||
|
@ -156,7 +193,7 @@ class CarQueryWhere {
|
||||||
final DateTimeSqlExpressionBuilder updatedAt =
|
final DateTimeSqlExpressionBuilder updatedAt =
|
||||||
new DateTimeSqlExpressionBuilder('updated_at');
|
new DateTimeSqlExpressionBuilder('updated_at');
|
||||||
|
|
||||||
String toWhereClause() {
|
String toWhereClause({bool keyword}) {
|
||||||
final List<String> expressions = [];
|
final List<String> expressions = [];
|
||||||
if (id.hasValue) {
|
if (id.hasValue) {
|
||||||
expressions.add('"id" ' + id.compile());
|
expressions.add('"id" ' + id.compile());
|
||||||
|
@ -179,6 +216,8 @@ class CarQueryWhere {
|
||||||
if (updatedAt.hasValue) {
|
if (updatedAt.hasValue) {
|
||||||
expressions.add(updatedAt.compile());
|
expressions.add(updatedAt.compile());
|
||||||
}
|
}
|
||||||
return expressions.isEmpty ? null : ('WHERE ' + expressions.join(' AND '));
|
return expressions.isEmpty
|
||||||
|
? null
|
||||||
|
: ((keyword != false ? 'WHERE ' : '') + expressions.join(' AND '));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
CREATE TABLE "cars" (
|
CREATE TEMPORARY TABLE "cars" (
|
||||||
"id" serial,
|
"id" serial,
|
||||||
"make" varchar,
|
"make" varchar,
|
||||||
"description" varchar,
|
"description" varchar,
|
||||||
"family_friendly" bit,
|
"family_friendly" boolean,
|
||||||
"recalled_at" timestamp,
|
"recalled_at" timestamp,
|
||||||
"created_at" timestamp,
|
"created_at" timestamp,
|
||||||
"updated_at" timestamp
|
"updated_at" timestamp
|
||||||
|
|
|
@ -13,4 +13,5 @@ final PhaseGroup PHASES = new PhaseGroup()
|
||||||
new GeneratorBuilder([new PostgresORMGenerator()],
|
new GeneratorBuilder([new PostgresORMGenerator()],
|
||||||
isStandalone: true, generatedExtension: '.orm.g.dart'),
|
isStandalone: true, generatedExtension: '.orm.g.dart'),
|
||||||
MODELS))
|
MODELS))
|
||||||
..addPhase(new Phase()..addAction(new SQLMigrationGenerator(), MODELS));
|
..addPhase(new Phase()
|
||||||
|
..addAction(new SQLMigrationGenerator(temporary: true), MODELS));
|
||||||
|
|
Loading…
Reference in a new issue