parent
85b032d4f0
commit
7298b4638b
9 changed files with 390 additions and 246 deletions
|
@ -1,4 +1,3 @@
|
||||||
import 'package:charcode/charcode.dart';
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:string_scanner/string_scanner.dart';
|
import 'package:string_scanner/string_scanner.dart';
|
||||||
|
|
7
angel_orm_generator/CHANGELOG.md
Normal file
7
angel_orm_generator/CHANGELOG.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# 1.0.0-alpha+1
|
||||||
|
* Closed #12. `insertX` and `updateX` now use `rc.camelCase`, instead of `rc.snakeCase`.
|
||||||
|
* Closed #13. Added `limit` and `offset` properties to `XQuery`.
|
||||||
|
* Closed #14. Refined the `or` method (it now takes an `XQueryWhere`), and removed `and` and `not`.
|
||||||
|
* Closed #16. Added `sortAscending` and `sortDescending` to `XQuery`.
|
||||||
|
* Closed #17. `delete` now uses `toSql` from `XQuery`.
|
||||||
|
* Closed #18. `XQuery` now supports `union` and `unionAll`.
|
|
@ -12,7 +12,12 @@ import 'package:source_gen/source_gen.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'];
|
const List<String> RELATIONS = const ['or'];
|
||||||
|
const List<String> RESTRICTORS = const ['limit', 'offset'];
|
||||||
|
const Map<String, String> SORT_MODES = const {
|
||||||
|
'Descending': 'DESC',
|
||||||
|
'Ascending': 'ASC'
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: HasOne, HasMany, BelongsTo
|
// TODO: HasOne, HasMany, BelongsTo
|
||||||
class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
|
@ -95,26 +100,51 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
var clazz = new ClassBuilder(ctx.queryClassName);
|
var clazz = new ClassBuilder(ctx.queryClassName);
|
||||||
|
|
||||||
// Add constructor + field
|
// Add constructor + field
|
||||||
var PostgreSQLConnection = new TypeBuilder('PostgreSQLConnection');
|
|
||||||
var connection = reference('connection');
|
var connection = reference('connection');
|
||||||
|
|
||||||
// Add or + not
|
// Add _unions
|
||||||
|
clazz.addField(varFinal('_unions',
|
||||||
|
value: map({}),
|
||||||
|
type: new TypeBuilder('Map',
|
||||||
|
genericTypes: [ctx.queryClassBuilder, lib$core.bool])));
|
||||||
|
|
||||||
|
var unions = <String, bool>{'union': false, 'unionAll': true};
|
||||||
|
unions.forEach((name, all) {
|
||||||
|
var meth = new MethodBuilder(name, returnType: lib$core.$void);
|
||||||
|
meth.addPositional(parameter('query', [ctx.queryClassBuilder]));
|
||||||
|
meth.addStatement(
|
||||||
|
literal(all).asAssign(reference('_unions')[reference('query')]));
|
||||||
|
clazz.addMethod(meth);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add _sortMode
|
||||||
|
clazz.addField(varField('_sortKey', type: lib$core.String));
|
||||||
|
clazz.addField(varField('_sortMode', type: lib$core.String));
|
||||||
|
|
||||||
|
SORT_MODES.keys.forEach((sort) {
|
||||||
|
var m = new MethodBuilder('sort$sort', returnType: lib$core.$void);
|
||||||
|
m.addPositional(parameter('key', [lib$core.String]));
|
||||||
|
m.addStatement(literal(sort).asAssign(reference('_sortMode')));
|
||||||
|
m.addStatement(reference('key').asAssign(reference('_sortKey')));
|
||||||
|
clazz.addMethod(m);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add limit, offset
|
||||||
|
for (var restrictor in RESTRICTORS) {
|
||||||
|
clazz.addField(varField(restrictor, type: lib$core.int));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add and, or, not
|
||||||
for (var relation in RELATIONS) {
|
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: [ctx.whereClassBuilder]),
|
||||||
value: list([])));
|
value: list([])));
|
||||||
var relationMethod =
|
var relationMethod =
|
||||||
new MethodBuilder(relation, returnType: lib$core.$void);
|
new MethodBuilder(relation, returnType: lib$core.$void);
|
||||||
relationMethod.addPositional(
|
relationMethod
|
||||||
parameter('other', [new TypeBuilder(ctx.queryClassName)]));
|
.addPositional(parameter('selector', [ctx.whereClassBuilder]));
|
||||||
var otherWhere = reference('other').property('where');
|
relationMethod.addStatement(
|
||||||
var compiled = reference('compiled');
|
reference('_$relation').invoke('add', [reference('selector')]));
|
||||||
relationMethod.addStatement(varField('compiled',
|
|
||||||
value: otherWhere.invoke('toWhereClause', [],
|
|
||||||
namedArguments: {'keyword': literal(false)})));
|
|
||||||
relationMethod.addStatement(ifThen(compiled.notEquals(literal(null)), [
|
|
||||||
reference('_$relation').invoke('add', [compiled])
|
|
||||||
]));
|
|
||||||
clazz.addMethod(relationMethod);
|
clazz.addMethod(relationMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,24 +189,35 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
clazz.addMethod(
|
clazz.addMethod(
|
||||||
new MethodBuilder('getAll',
|
new MethodBuilder('getAll',
|
||||||
returnType: new TypeBuilder('Stream',
|
returnType: new TypeBuilder('Stream',
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]),
|
genericTypes: [ctx.modelClassBuilder]),
|
||||||
returns: new TypeBuilder(ctx.queryClassName)
|
returns: ctx.queryClassBuilder
|
||||||
.newInstance([]).invoke('get', [connection]))
|
.newInstance([]).invoke('get', [connection]))
|
||||||
..addPositional(parameter('connection', [PostgreSQLConnection])),
|
..addPositional(
|
||||||
|
parameter('connection', [ctx.postgreSQLConnectionBuilder])),
|
||||||
asStatic: true);
|
asStatic: true);
|
||||||
|
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildToSqlMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildToSqlMethod(PostgresBuildContext ctx) {
|
||||||
// TODO: Bake relations into SQL queries
|
// TODO: Bake relationships into SQL queries
|
||||||
var meth = new MethodBuilder('toSql', returnType: lib$core.String);
|
var meth = new MethodBuilder('toSql', returnType: lib$core.String);
|
||||||
meth.addStatement(varField('buf',
|
meth.addPositional(parameter('prefix', [lib$core.String]).asOptional());
|
||||||
value: lib$core.StringBuffer
|
var buf = reference('buf');
|
||||||
.newInstance([literal('SELECT * FROM "${ctx.tableName}"')])));
|
meth.addStatement(
|
||||||
|
varField('buf', value: lib$core.StringBuffer.newInstance([])));
|
||||||
|
|
||||||
|
// Write prefix, or default to SELECT
|
||||||
|
var prefix = reference('prefix');
|
||||||
|
meth.addStatement(buf.invoke('write', [
|
||||||
|
prefix
|
||||||
|
.notEquals(literal(null))
|
||||||
|
.ternary(prefix, literal('SELECT * FROM "${ctx.tableName}"'))
|
||||||
|
]));
|
||||||
|
|
||||||
meth.addStatement(varField('whereClause',
|
meth.addStatement(varField('whereClause',
|
||||||
value: reference('where').invoke('toWhereClause', [])));
|
value: reference('where').invoke('toWhereClause', [])));
|
||||||
var buf = reference('buf');
|
|
||||||
var whereClause = reference('whereClause');
|
var whereClause = reference('whereClause');
|
||||||
|
|
||||||
meth.addStatement(ifThen(whereClause.notEquals(literal(null)), [
|
meth.addStatement(ifThen(whereClause.notEquals(literal(null)), [
|
||||||
|
@ -184,29 +225,73 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
]));
|
]));
|
||||||
|
|
||||||
for (var relation in RELATIONS) {
|
for (var relation in RELATIONS) {
|
||||||
var ref = reference('_$relation');
|
var ref = reference('_$relation'),
|
||||||
|
x = reference('x'),
|
||||||
|
whereClause = reference('whereClause');
|
||||||
var upper = relation.toUpperCase();
|
var upper = relation.toUpperCase();
|
||||||
var joined = ref.invoke('join', [literal(',')]);
|
var closure = new MethodBuilder.closure();
|
||||||
|
closure.addPositional(parameter('x'));
|
||||||
|
closure.addStatement(varField('whereClause',
|
||||||
|
value: x.invoke('toWhereClause', [],
|
||||||
|
namedArguments: {'keyword': literal(false)})));
|
||||||
|
closure.addStatement(ifThen(whereClause.notEquals(literal(null)), [
|
||||||
|
buf.invoke('write', [literal(' $upper (') + whereClause + literal(')')])
|
||||||
|
]));
|
||||||
|
|
||||||
meth.addStatement(ifThen(ref.property('isNotEmpty'), [
|
meth.addStatement(ref.invoke('forEach', [closure]));
|
||||||
buf.invoke('write', [literal(' $upper (') + joined + literal(')')])
|
}
|
||||||
|
|
||||||
|
var ifNoPrefix = ifThen(reference('prefix').equals(literal(null)));
|
||||||
|
|
||||||
|
for (var restrictor in RESTRICTORS) {
|
||||||
|
var ref = reference(restrictor);
|
||||||
|
var upper = restrictor.toUpperCase();
|
||||||
|
ifNoPrefix.addStatement(ifThen(ref.notEquals(literal(null)), [
|
||||||
|
buf.invoke('write', [literal(' $upper ') + ref.invoke('toString', [])])
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
meth.addStatement(buf.invoke('write', [literal(';')]));
|
var sortMode = reference('_sortMode');
|
||||||
meth.addStatement(buf.invoke('toString', []).asReturn());
|
|
||||||
|
|
||||||
|
SORT_MODES.forEach((k, sort) {
|
||||||
|
ifNoPrefix.addStatement(ifThen(sortMode.equals(literal(k)), [
|
||||||
|
buf.invoke('write', [
|
||||||
|
literal(' ORDER BY "') + reference('_sortKey') + literal('" $sort')
|
||||||
|
])
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add unions
|
||||||
|
var unionClosure = new MethodBuilder.closure();
|
||||||
|
unionClosure.addPositional(parameter('query'));
|
||||||
|
unionClosure.addPositional(parameter('all'));
|
||||||
|
unionClosure.addStatement(buf.invoke('write', [literal(' UNION')]));
|
||||||
|
unionClosure.addStatement(ifThen(reference('all'), [
|
||||||
|
buf.invoke('write', [literal(' ALL')])
|
||||||
|
]));
|
||||||
|
unionClosure.addStatement(buf.invoke('write', [literal(' (')]));
|
||||||
|
unionClosure.addStatement(varField('sql',
|
||||||
|
value: reference('query').invoke('toSql', []).invoke(
|
||||||
|
'replaceAll', [literal(';'), literal('')])));
|
||||||
|
unionClosure
|
||||||
|
.addStatement(buf.invoke('write', [reference('sql') + literal(')')]));
|
||||||
|
|
||||||
|
ifNoPrefix
|
||||||
|
.addStatement(reference('_unions').invoke('forEach', [unionClosure]));
|
||||||
|
|
||||||
|
ifNoPrefix.addStatement(buf.invoke('write', [literal(';')]));
|
||||||
|
|
||||||
|
meth.addStatement(ifNoPrefix);
|
||||||
|
meth.addStatement(buf.invoke('toString', []).asReturn());
|
||||||
return meth;
|
return meth;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodBuilder buildParseRowMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildParseRowMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('parseRow',
|
var meth = new MethodBuilder('parseRow', returnType: ctx.modelClassBuilder);
|
||||||
returnType: new TypeBuilder(ctx.modelClassName));
|
|
||||||
meth.addPositional(parameter('row', [lib$core.List]));
|
meth.addPositional(parameter('row', [lib$core.List]));
|
||||||
//meth.addStatement(lib$core.print.call(
|
//meth.addStatement(lib$core.print.call(
|
||||||
// [literal('ROW MAP: ') + reference('row').invoke('toString', [])]));
|
// [literal('ROW MAP: ') + reference('row').invoke('toString', [])]));
|
||||||
var row = reference('row');
|
var row = reference('row');
|
||||||
var DATE_YMD_HMS = reference('DATE_YMD_HMS');
|
|
||||||
|
|
||||||
// We want to create a Map using the SQL row.
|
// We want to create a Map using the SQL row.
|
||||||
Map<String, ExpressionBuilder> data = {};
|
Map<String, ExpressionBuilder> data = {};
|
||||||
|
@ -217,18 +302,9 @@ 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)) {
|
|
||||||
// TODO: Handle DATE and not just DATETIME
|
|
||||||
data[name] = DATE_YMD_HMS.invoke('parse', [rowKey]);
|
|
||||||
} else
|
|
||||||
*/
|
|
||||||
if (field.name == 'id' && ctx.shimmed.containsKey('id')) {
|
if (field.name == 'id' && ctx.shimmed.containsKey('id')) {
|
||||||
data[name] = rowKey.invoke('toString', []);
|
data[name] = rowKey.invoke('toString', []);
|
||||||
} /* else if (field.type.isAssignableTo(ctx.typeProvider.boolType)) {
|
} else
|
||||||
// TODO: Find out what date is returned as
|
|
||||||
data[name] = rowKey.equals(literal(1));
|
|
||||||
}*/
|
|
||||||
else
|
|
||||||
data[name] = rowKey;
|
data[name] = rowKey;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -244,7 +320,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then, call a .fromJson() constructor
|
// Then, call a .fromJson() constructor
|
||||||
meth.addStatement(new TypeBuilder(ctx.modelClassName)
|
meth.addStatement(ctx.modelClassBuilder
|
||||||
.newInstance([map(data)], constructor: 'fromJson').asReturn());
|
.newInstance([map(data)], constructor: 'fromJson').asReturn());
|
||||||
|
|
||||||
return meth;
|
return meth;
|
||||||
|
@ -266,12 +342,12 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
|
|
||||||
MethodBuilder buildGetMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildGetMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('get',
|
var meth = new MethodBuilder('get',
|
||||||
returnType: new TypeBuilder('Stream',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Stream', genericTypes: [ctx.modelClassBuilder]));
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
var streamController = new TypeBuilder('StreamController',
|
var streamController = new TypeBuilder('StreamController',
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
genericTypes: [ctx.modelClassBuilder]);
|
||||||
meth.addStatement(varField('ctrl',
|
meth.addStatement(varField('ctrl',
|
||||||
type: streamController, value: streamController.newInstance([])));
|
type: streamController, value: streamController.newInstance([])));
|
||||||
|
|
||||||
|
@ -283,11 +359,11 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
|
|
||||||
MethodBuilder buildGetOneMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildGetOneMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('getOne',
|
var meth = new MethodBuilder('getOne',
|
||||||
returnType: new TypeBuilder('Future',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||||
meth.addPositional(parameter('id', [lib$core.int]));
|
meth.addPositional(parameter('id', [lib$core.int]));
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
meth.addStatement(reference('connection').invoke('query', [
|
meth.addStatement(reference('connection').invoke('query', [
|
||||||
literal('SELECT * FROM "${ctx.tableName}" WHERE "id" = @id;')
|
literal('SELECT * FROM "${ctx.tableName}" WHERE "id" = @id;')
|
||||||
], namedArguments: {
|
], namedArguments: {
|
||||||
|
@ -360,10 +436,10 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
|
|
||||||
MethodBuilder buildUpdateMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildUpdateMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('update',
|
var meth = new MethodBuilder('update',
|
||||||
returnType: new TypeBuilder('Stream',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Stream', genericTypes: [ctx.modelClassBuilder]));
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
_addAllNamed(meth, ctx);
|
_addAllNamed(meth, ctx);
|
||||||
|
|
||||||
var buf = new StringBuffer('UPDATE "${ctx.tableName}" SET (');
|
var buf = new StringBuffer('UPDATE "${ctx.tableName}" SET (');
|
||||||
|
@ -409,7 +485,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
var substitutionValues = _buildSubstitutionValues(ctx);
|
var substitutionValues = _buildSubstitutionValues(ctx);
|
||||||
|
|
||||||
var ctrlType = new TypeBuilder('StreamController',
|
var ctrlType = new TypeBuilder('StreamController',
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
genericTypes: [ctx.modelClassBuilder]);
|
||||||
meth.addStatement(varField('ctrl', value: ctrlType.newInstance([])));
|
meth.addStatement(varField('ctrl', value: ctrlType.newInstance([])));
|
||||||
var result = _executeQuery(
|
var result = _executeQuery(
|
||||||
$buf.invoke('toString', []) + literal(buf2.toString()),
|
$buf.invoke('toString', []) + literal(buf2.toString()),
|
||||||
|
@ -421,46 +497,23 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
|
|
||||||
MethodBuilder buildDeleteMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildDeleteMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('delete',
|
var meth = new MethodBuilder('delete',
|
||||||
returnType: new TypeBuilder('Stream',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Stream', genericTypes: [ctx.modelClassBuilder]));
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
var buf = reference('buf'), whereClause = reference('whereClause');
|
|
||||||
|
|
||||||
meth.addStatement(varField('buf',
|
|
||||||
value: lib$core.StringBuffer
|
|
||||||
.newInstance([literal('DELETE FROM "${ctx.tableName}"')])));
|
|
||||||
meth.addStatement(varField('whereClause',
|
|
||||||
value: reference('where').invoke('toWhereClause', [])));
|
|
||||||
|
|
||||||
var ifStmt = ifThen(whereClause.notEquals(literal(null)), [
|
|
||||||
buf.invoke('write', [literal(' ') + whereClause])
|
|
||||||
]);
|
|
||||||
meth.addStatement(ifStmt);
|
|
||||||
|
|
||||||
for (var relation in RELATIONS) {
|
|
||||||
var ref = reference('_$relation');
|
|
||||||
var upper = relation.toUpperCase();
|
|
||||||
ifStmt.addStatement(ifThen(ref.property('isNotEmpty'), [
|
|
||||||
buf.invoke('write', [
|
|
||||||
literal(' $upper (') +
|
|
||||||
ref.invoke('join', [literal(', ')]) +
|
|
||||||
literal(')')
|
|
||||||
])
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
var litBuf = new StringBuffer();
|
var litBuf = new StringBuffer();
|
||||||
_addReturning(litBuf, ctx);
|
_addReturning(litBuf, ctx);
|
||||||
meth.addStatement(buf.invoke('write', [literal(litBuf.toString())]));
|
|
||||||
|
|
||||||
var streamController = new TypeBuilder('StreamController',
|
var streamController = new TypeBuilder('StreamController',
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
genericTypes: [ctx.modelClassBuilder]);
|
||||||
meth.addStatement(varField('ctrl',
|
meth.addStatement(varField('ctrl',
|
||||||
type: streamController, value: streamController.newInstance([])));
|
type: streamController, value: streamController.newInstance([])));
|
||||||
|
|
||||||
var future =
|
var future = reference('connection').invoke('query', [
|
||||||
reference('connection').invoke('query', [buf.invoke('toString', [])]);
|
reference('toSql').call([literal('DELETE FROM "${ctx.tableName}"')]) +
|
||||||
|
literal(litBuf.toString())
|
||||||
|
]);
|
||||||
_invokeStreamClosure(future, meth);
|
_invokeStreamClosure(future, meth);
|
||||||
|
|
||||||
return meth;
|
return meth;
|
||||||
|
@ -469,11 +522,11 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
MethodBuilder buildDeleteOneMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildDeleteOneMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('deleteOne',
|
var meth = new MethodBuilder('deleteOne',
|
||||||
modifier: MethodModifier.asAsync,
|
modifier: MethodModifier.asAsync,
|
||||||
returnType: new TypeBuilder('Future',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]))
|
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]))
|
||||||
..addPositional(parameter('id', [lib$core.int]))
|
..addPositional(parameter('id', [lib$core.int]))
|
||||||
..addPositional(
|
..addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
|
|
||||||
var id = reference('id');
|
var id = reference('id');
|
||||||
var connection = reference('connection');
|
var connection = reference('connection');
|
||||||
|
@ -498,10 +551,10 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
MethodBuilder buildInsertMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildInsertMethod(PostgresBuildContext ctx) {
|
||||||
var meth = new MethodBuilder('insert',
|
var meth = new MethodBuilder('insert',
|
||||||
modifier: MethodModifier.asAsync,
|
modifier: MethodModifier.asAsync,
|
||||||
returnType: new TypeBuilder('Future',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
|
|
||||||
// Add all named params
|
// Add all named params
|
||||||
_addAllNamed(meth, ctx);
|
_addAllNamed(meth, ctx);
|
||||||
|
@ -554,22 +607,21 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
MethodBuilder buildInsertModelMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildInsertModelMethod(PostgresBuildContext ctx) {
|
||||||
var rc = new ReCase(ctx.modelClassName);
|
var rc = new ReCase(ctx.modelClassName);
|
||||||
var meth = new MethodBuilder('insert${rc.pascalCase}',
|
var meth = new MethodBuilder('insert${rc.pascalCase}',
|
||||||
returnType: new TypeBuilder('Future',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||||
|
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
meth.addPositional(
|
meth.addPositional(parameter(rc.camelCase, [ctx.modelClassBuilder]));
|
||||||
parameter(rc.snakeCase, [new TypeBuilder(ctx.modelClassName)]));
|
|
||||||
|
|
||||||
Map<String, ExpressionBuilder> args = {};
|
Map<String, ExpressionBuilder> args = {};
|
||||||
var ref = reference(rc.snakeCase);
|
var ref = reference(rc.camelCase);
|
||||||
|
|
||||||
ctx.fields.forEach((f) {
|
ctx.fields.forEach((f) {
|
||||||
if (f.name != 'id') args[f.name] = ref.property(f.name);
|
if (f.name != 'id') args[f.name] = ref.property(f.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
meth.addStatement(new TypeBuilder(ctx.queryClassName)
|
meth.addStatement(ctx.queryClassBuilder
|
||||||
.invoke('insert', [reference('connection')], namedArguments: args)
|
.invoke('insert', [reference('connection')], namedArguments: args)
|
||||||
.asReturn());
|
.asReturn());
|
||||||
|
|
||||||
|
@ -579,19 +631,18 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||||
MethodBuilder buildUpdateModelMethod(PostgresBuildContext ctx) {
|
MethodBuilder buildUpdateModelMethod(PostgresBuildContext ctx) {
|
||||||
var rc = new ReCase(ctx.modelClassName);
|
var rc = new ReCase(ctx.modelClassName);
|
||||||
var meth = new MethodBuilder('update${rc.pascalCase}',
|
var meth = new MethodBuilder('update${rc.pascalCase}',
|
||||||
returnType: new TypeBuilder('Future',
|
returnType:
|
||||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||||
|
|
||||||
meth.addPositional(
|
meth.addPositional(
|
||||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||||
meth.addPositional(
|
meth.addPositional(parameter(rc.camelCase, [ctx.modelClassBuilder]));
|
||||||
parameter(rc.snakeCase, [new TypeBuilder(ctx.modelClassName)]));
|
|
||||||
|
|
||||||
// var query = new XQuery();
|
// var query = new XQuery();
|
||||||
var ref = reference(rc.snakeCase);
|
var ref = reference(rc.camelCase);
|
||||||
var query = reference('query');
|
var query = reference('query');
|
||||||
meth.addStatement(varField('query',
|
meth.addStatement(
|
||||||
value: new TypeBuilder(ctx.queryClassName).newInstance([])));
|
varField('query', value: ctx.queryClassBuilder.newInstance([])));
|
||||||
|
|
||||||
// query.where.id.equals(x.id);
|
// query.where.id.equals(x.id);
|
||||||
meth.addStatement(query.property('where').property('id').invoke('equals', [
|
meth.addStatement(query.property('where').property('id').invoke('equals', [
|
||||||
|
|
|
@ -4,11 +4,16 @@ import 'package:analyzer/src/generated/resolver.dart';
|
||||||
import 'package:angel_orm/angel_orm.dart';
|
import 'package:angel_orm/angel_orm.dart';
|
||||||
import 'package:angel_serialize_generator/context.dart';
|
import 'package:angel_serialize_generator/context.dart';
|
||||||
import 'package:build/build.dart';
|
import 'package:build/build.dart';
|
||||||
|
import 'package:code_builder/code_builder.dart';
|
||||||
|
|
||||||
class PostgresBuildContext extends BuildContext {
|
class PostgresBuildContext extends BuildContext {
|
||||||
DartType _dateTimeTypeCache;
|
DartType _dateTimeTypeCache;
|
||||||
LibraryElement _libraryCache;
|
LibraryElement _libraryCache;
|
||||||
TypeProvider _typeProviderCache;
|
TypeProvider _typeProviderCache;
|
||||||
|
TypeBuilder _modelClassBuilder,
|
||||||
|
_queryClassBuilder,
|
||||||
|
_whereClassBuilder,
|
||||||
|
_postgresqlConnectionBuilder;
|
||||||
final Map<String, Column> columnInfo = {};
|
final Map<String, Column> columnInfo = {};
|
||||||
final Map<String, IndexType> indices = {};
|
final Map<String, IndexType> indices = {};
|
||||||
final Map<String, Relationship> relationships = {};
|
final Map<String, Relationship> relationships = {};
|
||||||
|
@ -28,6 +33,18 @@ class PostgresBuildContext extends BuildContext {
|
||||||
|
|
||||||
final List<FieldElement> fields = [], relationshipFields = [];
|
final List<FieldElement> fields = [], relationshipFields = [];
|
||||||
|
|
||||||
|
TypeBuilder get modelClassBuilder =>
|
||||||
|
_modelClassBuilder ??= new TypeBuilder(modelClassName);
|
||||||
|
|
||||||
|
TypeBuilder get queryClassBuilder =>
|
||||||
|
_queryClassBuilder ??= new TypeBuilder(queryClassName);
|
||||||
|
|
||||||
|
TypeBuilder get whereClassBuilder =>
|
||||||
|
_whereClassBuilder ??= new TypeBuilder(whereClassName);
|
||||||
|
|
||||||
|
TypeBuilder get postgreSQLConnectionBuilder =>
|
||||||
|
_postgresqlConnectionBuilder ??= new TypeBuilder('PostgreSQLConnection');
|
||||||
|
|
||||||
Map<String, String> get aliases => raw.aliases;
|
Map<String, String> get aliases => raw.aliases;
|
||||||
|
|
||||||
Map<String, bool> get shimmed => raw.shimmed;
|
Map<String, bool> get shimmed => raw.shimmed;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel_orm_generator
|
name: angel_orm_generator
|
||||||
version: 1.0.0-alpha
|
version: 1.0.0-alpha+1
|
||||||
description: Code generators for Angel's ORM.
|
description: Code generators for Angel's ORM.
|
||||||
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
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_orm/angel_orm.dart';
|
import 'package:angel_orm/angel_orm.dart';
|
||||||
import 'package:postgres/postgres.dart';
|
import 'package:postgres/postgres.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
@ -84,10 +83,32 @@ main() {
|
||||||
expect(car.recalledAt, isNull);
|
expect(car.recalledAt, isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('and clause', () async {
|
test('union', () async {
|
||||||
|
var query1 = new CarQuery()..where.make.like('%Fer%');
|
||||||
|
var query2 = new CarQuery()..where.familyFriendly.equals(true);
|
||||||
|
var query3 = new CarQuery()..where.description.equals('Submarine');
|
||||||
|
query1
|
||||||
|
..union(query2)
|
||||||
|
..unionAll(query3);
|
||||||
|
print(query1.toSql());
|
||||||
|
|
||||||
|
var cars = await query1.get(connection).toList();
|
||||||
|
expect(cars, hasLength(1));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('or clause', () async {
|
||||||
var query = new CarQuery()
|
var query = new CarQuery()
|
||||||
..where.make.like('Fer%')
|
..where.make.like('Fer%')
|
||||||
..and(new CarQuery()..where.familyFriendly.equals(true));
|
..or(new CarQueryWhere()
|
||||||
|
..familyFriendly.equals(true)
|
||||||
|
..make.equals('Honda'));
|
||||||
|
print(query.toSql());
|
||||||
|
var cars = await query.get(connection).toList();
|
||||||
|
expect(cars, hasLength(1));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('limit obeyed', () async {
|
||||||
|
var query = new CarQuery()..limit = 0;
|
||||||
print(query.toSql());
|
print(query.toSql());
|
||||||
var cars = await query.get(connection).toList();
|
var cars = await query.get(connection).toList();
|
||||||
expect(cars, isEmpty);
|
expect(cars, isEmpty);
|
||||||
|
@ -108,6 +129,8 @@ main() {
|
||||||
|
|
||||||
test('delete stream', () async {
|
test('delete stream', () async {
|
||||||
var query = new CarQuery()..where.make.equals('Ferrari');
|
var query = new CarQuery()..where.make.equals('Ferrari');
|
||||||
|
query.or(new CarQueryWhere()..familyFriendly.equals(true));
|
||||||
|
print(query.toSql('DELETE FROM "cars"'));
|
||||||
var cars = await query.delete(connection).toList();
|
var cars = await query.delete(connection).toList();
|
||||||
expect(cars, hasLength(1));
|
expect(cars, hasLength(1));
|
||||||
expect(cars.first.toJson(), ferrari.toJson());
|
expect(cars.first.toJson(), ferrari.toJson());
|
||||||
|
|
|
@ -11,51 +11,79 @@ import 'package:postgres/postgres.dart';
|
||||||
import 'author.dart';
|
import 'author.dart';
|
||||||
|
|
||||||
class AuthorQuery {
|
class AuthorQuery {
|
||||||
final List<String> _and = [];
|
final Map<AuthorQuery, bool> _unions = {};
|
||||||
|
|
||||||
final List<String> _or = [];
|
String _sortKey;
|
||||||
|
|
||||||
final List<String> _not = [];
|
String _sortMode;
|
||||||
|
|
||||||
|
int limit;
|
||||||
|
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
final List<AuthorQueryWhere> _or = [];
|
||||||
|
|
||||||
final AuthorQueryWhere where = new AuthorQueryWhere();
|
final AuthorQueryWhere where = new AuthorQueryWhere();
|
||||||
|
|
||||||
void and(AuthorQuery other) {
|
void union(AuthorQuery query) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_unions[query] = false;
|
||||||
if (compiled != null) {
|
|
||||||
_and.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void or(AuthorQuery other) {
|
void unionAll(AuthorQuery query) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_unions[query] = true;
|
||||||
if (compiled != null) {
|
|
||||||
_or.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void not(AuthorQuery other) {
|
void sortDescending(String key) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_sortMode = 'Descending';
|
||||||
if (compiled != null) {
|
_sortKey = key;
|
||||||
_not.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String toSql() {
|
void sortAscending(String key) {
|
||||||
var buf = new StringBuffer('SELECT * FROM "authors"');
|
_sortMode = 'Ascending';
|
||||||
|
_sortKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void or(AuthorQueryWhere selector) {
|
||||||
|
_or.add(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toSql([String prefix]) {
|
||||||
|
var buf = new StringBuffer();
|
||||||
|
buf.write(prefix != null ? prefix : 'SELECT * FROM "authors"');
|
||||||
var whereClause = where.toWhereClause();
|
var whereClause = where.toWhereClause();
|
||||||
if (whereClause != null) {
|
if (whereClause != null) {
|
||||||
buf.write(' ' + whereClause);
|
buf.write(' ' + whereClause);
|
||||||
}
|
}
|
||||||
if (_and.isNotEmpty) {
|
_or.forEach((x) {
|
||||||
buf.write(' AND (' + _and.join(',') + ')');
|
var whereClause = x.toWhereClause(keyword: false);
|
||||||
|
if (whereClause != null) {
|
||||||
|
buf.write(' OR (' + whereClause + ')');
|
||||||
}
|
}
|
||||||
if (_or.isNotEmpty) {
|
});
|
||||||
buf.write(' OR (' + _or.join(',') + ')');
|
if (prefix == null) {
|
||||||
|
if (limit != null) {
|
||||||
|
buf.write(' LIMIT ' + limit.toString());
|
||||||
}
|
}
|
||||||
if (_not.isNotEmpty) {
|
if (offset != null) {
|
||||||
buf.write(' NOT (' + _not.join(',') + ')');
|
buf.write(' OFFSET ' + offset.toString());
|
||||||
}
|
}
|
||||||
|
if (_sortMode == 'Descending') {
|
||||||
|
buf.write(' ORDER BY "' + _sortKey + '" DESC');
|
||||||
|
}
|
||||||
|
if (_sortMode == 'Ascending') {
|
||||||
|
buf.write(' ORDER BY "' + _sortKey + '" ASC');
|
||||||
|
}
|
||||||
|
_unions.forEach((query, all) {
|
||||||
|
buf.write(' UNION');
|
||||||
|
if (all) {
|
||||||
|
buf.write(' ALL');
|
||||||
|
}
|
||||||
|
buf.write(' (');
|
||||||
|
var sql = query.toSql().replaceAll(';', '');
|
||||||
|
buf.write(sql + ')');
|
||||||
|
});
|
||||||
buf.write(';');
|
buf.write(';');
|
||||||
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,23 +136,11 @@ class AuthorQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Author> delete(PostgreSQLConnection connection) {
|
Stream<Author> delete(PostgreSQLConnection connection) {
|
||||||
var buf = new StringBuffer('DELETE FROM "authors"');
|
|
||||||
var whereClause = where.toWhereClause();
|
|
||||||
if (whereClause != null) {
|
|
||||||
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(' RETURNING "id", "name", "created_at", "updated_at";');
|
|
||||||
StreamController<Author> ctrl = new StreamController<Author>();
|
StreamController<Author> ctrl = new StreamController<Author>();
|
||||||
connection.query(buf.toString()).then((rows) {
|
connection
|
||||||
|
.query(toSql('DELETE FROM "authors"') +
|
||||||
|
' RETURNING "id", "name", "created_at", "updated_at";')
|
||||||
|
.then((rows) {
|
||||||
rows.map(parseRow).forEach(ctrl.add);
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
ctrl.close();
|
ctrl.close();
|
||||||
}).catchError(ctrl.addError);
|
}).catchError(ctrl.addError);
|
||||||
|
|
|
@ -12,51 +12,79 @@ import 'book.dart';
|
||||||
import 'author.orm.g.dart';
|
import 'author.orm.g.dart';
|
||||||
|
|
||||||
class BookQuery {
|
class BookQuery {
|
||||||
final List<String> _and = [];
|
final Map<BookQuery, bool> _unions = {};
|
||||||
|
|
||||||
final List<String> _or = [];
|
String _sortKey;
|
||||||
|
|
||||||
final List<String> _not = [];
|
String _sortMode;
|
||||||
|
|
||||||
|
int limit;
|
||||||
|
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
final List<BookQueryWhere> _or = [];
|
||||||
|
|
||||||
final BookQueryWhere where = new BookQueryWhere();
|
final BookQueryWhere where = new BookQueryWhere();
|
||||||
|
|
||||||
void and(BookQuery other) {
|
void union(BookQuery query) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_unions[query] = false;
|
||||||
if (compiled != null) {
|
|
||||||
_and.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void or(BookQuery other) {
|
void unionAll(BookQuery query) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_unions[query] = true;
|
||||||
if (compiled != null) {
|
|
||||||
_or.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void not(BookQuery other) {
|
void sortDescending(String key) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_sortMode = 'Descending';
|
||||||
if (compiled != null) {
|
_sortKey = key;
|
||||||
_not.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String toSql() {
|
void sortAscending(String key) {
|
||||||
var buf = new StringBuffer('SELECT * FROM "books"');
|
_sortMode = 'Ascending';
|
||||||
|
_sortKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void or(BookQueryWhere selector) {
|
||||||
|
_or.add(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toSql([String prefix]) {
|
||||||
|
var buf = new StringBuffer();
|
||||||
|
buf.write(prefix != null ? prefix : 'SELECT * FROM "books"');
|
||||||
var whereClause = where.toWhereClause();
|
var whereClause = where.toWhereClause();
|
||||||
if (whereClause != null) {
|
if (whereClause != null) {
|
||||||
buf.write(' ' + whereClause);
|
buf.write(' ' + whereClause);
|
||||||
}
|
}
|
||||||
if (_and.isNotEmpty) {
|
_or.forEach((x) {
|
||||||
buf.write(' AND (' + _and.join(',') + ')');
|
var whereClause = x.toWhereClause(keyword: false);
|
||||||
|
if (whereClause != null) {
|
||||||
|
buf.write(' OR (' + whereClause + ')');
|
||||||
}
|
}
|
||||||
if (_or.isNotEmpty) {
|
});
|
||||||
buf.write(' OR (' + _or.join(',') + ')');
|
if (prefix == null) {
|
||||||
|
if (limit != null) {
|
||||||
|
buf.write(' LIMIT ' + limit.toString());
|
||||||
}
|
}
|
||||||
if (_not.isNotEmpty) {
|
if (offset != null) {
|
||||||
buf.write(' NOT (' + _not.join(',') + ')');
|
buf.write(' OFFSET ' + offset.toString());
|
||||||
}
|
}
|
||||||
|
if (_sortMode == 'Descending') {
|
||||||
|
buf.write(' ORDER BY "' + _sortKey + '" DESC');
|
||||||
|
}
|
||||||
|
if (_sortMode == 'Ascending') {
|
||||||
|
buf.write(' ORDER BY "' + _sortKey + '" ASC');
|
||||||
|
}
|
||||||
|
_unions.forEach((query, all) {
|
||||||
|
buf.write(' UNION');
|
||||||
|
if (all) {
|
||||||
|
buf.write(' ALL');
|
||||||
|
}
|
||||||
|
buf.write(' (');
|
||||||
|
var sql = query.toSql().replaceAll(';', '');
|
||||||
|
buf.write(sql + ')');
|
||||||
|
});
|
||||||
buf.write(';');
|
buf.write(';');
|
||||||
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,23 +138,11 @@ class BookQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Book> delete(PostgreSQLConnection connection) {
|
Stream<Book> delete(PostgreSQLConnection connection) {
|
||||||
var buf = new StringBuffer('DELETE FROM "books"');
|
|
||||||
var whereClause = where.toWhereClause();
|
|
||||||
if (whereClause != null) {
|
|
||||||
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(' RETURNING "id", "name", "created_at", "updated_at";');
|
|
||||||
StreamController<Book> ctrl = new StreamController<Book>();
|
StreamController<Book> ctrl = new StreamController<Book>();
|
||||||
connection.query(buf.toString()).then((rows) {
|
connection
|
||||||
|
.query(toSql('DELETE FROM "books"') +
|
||||||
|
' RETURNING "id", "name", "created_at", "updated_at";')
|
||||||
|
.then((rows) {
|
||||||
rows.map(parseRow).forEach(ctrl.add);
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
ctrl.close();
|
ctrl.close();
|
||||||
}).catchError(ctrl.addError);
|
}).catchError(ctrl.addError);
|
||||||
|
|
|
@ -11,51 +11,79 @@ import 'package:postgres/postgres.dart';
|
||||||
import 'car.dart';
|
import 'car.dart';
|
||||||
|
|
||||||
class CarQuery {
|
class CarQuery {
|
||||||
final List<String> _and = [];
|
final Map<CarQuery, bool> _unions = {};
|
||||||
|
|
||||||
final List<String> _or = [];
|
String _sortKey;
|
||||||
|
|
||||||
final List<String> _not = [];
|
String _sortMode;
|
||||||
|
|
||||||
|
int limit;
|
||||||
|
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
final List<CarQueryWhere> _or = [];
|
||||||
|
|
||||||
final CarQueryWhere where = new CarQueryWhere();
|
final CarQueryWhere where = new CarQueryWhere();
|
||||||
|
|
||||||
void and(CarQuery other) {
|
void union(CarQuery query) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_unions[query] = false;
|
||||||
if (compiled != null) {
|
|
||||||
_and.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void or(CarQuery other) {
|
void unionAll(CarQuery query) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_unions[query] = true;
|
||||||
if (compiled != null) {
|
|
||||||
_or.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void not(CarQuery other) {
|
void sortDescending(String key) {
|
||||||
var compiled = other.where.toWhereClause(keyword: false);
|
_sortMode = 'Descending';
|
||||||
if (compiled != null) {
|
_sortKey = key;
|
||||||
_not.add(compiled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String toSql() {
|
void sortAscending(String key) {
|
||||||
var buf = new StringBuffer('SELECT * FROM "cars"');
|
_sortMode = 'Ascending';
|
||||||
|
_sortKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void or(CarQueryWhere selector) {
|
||||||
|
_or.add(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toSql([String prefix]) {
|
||||||
|
var buf = new StringBuffer();
|
||||||
|
buf.write(prefix != null ? prefix : 'SELECT * FROM "cars"');
|
||||||
var whereClause = where.toWhereClause();
|
var whereClause = where.toWhereClause();
|
||||||
if (whereClause != null) {
|
if (whereClause != null) {
|
||||||
buf.write(' ' + whereClause);
|
buf.write(' ' + whereClause);
|
||||||
}
|
}
|
||||||
if (_and.isNotEmpty) {
|
_or.forEach((x) {
|
||||||
buf.write(' AND (' + _and.join(',') + ')');
|
var whereClause = x.toWhereClause(keyword: false);
|
||||||
|
if (whereClause != null) {
|
||||||
|
buf.write(' OR (' + whereClause + ')');
|
||||||
}
|
}
|
||||||
if (_or.isNotEmpty) {
|
});
|
||||||
buf.write(' OR (' + _or.join(',') + ')');
|
if (prefix == null) {
|
||||||
|
if (limit != null) {
|
||||||
|
buf.write(' LIMIT ' + limit.toString());
|
||||||
}
|
}
|
||||||
if (_not.isNotEmpty) {
|
if (offset != null) {
|
||||||
buf.write(' NOT (' + _not.join(',') + ')');
|
buf.write(' OFFSET ' + offset.toString());
|
||||||
}
|
}
|
||||||
|
if (_sortMode == 'Descending') {
|
||||||
|
buf.write(' ORDER BY "' + _sortKey + '" DESC');
|
||||||
|
}
|
||||||
|
if (_sortMode == 'Ascending') {
|
||||||
|
buf.write(' ORDER BY "' + _sortKey + '" ASC');
|
||||||
|
}
|
||||||
|
_unions.forEach((query, all) {
|
||||||
|
buf.write(' UNION');
|
||||||
|
if (all) {
|
||||||
|
buf.write(' ALL');
|
||||||
|
}
|
||||||
|
buf.write(' (');
|
||||||
|
var sql = query.toSql().replaceAll(';', '');
|
||||||
|
buf.write(sql + ')');
|
||||||
|
});
|
||||||
buf.write(';');
|
buf.write(';');
|
||||||
|
}
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,24 +148,11 @@ class CarQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Car> delete(PostgreSQLConnection connection) {
|
Stream<Car> delete(PostgreSQLConnection connection) {
|
||||||
var buf = new StringBuffer('DELETE FROM "cars"');
|
|
||||||
var whereClause = where.toWhereClause();
|
|
||||||
if (whereClause != null) {
|
|
||||||
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(
|
|
||||||
' RETURNING "id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at";');
|
|
||||||
StreamController<Car> ctrl = new StreamController<Car>();
|
StreamController<Car> ctrl = new StreamController<Car>();
|
||||||
connection.query(buf.toString()).then((rows) {
|
connection
|
||||||
|
.query(toSql('DELETE FROM "cars"') +
|
||||||
|
' RETURNING "id", "make", "description", "family_friendly", "recalled_at", "created_at", "updated_at";')
|
||||||
|
.then((rows) {
|
||||||
rows.map(parseRow).forEach(ctrl.add);
|
rows.map(parseRow).forEach(ctrl.add);
|
||||||
ctrl.close();
|
ctrl.close();
|
||||||
}).catchError(ctrl.addError);
|
}).catchError(ctrl.addError);
|
||||||
|
|
Loading…
Reference in a new issue