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:intl/intl.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 '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
|
||||
class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
||||
|
@ -95,26 +100,51 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
var clazz = new ClassBuilder(ctx.queryClassName);
|
||||
|
||||
// Add constructor + field
|
||||
var PostgreSQLConnection = new TypeBuilder('PostgreSQLConnection');
|
||||
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) {
|
||||
clazz.addField(varFinal('_$relation',
|
||||
type: new TypeBuilder('List', genericTypes: [lib$core.String]),
|
||||
type: new TypeBuilder('List', genericTypes: [ctx.whereClassBuilder]),
|
||||
value: list([])));
|
||||
var relationMethod =
|
||||
new MethodBuilder(relation, returnType: lib$core.$void);
|
||||
relationMethod.addPositional(
|
||||
parameter('other', [new TypeBuilder(ctx.queryClassName)]));
|
||||
var otherWhere = reference('other').property('where');
|
||||
var compiled = reference('compiled');
|
||||
relationMethod.addStatement(varField('compiled',
|
||||
value: otherWhere.invoke('toWhereClause', [],
|
||||
namedArguments: {'keyword': literal(false)})));
|
||||
relationMethod.addStatement(ifThen(compiled.notEquals(literal(null)), [
|
||||
reference('_$relation').invoke('add', [compiled])
|
||||
]));
|
||||
relationMethod
|
||||
.addPositional(parameter('selector', [ctx.whereClassBuilder]));
|
||||
relationMethod.addStatement(
|
||||
reference('_$relation').invoke('add', [reference('selector')]));
|
||||
clazz.addMethod(relationMethod);
|
||||
}
|
||||
|
||||
|
@ -159,24 +189,35 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
clazz.addMethod(
|
||||
new MethodBuilder('getAll',
|
||||
returnType: new TypeBuilder('Stream',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]),
|
||||
returns: new TypeBuilder(ctx.queryClassName)
|
||||
genericTypes: [ctx.modelClassBuilder]),
|
||||
returns: ctx.queryClassBuilder
|
||||
.newInstance([]).invoke('get', [connection]))
|
||||
..addPositional(parameter('connection', [PostgreSQLConnection])),
|
||||
..addPositional(
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder])),
|
||||
asStatic: true);
|
||||
|
||||
return clazz;
|
||||
}
|
||||
|
||||
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);
|
||||
meth.addStatement(varField('buf',
|
||||
value: lib$core.StringBuffer
|
||||
.newInstance([literal('SELECT * FROM "${ctx.tableName}"')])));
|
||||
meth.addPositional(parameter('prefix', [lib$core.String]).asOptional());
|
||||
var buf = reference('buf');
|
||||
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',
|
||||
value: reference('where').invoke('toWhereClause', [])));
|
||||
var buf = reference('buf');
|
||||
|
||||
var whereClause = reference('whereClause');
|
||||
|
||||
meth.addStatement(ifThen(whereClause.notEquals(literal(null)), [
|
||||
|
@ -184,29 +225,73 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
]));
|
||||
|
||||
for (var relation in RELATIONS) {
|
||||
var ref = reference('_$relation');
|
||||
var ref = reference('_$relation'),
|
||||
x = reference('x'),
|
||||
whereClause = reference('whereClause');
|
||||
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'), [
|
||||
buf.invoke('write', [literal(' $upper (') + joined + literal(')')])
|
||||
meth.addStatement(ref.invoke('forEach', [closure]));
|
||||
}
|
||||
|
||||
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(';')]));
|
||||
meth.addStatement(buf.invoke('toString', []).asReturn());
|
||||
var sortMode = reference('_sortMode');
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MethodBuilder buildParseRowMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('parseRow',
|
||||
returnType: new TypeBuilder(ctx.modelClassName));
|
||||
var meth = new MethodBuilder('parseRow', returnType: ctx.modelClassBuilder);
|
||||
meth.addPositional(parameter('row', [lib$core.List]));
|
||||
//meth.addStatement(lib$core.print.call(
|
||||
// [literal('ROW MAP: ') + reference('row').invoke('toString', [])]));
|
||||
var row = reference('row');
|
||||
var DATE_YMD_HMS = reference('DATE_YMD_HMS');
|
||||
|
||||
// We want to create a Map using the SQL row.
|
||||
Map<String, ExpressionBuilder> data = {};
|
||||
|
@ -217,18 +302,9 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
var name = ctx.resolveFieldName(field.name);
|
||||
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')) {
|
||||
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
|
||||
} else
|
||||
data[name] = rowKey;
|
||||
});
|
||||
|
||||
|
@ -244,7 +320,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
});
|
||||
|
||||
// Then, call a .fromJson() constructor
|
||||
meth.addStatement(new TypeBuilder(ctx.modelClassName)
|
||||
meth.addStatement(ctx.modelClassBuilder
|
||||
.newInstance([map(data)], constructor: 'fromJson').asReturn());
|
||||
|
||||
return meth;
|
||||
|
@ -266,12 +342,12 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
|
||||
MethodBuilder buildGetMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('get',
|
||||
returnType: new TypeBuilder('Stream',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Stream', genericTypes: [ctx.modelClassBuilder]));
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
var streamController = new TypeBuilder('StreamController',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
||||
genericTypes: [ctx.modelClassBuilder]);
|
||||
meth.addStatement(varField('ctrl',
|
||||
type: streamController, value: streamController.newInstance([])));
|
||||
|
||||
|
@ -283,11 +359,11 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
|
||||
MethodBuilder buildGetOneMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('getOne',
|
||||
returnType: new TypeBuilder('Future',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||
meth.addPositional(parameter('id', [lib$core.int]));
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
meth.addStatement(reference('connection').invoke('query', [
|
||||
literal('SELECT * FROM "${ctx.tableName}" WHERE "id" = @id;')
|
||||
], namedArguments: {
|
||||
|
@ -360,10 +436,10 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
|
||||
MethodBuilder buildUpdateMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('update',
|
||||
returnType: new TypeBuilder('Stream',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Stream', genericTypes: [ctx.modelClassBuilder]));
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
_addAllNamed(meth, ctx);
|
||||
|
||||
var buf = new StringBuffer('UPDATE "${ctx.tableName}" SET (');
|
||||
|
@ -409,7 +485,7 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
var substitutionValues = _buildSubstitutionValues(ctx);
|
||||
|
||||
var ctrlType = new TypeBuilder('StreamController',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
||||
genericTypes: [ctx.modelClassBuilder]);
|
||||
meth.addStatement(varField('ctrl', value: ctrlType.newInstance([])));
|
||||
var result = _executeQuery(
|
||||
$buf.invoke('toString', []) + literal(buf2.toString()),
|
||||
|
@ -421,46 +497,23 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
|
||||
MethodBuilder buildDeleteMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('delete',
|
||||
returnType: new TypeBuilder('Stream',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Stream', genericTypes: [ctx.modelClassBuilder]));
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
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(')')
|
||||
])
|
||||
]));
|
||||
}
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
|
||||
var litBuf = new StringBuffer();
|
||||
_addReturning(litBuf, ctx);
|
||||
meth.addStatement(buf.invoke('write', [literal(litBuf.toString())]));
|
||||
|
||||
var streamController = new TypeBuilder('StreamController',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]);
|
||||
genericTypes: [ctx.modelClassBuilder]);
|
||||
meth.addStatement(varField('ctrl',
|
||||
type: streamController, value: streamController.newInstance([])));
|
||||
|
||||
var future =
|
||||
reference('connection').invoke('query', [buf.invoke('toString', [])]);
|
||||
var future = reference('connection').invoke('query', [
|
||||
reference('toSql').call([literal('DELETE FROM "${ctx.tableName}"')]) +
|
||||
literal(litBuf.toString())
|
||||
]);
|
||||
_invokeStreamClosure(future, meth);
|
||||
|
||||
return meth;
|
||||
|
@ -469,11 +522,11 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
MethodBuilder buildDeleteOneMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('deleteOne',
|
||||
modifier: MethodModifier.asAsync,
|
||||
returnType: new TypeBuilder('Future',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]))
|
||||
returnType:
|
||||
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]))
|
||||
..addPositional(parameter('id', [lib$core.int]))
|
||||
..addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
|
||||
var id = reference('id');
|
||||
var connection = reference('connection');
|
||||
|
@ -498,10 +551,10 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
MethodBuilder buildInsertMethod(PostgresBuildContext ctx) {
|
||||
var meth = new MethodBuilder('insert',
|
||||
modifier: MethodModifier.asAsync,
|
||||
returnType: new TypeBuilder('Future',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
|
||||
// Add all named params
|
||||
_addAllNamed(meth, ctx);
|
||||
|
@ -554,22 +607,21 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
MethodBuilder buildInsertModelMethod(PostgresBuildContext ctx) {
|
||||
var rc = new ReCase(ctx.modelClassName);
|
||||
var meth = new MethodBuilder('insert${rc.pascalCase}',
|
||||
returnType: new TypeBuilder('Future',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
meth.addPositional(
|
||||
parameter(rc.snakeCase, [new TypeBuilder(ctx.modelClassName)]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
meth.addPositional(parameter(rc.camelCase, [ctx.modelClassBuilder]));
|
||||
|
||||
Map<String, ExpressionBuilder> args = {};
|
||||
var ref = reference(rc.snakeCase);
|
||||
var ref = reference(rc.camelCase);
|
||||
|
||||
ctx.fields.forEach((f) {
|
||||
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)
|
||||
.asReturn());
|
||||
|
||||
|
@ -579,19 +631,18 @@ class PostgresORMGenerator extends GeneratorForAnnotation<ORM> {
|
|||
MethodBuilder buildUpdateModelMethod(PostgresBuildContext ctx) {
|
||||
var rc = new ReCase(ctx.modelClassName);
|
||||
var meth = new MethodBuilder('update${rc.pascalCase}',
|
||||
returnType: new TypeBuilder('Future',
|
||||
genericTypes: [new TypeBuilder(ctx.modelClassName)]));
|
||||
returnType:
|
||||
new TypeBuilder('Future', genericTypes: [ctx.modelClassBuilder]));
|
||||
|
||||
meth.addPositional(
|
||||
parameter('connection', [new TypeBuilder('PostgreSQLConnection')]));
|
||||
meth.addPositional(
|
||||
parameter(rc.snakeCase, [new TypeBuilder(ctx.modelClassName)]));
|
||||
parameter('connection', [ctx.postgreSQLConnectionBuilder]));
|
||||
meth.addPositional(parameter(rc.camelCase, [ctx.modelClassBuilder]));
|
||||
|
||||
// var query = new XQuery();
|
||||
var ref = reference(rc.snakeCase);
|
||||
var ref = reference(rc.camelCase);
|
||||
var query = reference('query');
|
||||
meth.addStatement(varField('query',
|
||||
value: new TypeBuilder(ctx.queryClassName).newInstance([])));
|
||||
meth.addStatement(
|
||||
varField('query', value: ctx.queryClassBuilder.newInstance([])));
|
||||
|
||||
// query.where.id.equals(x.id);
|
||||
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_serialize_generator/context.dart';
|
||||
import 'package:build/build.dart';
|
||||
import 'package:code_builder/code_builder.dart';
|
||||
|
||||
class PostgresBuildContext extends BuildContext {
|
||||
DartType _dateTimeTypeCache;
|
||||
LibraryElement _libraryCache;
|
||||
TypeProvider _typeProviderCache;
|
||||
TypeBuilder _modelClassBuilder,
|
||||
_queryClassBuilder,
|
||||
_whereClassBuilder,
|
||||
_postgresqlConnectionBuilder;
|
||||
final Map<String, Column> columnInfo = {};
|
||||
final Map<String, IndexType> indices = {};
|
||||
final Map<String, Relationship> relationships = {};
|
||||
|
@ -28,6 +33,18 @@ class PostgresBuildContext extends BuildContext {
|
|||
|
||||
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, bool> get shimmed => raw.shimmed;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: angel_orm_generator
|
||||
version: 1.0.0-alpha
|
||||
version: 1.0.0-alpha+1
|
||||
description: Code generators for Angel's ORM.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/orm
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_orm/angel_orm.dart';
|
||||
import 'package:postgres/postgres.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -84,10 +83,32 @@ main() {
|
|||
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()
|
||||
..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());
|
||||
var cars = await query.get(connection).toList();
|
||||
expect(cars, isEmpty);
|
||||
|
@ -108,6 +129,8 @@ main() {
|
|||
|
||||
test('delete stream', () async {
|
||||
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();
|
||||
expect(cars, hasLength(1));
|
||||
expect(cars.first.toJson(), ferrari.toJson());
|
||||
|
|
|
@ -11,51 +11,79 @@ import 'package:postgres/postgres.dart';
|
|||
import 'author.dart';
|
||||
|
||||
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();
|
||||
|
||||
void and(AuthorQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_and.add(compiled);
|
||||
}
|
||||
void union(AuthorQuery query) {
|
||||
_unions[query] = false;
|
||||
}
|
||||
|
||||
void or(AuthorQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_or.add(compiled);
|
||||
}
|
||||
void unionAll(AuthorQuery query) {
|
||||
_unions[query] = true;
|
||||
}
|
||||
|
||||
void not(AuthorQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_not.add(compiled);
|
||||
}
|
||||
void sortDescending(String key) {
|
||||
_sortMode = 'Descending';
|
||||
_sortKey = key;
|
||||
}
|
||||
|
||||
String toSql() {
|
||||
var buf = new StringBuffer('SELECT * FROM "authors"');
|
||||
void sortAscending(String key) {
|
||||
_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();
|
||||
if (whereClause != null) {
|
||||
buf.write(' ' + whereClause);
|
||||
}
|
||||
if (_and.isNotEmpty) {
|
||||
buf.write(' AND (' + _and.join(',') + ')');
|
||||
_or.forEach((x) {
|
||||
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) {
|
||||
buf.write(' NOT (' + _not.join(',') + ')');
|
||||
if (offset != null) {
|
||||
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(';');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
@ -108,23 +136,11 @@ class AuthorQuery {
|
|||
}
|
||||
|
||||
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>();
|
||||
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);
|
||||
ctrl.close();
|
||||
}).catchError(ctrl.addError);
|
||||
|
|
|
@ -12,51 +12,79 @@ import 'book.dart';
|
|||
import 'author.orm.g.dart';
|
||||
|
||||
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();
|
||||
|
||||
void and(BookQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_and.add(compiled);
|
||||
}
|
||||
void union(BookQuery query) {
|
||||
_unions[query] = false;
|
||||
}
|
||||
|
||||
void or(BookQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_or.add(compiled);
|
||||
}
|
||||
void unionAll(BookQuery query) {
|
||||
_unions[query] = true;
|
||||
}
|
||||
|
||||
void not(BookQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_not.add(compiled);
|
||||
}
|
||||
void sortDescending(String key) {
|
||||
_sortMode = 'Descending';
|
||||
_sortKey = key;
|
||||
}
|
||||
|
||||
String toSql() {
|
||||
var buf = new StringBuffer('SELECT * FROM "books"');
|
||||
void sortAscending(String key) {
|
||||
_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();
|
||||
if (whereClause != null) {
|
||||
buf.write(' ' + whereClause);
|
||||
}
|
||||
if (_and.isNotEmpty) {
|
||||
buf.write(' AND (' + _and.join(',') + ')');
|
||||
_or.forEach((x) {
|
||||
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) {
|
||||
buf.write(' NOT (' + _not.join(',') + ')');
|
||||
if (offset != null) {
|
||||
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(';');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
@ -110,23 +138,11 @@ class BookQuery {
|
|||
}
|
||||
|
||||
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>();
|
||||
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);
|
||||
ctrl.close();
|
||||
}).catchError(ctrl.addError);
|
||||
|
|
|
@ -11,51 +11,79 @@ import 'package:postgres/postgres.dart';
|
|||
import 'car.dart';
|
||||
|
||||
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();
|
||||
|
||||
void and(CarQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_and.add(compiled);
|
||||
}
|
||||
void union(CarQuery query) {
|
||||
_unions[query] = false;
|
||||
}
|
||||
|
||||
void or(CarQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_or.add(compiled);
|
||||
}
|
||||
void unionAll(CarQuery query) {
|
||||
_unions[query] = true;
|
||||
}
|
||||
|
||||
void not(CarQuery other) {
|
||||
var compiled = other.where.toWhereClause(keyword: false);
|
||||
if (compiled != null) {
|
||||
_not.add(compiled);
|
||||
}
|
||||
void sortDescending(String key) {
|
||||
_sortMode = 'Descending';
|
||||
_sortKey = key;
|
||||
}
|
||||
|
||||
String toSql() {
|
||||
var buf = new StringBuffer('SELECT * FROM "cars"');
|
||||
void sortAscending(String key) {
|
||||
_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();
|
||||
if (whereClause != null) {
|
||||
buf.write(' ' + whereClause);
|
||||
}
|
||||
if (_and.isNotEmpty) {
|
||||
buf.write(' AND (' + _and.join(',') + ')');
|
||||
_or.forEach((x) {
|
||||
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) {
|
||||
buf.write(' NOT (' + _not.join(',') + ')');
|
||||
if (offset != null) {
|
||||
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(';');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
@ -120,24 +148,11 @@ class CarQuery {
|
|||
}
|
||||
|
||||
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>();
|
||||
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);
|
||||
ctrl.close();
|
||||
}).catchError(ctrl.addError);
|
||||
|
|
Loading…
Reference in a new issue