fix lists + double
This commit is contained in:
parent
50c4b394c7
commit
24fb936a86
24 changed files with 295 additions and 91 deletions
|
@ -1,3 +1,7 @@
|
|||
# 2.0.0-dev.19
|
||||
* Implement cast-based `double` support.
|
||||
* Finish `ListSqlExpressionBuilder`.
|
||||
|
||||
# 2.0.0-dev.18
|
||||
* Add `ListSqlExpressionBuilder` (still in development).
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ String sanitizeExpression(String unsafe) {
|
|||
abstract class SqlExpressionBuilder<T> {
|
||||
final Query query;
|
||||
final String columnName;
|
||||
String _cast;
|
||||
bool _isProperty = false;
|
||||
String _substitution;
|
||||
|
||||
|
@ -75,7 +76,10 @@ class NumericSqlExpressionBuilder<T extends num>
|
|||
String compile() {
|
||||
if (_raw != null) return _raw;
|
||||
if (_value == null) return null;
|
||||
return '$_op $_value';
|
||||
var v = _value.toString();
|
||||
if (T == double) v = 'CAST ("$v" as decimal)';
|
||||
if (_cast != null) v = 'CAST ($v AS $_cast)';
|
||||
return '$_op $v';
|
||||
}
|
||||
|
||||
operator <(T value) => _change('<', value);
|
||||
|
@ -306,6 +310,7 @@ class BooleanSqlExpressionBuilder extends SqlExpressionBuilder<bool> {
|
|||
if (_raw != null) return _raw;
|
||||
if (_value == null) return null;
|
||||
var v = _value ? 'TRUE' : 'FALSE';
|
||||
if (_cast != null) v = 'CAST ($v AS $_cast)';
|
||||
return '$_op $v';
|
||||
}
|
||||
|
||||
|
@ -555,17 +560,16 @@ class JsonSqlExpressionBuilderProperty {
|
|||
throw StateError(
|
||||
'$nameString is already typed as $_typed, and cannot be changed.');
|
||||
} else {
|
||||
_typed = value().._isProperty = true;
|
||||
_typed = value()
|
||||
.._cast = 'text'
|
||||
.._isProperty = true;
|
||||
return _typed as T;
|
||||
}
|
||||
}
|
||||
|
||||
String get nameString {
|
||||
if (isInt) {
|
||||
return '(${builder.columnName}->>$name)::jsonb';
|
||||
} else {
|
||||
return "(${builder.columnName}->>'$name')::jsonb";
|
||||
}
|
||||
var n = isInt ? name : "'$name'";
|
||||
return '${builder.columnName}::jsonb->>$n';
|
||||
}
|
||||
|
||||
void isNotNull() {
|
||||
|
|
|
@ -7,6 +7,10 @@ bool isAscii(int ch) => ch >= $nul && ch <= $del;
|
|||
|
||||
/// A base class for objects that compile to SQL queries, typically within an ORM.
|
||||
abstract class QueryBase<T> {
|
||||
/// Casts to perform when querying the database.
|
||||
Map<String, String> get casts => {};
|
||||
|
||||
/// Values to insert into a prepared statement.
|
||||
final Map<String, dynamic> substitutionValues = {};
|
||||
|
||||
/// The list of fields returned by this query.
|
||||
|
@ -15,15 +19,18 @@ abstract class QueryBase<T> {
|
|||
List<String> get fields;
|
||||
|
||||
/// A String of all [fields], joined by a comma (`,`).
|
||||
String get fieldSet => fields.join(', ');
|
||||
String get fieldSet => fields.map((k) {
|
||||
var cast = casts[k];
|
||||
return cast == null ? k : 'CAST ($k AS $cast)';
|
||||
}).join(', ');
|
||||
|
||||
String compile(
|
||||
String compile(Set<String> trampoline,
|
||||
{bool includeTableName: false, String preamble, bool withFields: true});
|
||||
|
||||
T deserialize(List row);
|
||||
|
||||
Future<List<T>> get(QueryExecutor executor) async {
|
||||
var sql = compile();
|
||||
var sql = compile(Set());
|
||||
return executor
|
||||
.query(sql, substitutionValues)
|
||||
.then((it) => it.map(deserialize).toList());
|
||||
|
@ -187,52 +194,77 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
|||
|
||||
String _joinAlias() => 'a${_joins.length}';
|
||||
|
||||
String _compileJoin(tableName, Set<String> trampoline) {
|
||||
if (tableName is String) return tableName;
|
||||
if (tableName is Query) {
|
||||
var c = tableName.compile(trampoline);
|
||||
if (c == null) return c;
|
||||
return '($c)';
|
||||
}
|
||||
throw ArgumentError.value(
|
||||
tableName, 'tableName', 'must be a String or Query');
|
||||
}
|
||||
|
||||
/// Execute an `INNER JOIN` against another table.
|
||||
void join(String tableName, String localKey, String foreignKey,
|
||||
{String op: '=', List<String> additionalFields: const []}) {
|
||||
_joins.add(new JoinBuilder(
|
||||
JoinType.inner, this, tableName, localKey, foreignKey,
|
||||
void join(tableName, String localKey, String foreignKey,
|
||||
{String op: '=',
|
||||
List<String> additionalFields: const [],
|
||||
Set<String> trampoline}) {
|
||||
_joins.add(new JoinBuilder(JoinType.inner, this,
|
||||
_compileJoin(tableName, trampoline ?? Set()), localKey, foreignKey,
|
||||
op: op, alias: _joinAlias(), additionalFields: additionalFields));
|
||||
}
|
||||
|
||||
/// Execute a `LEFT JOIN` against another table.
|
||||
void leftJoin(String tableName, String localKey, String foreignKey,
|
||||
{String op: '=', List<String> additionalFields: const []}) {
|
||||
_joins.add(new JoinBuilder(
|
||||
JoinType.left, this, tableName, localKey, foreignKey,
|
||||
void leftJoin(tableName, String localKey, String foreignKey,
|
||||
{String op: '=',
|
||||
List<String> additionalFields: const [],
|
||||
Set<String> trampoline}) {
|
||||
_joins.add(new JoinBuilder(JoinType.left, this,
|
||||
_compileJoin(tableName, trampoline ?? Set()), localKey, foreignKey,
|
||||
op: op, alias: _joinAlias(), additionalFields: additionalFields));
|
||||
}
|
||||
|
||||
/// Execute a `RIGHT JOIN` against another table.
|
||||
void rightJoin(String tableName, String localKey, String foreignKey,
|
||||
{String op: '=', List<String> additionalFields: const []}) {
|
||||
_joins.add(new JoinBuilder(
|
||||
JoinType.right, this, tableName, localKey, foreignKey,
|
||||
void rightJoin(tableName, String localKey, String foreignKey,
|
||||
{String op: '=',
|
||||
List<String> additionalFields: const [],
|
||||
Set<String> trampoline}) {
|
||||
_joins.add(new JoinBuilder(JoinType.right, this,
|
||||
_compileJoin(tableName, trampoline ?? Set()), localKey, foreignKey,
|
||||
op: op, alias: _joinAlias(), additionalFields: additionalFields));
|
||||
}
|
||||
|
||||
/// Execute a `FULL OUTER JOIN` against another table.
|
||||
void fullOuterJoin(String tableName, String localKey, String foreignKey,
|
||||
{String op: '=', List<String> additionalFields: const []}) {
|
||||
_joins.add(new JoinBuilder(
|
||||
JoinType.full, this, tableName, localKey, foreignKey,
|
||||
void fullOuterJoin(tableName, String localKey, String foreignKey,
|
||||
{String op: '=',
|
||||
List<String> additionalFields: const [],
|
||||
Set<String> trampoline}) {
|
||||
_joins.add(new JoinBuilder(JoinType.full, this,
|
||||
_compileJoin(tableName, trampoline ?? Set()), localKey, foreignKey,
|
||||
op: op, alias: _joinAlias(), additionalFields: additionalFields));
|
||||
}
|
||||
|
||||
/// Execute a `SELF JOIN`.
|
||||
void selfJoin(String tableName, String localKey, String foreignKey,
|
||||
{String op: '=', List<String> additionalFields: const []}) {
|
||||
_joins.add(new JoinBuilder(
|
||||
JoinType.self, this, tableName, localKey, foreignKey,
|
||||
void selfJoin(tableName, String localKey, String foreignKey,
|
||||
{String op: '=',
|
||||
List<String> additionalFields: const [],
|
||||
Set<String> trampoline}) {
|
||||
_joins.add(new JoinBuilder(JoinType.self, this,
|
||||
_compileJoin(tableName, trampoline ?? Set()), localKey, foreignKey,
|
||||
op: op, alias: _joinAlias(), additionalFields: additionalFields));
|
||||
}
|
||||
|
||||
@override
|
||||
String compile(
|
||||
String compile(Set<String> trampoline,
|
||||
{bool includeTableName: false,
|
||||
String preamble,
|
||||
bool withFields: true,
|
||||
String fromQuery}) {
|
||||
if (!trampoline.add(tableName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
includeTableName = includeTableName || _joins.isNotEmpty;
|
||||
var b = new StringBuffer(preamble ?? 'SELECT');
|
||||
b.write(' ');
|
||||
|
@ -241,8 +273,12 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
|||
if (fields == null) {
|
||||
f = ['*'];
|
||||
} else {
|
||||
f = new List<String>.from(
|
||||
fields.map((s) => includeTableName ? '$tableName.$s' : s));
|
||||
f = new List<String>.from(fields.map((s) {
|
||||
var ss = includeTableName ? '$tableName.$s' : s;
|
||||
var cast = casts[s];
|
||||
if (cast != null) ss = 'CAST ($ss AS $cast)';
|
||||
return ss;
|
||||
}));
|
||||
_joins.forEach((j) {
|
||||
f
|
||||
..add(j.fieldName)
|
||||
|
@ -256,7 +292,10 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
|||
// No joins if it's not a select.
|
||||
if (preamble == null) {
|
||||
if (_crossJoin != null) b.write(' CROSS JOIN $_crossJoin');
|
||||
for (var join in _joins) b.write(' ${join.compile()}');
|
||||
for (var join in _joins) {
|
||||
var c = join.compile();
|
||||
if (c != null) b.write(' $c');
|
||||
}
|
||||
}
|
||||
|
||||
var whereClause =
|
||||
|
@ -276,7 +315,7 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
|||
}
|
||||
|
||||
Future<List<T>> delete(QueryExecutor executor) {
|
||||
var sql = compile(preamble: 'DELETE', withFields: false);
|
||||
var sql = compile(Set(), preamble: 'DELETE', withFields: false);
|
||||
|
||||
if (_joins.isEmpty) {
|
||||
return executor
|
||||
|
@ -305,7 +344,7 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
|||
} else {
|
||||
// TODO: How to do this in a non-Postgres DB?
|
||||
var returning = fields.map(adornWithTableName).join(', ');
|
||||
var sql = compile();
|
||||
var sql = compile(Set());
|
||||
sql = 'WITH $tableName as ($insertion RETURNING $returning) ' + sql;
|
||||
return executor
|
||||
.query(sql, substitutionValues)
|
||||
|
@ -326,7 +365,7 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
|||
if (_limit != null) updateSql.write(' LIMIT $_limit');
|
||||
|
||||
var returning = fields.map(adornWithTableName).join(', ');
|
||||
var sql = compile();
|
||||
var sql = compile(Set());
|
||||
sql = 'WITH $tableName as ($updateSql RETURNING $returning) ' + sql;
|
||||
|
||||
return executor
|
||||
|
@ -480,10 +519,12 @@ class Union<T> extends QueryBase<T> {
|
|||
T deserialize(List row) => left.deserialize(row);
|
||||
|
||||
@override
|
||||
String compile(
|
||||
String compile(Set<String> trampoline,
|
||||
{bool includeTableName: false, String preamble, bool withFields: true}) {
|
||||
var selector = all == true ? 'UNION ALL' : 'UNION';
|
||||
return '(${left.compile(includeTableName: includeTableName)}) $selector (${right.compile(includeTableName: includeTableName)})';
|
||||
var t1 = Set<String>.from(trampoline);
|
||||
var t2 = Set<String>.from(trampoline);
|
||||
return '(${left.compile(t1, includeTableName: includeTableName)}) $selector (${right.compile(t2, includeTableName: includeTableName)})';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,7 +536,10 @@ class JoinBuilder {
|
|||
final List<String> additionalFields;
|
||||
|
||||
JoinBuilder(this.type, this.from, this.to, this.key, this.value,
|
||||
{this.op: '=', this.alias, this.additionalFields: const []});
|
||||
{this.op: '=', this.alias, this.additionalFields: const []}) {
|
||||
assert(to != null,
|
||||
'computation of this join threw an error, and returned null.');
|
||||
}
|
||||
|
||||
String get fieldName {
|
||||
var right = '$to.$value';
|
||||
|
@ -510,6 +554,7 @@ class JoinBuilder {
|
|||
}
|
||||
|
||||
String compile() {
|
||||
if (to == null) return null;
|
||||
var b = new StringBuffer();
|
||||
var left = '${from.tableName}.$key';
|
||||
var right = fieldName;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: angel_orm
|
||||
version: 2.0.0-dev.18
|
||||
version: 2.0.0-dev.19
|
||||
description: Runtime support for Angel's ORM. Includes base classes for queries.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/orm
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# 2.0.0-dev.5
|
||||
* Implement cast-based `double` support.
|
||||
* Finish `ListSqlExpressionBuilder`.
|
||||
|
||||
# 2.0.0-dev.4
|
||||
* List generation support.
|
||||
|
||||
|
|
|
@ -11,6 +11,14 @@ import 'package:source_gen/source_gen.dart';
|
|||
|
||||
import 'orm_build_context.dart';
|
||||
|
||||
var floatTypes = [
|
||||
ColumnType.decimal,
|
||||
ColumnType.float,
|
||||
ColumnType.numeric,
|
||||
ColumnType.real,
|
||||
const ColumnType('double precision'),
|
||||
];
|
||||
|
||||
Builder ormBuilder(BuilderOptions options) {
|
||||
return new SharedPartBuilder([
|
||||
new OrmGenerator(
|
||||
|
@ -68,6 +76,28 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
]);
|
||||
});
|
||||
|
||||
// Override casts so that we can cast doubles
|
||||
clazz.methods.add(Method((b) {
|
||||
b
|
||||
..name = 'casts'
|
||||
..annotations.add(refer('override'))
|
||||
..type = MethodType.getter
|
||||
..body = Block((b) {
|
||||
var args = <String, Expression>{};
|
||||
|
||||
for (var field in ctx.effectiveFields) {
|
||||
var name = ctx.buildContext.resolveFieldName(field.name);
|
||||
var type = ctx.columns[field.name]?.type;
|
||||
if (type == null) continue;
|
||||
if (floatTypes.contains(type)) {
|
||||
args[name] = literalString('text');
|
||||
}
|
||||
}
|
||||
|
||||
b.addExpression(literalMap(args).returned);
|
||||
});
|
||||
}));
|
||||
|
||||
// Add values
|
||||
clazz.fields.add(new Field((b) {
|
||||
var type = refer('${rc.pascalCase}QueryValues');
|
||||
|
@ -158,6 +188,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
expr = refer('json')
|
||||
.property('decode')
|
||||
.call([expr.asA(refer('String'))]).asA(type);
|
||||
} else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
|
||||
expr = refer('double')
|
||||
.property('parse')
|
||||
.call([expr.property('toString').call([])]);
|
||||
} else if (fType is InterfaceType && fType.element.isEnum) {
|
||||
expr = type.property('values').index(expr.asA(refer('int')));
|
||||
} else
|
||||
|
@ -222,7 +256,18 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
// If there are any relations, we need some overrides.
|
||||
clazz.constructors.add(new Constructor((b) {
|
||||
b
|
||||
..optionalParameters.add(Parameter((b) => b
|
||||
..named = true
|
||||
..name = 'trampoline'
|
||||
..type = TypeReference((b) => b
|
||||
..symbol = 'Set'
|
||||
..types.add(refer('String')))))
|
||||
..body = new Block((b) {
|
||||
b.statements.addAll([
|
||||
Code('trampoline ??= Set();'),
|
||||
Code('trampoline.add(tableName);'),
|
||||
]);
|
||||
|
||||
// Add a constructor that initializes _where
|
||||
b.addExpression(
|
||||
refer('_where')
|
||||
|
@ -248,16 +293,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
var foreignQueryType =
|
||||
foreign.buildContext.modelClassNameRecase.pascalCase +
|
||||
'Query';
|
||||
var compiledSubquery = refer(foreignQueryType)
|
||||
.newInstance([])
|
||||
.property('compile')
|
||||
.call([]);
|
||||
|
||||
joinArgs.insert(
|
||||
0,
|
||||
literalString('(')
|
||||
.operatorAdd(compiledSubquery)
|
||||
.operatorAdd(literalString(')')));
|
||||
refer(foreignQueryType).newInstance(
|
||||
[], {'trampoline': refer('trampoline')}));
|
||||
} else {
|
||||
joinArgs.insert(0, literalString(foreign.tableName));
|
||||
}
|
||||
|
@ -580,11 +619,13 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
for (var field in ctx.effectiveFields) {
|
||||
var fType = field.type;
|
||||
var name = ctx.buildContext.resolveFieldName(field.name);
|
||||
var type = ctx.columns[field.name]?.type?.name;
|
||||
var type = ctx.columns[field.name]?.type;
|
||||
if (type == null) continue;
|
||||
if (const TypeChecker.fromRuntime(List)
|
||||
.isAssignableFromType(fType)) {
|
||||
args[name] = literalString(type);
|
||||
args[name] = literalString(type.name);
|
||||
} else if (floatTypes.contains(type)) {
|
||||
args[name] = literalString(type.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -612,6 +653,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
value = refer('json')
|
||||
.property('decode')
|
||||
.call([value.asA(refer('String'))]).asA(refer('List'));
|
||||
} else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
|
||||
value = refer('double')
|
||||
.property('parse')
|
||||
.call([value.asA(refer('String'))]);
|
||||
} else {
|
||||
value = value.asA(type);
|
||||
}
|
||||
|
@ -631,6 +676,8 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
|||
} else if (const TypeChecker.fromRuntime(List)
|
||||
.isAssignableFromType(fType)) {
|
||||
value = refer('json').property('encode').call([value]);
|
||||
} else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
|
||||
value = value.property('toString').call([]);
|
||||
}
|
||||
|
||||
b
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: angel_orm_generator
|
||||
version: 2.0.0-dev.4
|
||||
version: 2.0.0-dev.5
|
||||
description: Code generators for Angel's ORM. Generates query builder classes.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/orm
|
||||
|
|
|
@ -54,7 +54,7 @@ main() {
|
|||
test('select one', () async {
|
||||
var query = new BookQuery();
|
||||
query.where.id.equals(int.parse(deathlyHallows.id));
|
||||
print(query.compile());
|
||||
print(query.compile(Set()));
|
||||
|
||||
var book = await query.getOne(executor);
|
||||
print(book.toJson());
|
||||
|
@ -71,7 +71,7 @@ main() {
|
|||
var query = new BookQuery()
|
||||
..where.name.equals('Goblet of Fire')
|
||||
..orWhere((w) => w.authorId.equals(int.parse(jkRowling.id)));
|
||||
print(query.compile());
|
||||
print(query.compile(Set()));
|
||||
|
||||
var books = await query.get(executor);
|
||||
expect(books, hasLength(1));
|
||||
|
@ -95,7 +95,7 @@ main() {
|
|||
query1
|
||||
..union(query2)
|
||||
..unionAll(query3);
|
||||
print(query1.compile());
|
||||
print(query1.compile(Set()));
|
||||
|
||||
var books = await query1.get(executor);
|
||||
expect(books, hasLength(1));
|
||||
|
@ -120,7 +120,7 @@ main() {
|
|||
|
||||
test('delete stream', () async {
|
||||
var query = new BookQuery()..where.name.equals(deathlyHallows.name);
|
||||
print(query.compile());
|
||||
print(query.compile(Set()));
|
||||
var books = await query.delete(executor);
|
||||
expect(books, hasLength(1));
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ main() {
|
|||
test('can fetch one foot', () async {
|
||||
var footQuery = new FootQuery()
|
||||
..values.legId = int.parse(originalLeg.id)
|
||||
..values.nToes = 5;
|
||||
..values.nToes = 5.64;
|
||||
var legQuery = new LegQuery()..where.id.equals(int.parse(originalLeg.id));
|
||||
var foot = await footQuery.insert(executor);
|
||||
var leg = await legQuery.getOne(executor);
|
||||
|
@ -57,7 +57,7 @@ main() {
|
|||
test('sets foot on update', () async {
|
||||
var footQuery = new FootQuery()
|
||||
..values.legId = int.parse(originalLeg.id)
|
||||
..values.nToes = 5;
|
||||
..values.nToes = 5.64;
|
||||
var legQuery = new LegQuery()
|
||||
..where.id.equals(int.parse(originalLeg.id))
|
||||
..values.copyFrom(originalLeg.copyWith(name: 'Right'));
|
||||
|
@ -73,7 +73,7 @@ main() {
|
|||
test('sets foot on delete', () async {
|
||||
var footQuery = new FootQuery()
|
||||
..values.legId = int.parse(originalLeg.id)
|
||||
..values.nToes = 5;
|
||||
..values.nToes = 5.64;
|
||||
var legQuery = new LegQuery()..where.id.equals(int.parse(originalLeg.id));
|
||||
var foot = await footQuery.insert(executor);
|
||||
var leg = await legQuery.deleteOne(executor);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
CREATE TEMPORARY TABLE "user_roles" (
|
||||
CREATE TEMPORARY TABLE "role_users" (
|
||||
"id" serial PRIMARY KEY,
|
||||
"user_id" int NOT NULL,
|
||||
"role_id" int NOT NULL,
|
||||
|
|
|
@ -28,7 +28,9 @@ class AuthorMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class AuthorQuery extends Query<Author, AuthorQueryWhere> {
|
||||
AuthorQuery() {
|
||||
AuthorQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new AuthorQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -37,6 +39,11 @@ class AuthorQuery extends Query<Author, AuthorQueryWhere> {
|
|||
|
||||
AuthorQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'authors';
|
||||
|
|
|
@ -30,7 +30,9 @@ class BookMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class BookQuery extends Query<Book, BookQueryWhere> {
|
||||
BookQuery() {
|
||||
BookQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new BookQueryWhere(this);
|
||||
leftJoin('authors', 'author_id', 'id',
|
||||
additionalFields: const ['name', 'created_at', 'updated_at']);
|
||||
|
@ -43,6 +45,11 @@ class BookQuery extends Query<Book, BookQueryWhere> {
|
|||
|
||||
BookQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'books';
|
||||
|
|
|
@ -31,7 +31,9 @@ class CarMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class CarQuery extends Query<Car, CarQueryWhere> {
|
||||
CarQuery() {
|
||||
CarQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new CarQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -40,6 +42,11 @@ class CarQuery extends Query<Car, CarQueryWhere> {
|
|||
|
||||
CarQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'cars';
|
||||
|
|
|
@ -27,7 +27,9 @@ class CustomerMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
|
||||
CustomerQuery() {
|
||||
CustomerQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new CustomerQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -36,6 +38,11 @@ class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
|
|||
|
||||
CustomerQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'customers';
|
||||
|
|
|
@ -9,5 +9,7 @@ part 'foot.g.dart';
|
|||
@serializable
|
||||
@Orm(tableName: 'feet')
|
||||
class _Foot extends Model {
|
||||
int legId, nToes;
|
||||
int legId;
|
||||
|
||||
double nToes;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ class FootMigration extends Migration {
|
|||
schema.create('feet', (table) {
|
||||
table.serial('id')..primaryKey();
|
||||
table.integer('leg_id');
|
||||
table.integer('n_toes');
|
||||
table.declare('n_toes', new ColumnType('decimal'));
|
||||
table.timeStamp('created_at');
|
||||
table.timeStamp('updated_at');
|
||||
});
|
||||
|
@ -29,7 +29,9 @@ class FootMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class FootQuery extends Query<Foot, FootQueryWhere> {
|
||||
FootQuery() {
|
||||
FootQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new FootQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -38,6 +40,11 @@ class FootQuery extends Query<Foot, FootQueryWhere> {
|
|||
|
||||
FootQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {'n_toes': 'text'};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'feet';
|
||||
|
@ -63,7 +70,7 @@ class FootQuery extends Query<Foot, FootQueryWhere> {
|
|||
var model = new Foot(
|
||||
id: row[0].toString(),
|
||||
legId: (row[1] as int),
|
||||
nToes: (row[2] as int),
|
||||
nToes: double.parse(row[2].toString()),
|
||||
createdAt: (row[3] as DateTime),
|
||||
updatedAt: (row[4] as DateTime));
|
||||
return model;
|
||||
|
@ -79,7 +86,7 @@ class FootQueryWhere extends QueryWhere {
|
|||
FootQueryWhere(FootQuery query)
|
||||
: id = new NumericSqlExpressionBuilder<int>(query, 'id'),
|
||||
legId = new NumericSqlExpressionBuilder<int>(query, 'leg_id'),
|
||||
nToes = new NumericSqlExpressionBuilder<int>(query, 'n_toes'),
|
||||
nToes = new NumericSqlExpressionBuilder<double>(query, 'n_toes'),
|
||||
createdAt = new DateTimeSqlExpressionBuilder(query, 'created_at'),
|
||||
updatedAt = new DateTimeSqlExpressionBuilder(query, 'updated_at');
|
||||
|
||||
|
@ -87,7 +94,7 @@ class FootQueryWhere extends QueryWhere {
|
|||
|
||||
final NumericSqlExpressionBuilder<int> legId;
|
||||
|
||||
final NumericSqlExpressionBuilder<int> nToes;
|
||||
final NumericSqlExpressionBuilder<double> nToes;
|
||||
|
||||
final DateTimeSqlExpressionBuilder createdAt;
|
||||
|
||||
|
@ -102,7 +109,7 @@ class FootQueryWhere extends QueryWhere {
|
|||
class FootQueryValues extends MapQueryValues {
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
return {'n_toes': 'decimal'};
|
||||
}
|
||||
|
||||
int get id {
|
||||
|
@ -115,11 +122,11 @@ class FootQueryValues extends MapQueryValues {
|
|||
}
|
||||
|
||||
set legId(int value) => values['leg_id'] = value;
|
||||
int get nToes {
|
||||
return (values['n_toes'] as int);
|
||||
double get nToes {
|
||||
return double.parse((values['n_toes'] as String));
|
||||
}
|
||||
|
||||
set nToes(int value) => values['n_toes'] = value;
|
||||
set nToes(double value) => values['n_toes'] = value.toString();
|
||||
DateTime get createdAt {
|
||||
return (values['created_at'] as DateTime);
|
||||
}
|
||||
|
@ -153,7 +160,7 @@ class Foot extends _Foot {
|
|||
final int legId;
|
||||
|
||||
@override
|
||||
final int nToes;
|
||||
final double nToes;
|
||||
|
||||
@override
|
||||
final DateTime createdAt;
|
||||
|
@ -164,7 +171,7 @@ class Foot extends _Foot {
|
|||
Foot copyWith(
|
||||
{String id,
|
||||
int legId,
|
||||
int nToes,
|
||||
double nToes,
|
||||
DateTime createdAt,
|
||||
DateTime updatedAt}) {
|
||||
return new Foot(
|
||||
|
@ -203,7 +210,7 @@ abstract class FootSerializer {
|
|||
return new Foot(
|
||||
id: map['id'] as String,
|
||||
legId: map['leg_id'] as int,
|
||||
nToes: map['n_toes'] as int,
|
||||
nToes: map['n_toes'] as double,
|
||||
createdAt: map['created_at'] != null
|
||||
? (map['created_at'] is DateTime
|
||||
? (map['created_at'] as DateTime)
|
||||
|
|
|
@ -29,7 +29,9 @@ class FruitMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class FruitQuery extends Query<Fruit, FruitQueryWhere> {
|
||||
FruitQuery() {
|
||||
FruitQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new FruitQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -38,6 +40,11 @@ class FruitQuery extends Query<Fruit, FruitQueryWhere> {
|
|||
|
||||
FruitQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'fruits';
|
||||
|
|
|
@ -28,7 +28,9 @@ class HasCarMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class HasCarQuery extends Query<HasCar, HasCarQueryWhere> {
|
||||
HasCarQuery() {
|
||||
HasCarQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new HasCarQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -37,6 +39,11 @@ class HasCarQuery extends Query<HasCar, HasCarQueryWhere> {
|
|||
|
||||
HasCarQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'has_cars';
|
||||
|
|
|
@ -26,7 +26,9 @@ class HasMapMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
|
||||
HasMapQuery() {
|
||||
HasMapQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new HasMapQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -35,6 +37,11 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
|
|||
|
||||
HasMapQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'has_maps';
|
||||
|
|
|
@ -28,7 +28,9 @@ class LegMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class LegQuery extends Query<Leg, LegQueryWhere> {
|
||||
LegQuery() {
|
||||
LegQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new LegQueryWhere(this);
|
||||
leftJoin('feet', 'id', 'leg_id', additionalFields: const [
|
||||
'leg_id',
|
||||
|
@ -43,6 +45,11 @@ class LegQuery extends Query<Leg, LegQueryWhere> {
|
|||
|
||||
LegQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'legs';
|
||||
|
|
|
@ -31,7 +31,9 @@ class OrderMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class OrderQuery extends Query<Order, OrderQueryWhere> {
|
||||
OrderQuery() {
|
||||
OrderQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new OrderQueryWhere(this);
|
||||
leftJoin('customers', 'customer_id', 'id',
|
||||
additionalFields: const ['created_at', 'updated_at']);
|
||||
|
@ -42,6 +44,11 @@ class OrderQuery extends Query<Order, OrderQueryWhere> {
|
|||
|
||||
OrderQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'orders';
|
||||
|
|
|
@ -28,9 +28,11 @@ class TreeMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class TreeQuery extends Query<Tree, TreeQueryWhere> {
|
||||
TreeQuery() {
|
||||
TreeQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new TreeQueryWhere(this);
|
||||
leftJoin('(' + new FruitQuery().compile() + ')', 'id', 'tree_id',
|
||||
leftJoin(new FruitQuery(trampoline: trampoline), 'id', 'tree_id',
|
||||
additionalFields: const [
|
||||
'tree_id',
|
||||
'common_name',
|
||||
|
@ -44,6 +46,11 @@ class TreeQuery extends Query<Tree, TreeQueryWhere> {
|
|||
|
||||
TreeQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'trees';
|
||||
|
|
|
@ -65,7 +65,9 @@ class RoleMigration extends Migration {
|
|||
// **************************************************************************
|
||||
|
||||
class UserQuery extends Query<User, UserQueryWhere> {
|
||||
UserQuery() {
|
||||
UserQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new UserQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -74,6 +76,11 @@ class UserQuery extends Query<User, UserQueryWhere> {
|
|||
|
||||
UserQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'users';
|
||||
|
@ -192,7 +199,9 @@ class UserQueryValues extends MapQueryValues {
|
|||
}
|
||||
|
||||
class RoleUserQuery extends Query<RoleUser, RoleUserQueryWhere> {
|
||||
RoleUserQuery() {
|
||||
RoleUserQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new RoleUserQueryWhere(this);
|
||||
leftJoin('roles', 'role_id', 'id',
|
||||
additionalFields: const ['name', 'created_at', 'updated_at']);
|
||||
|
@ -210,6 +219,11 @@ class RoleUserQuery extends Query<RoleUser, RoleUserQueryWhere> {
|
|||
|
||||
RoleUserQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'role_users';
|
||||
|
@ -319,7 +333,9 @@ class RoleUserQueryValues extends MapQueryValues {
|
|||
}
|
||||
|
||||
class RoleQuery extends Query<Role, RoleQueryWhere> {
|
||||
RoleQuery() {
|
||||
RoleQuery({Set<String> trampoline}) {
|
||||
trampoline ??= Set();
|
||||
trampoline.add(tableName);
|
||||
_where = new RoleQueryWhere(this);
|
||||
}
|
||||
|
||||
|
@ -328,6 +344,11 @@ class RoleQuery extends Query<Role, RoleQueryWhere> {
|
|||
|
||||
RoleQueryWhere _where;
|
||||
|
||||
@override
|
||||
get casts {
|
||||
return {};
|
||||
}
|
||||
|
||||
@override
|
||||
get tableName {
|
||||
return 'roles';
|
||||
|
|
|
@ -82,7 +82,7 @@ main() {
|
|||
var query2 = new CarQuery()..where.familyFriendly.isTrue;
|
||||
var query3 = new CarQuery()..where.description.equals('Submarine');
|
||||
var union = query1.union(query2).unionAll(query3);
|
||||
print(union.compile());
|
||||
print(union.compile(Set()));
|
||||
var cars = await union.get(connection);
|
||||
expect(cars, hasLength(1));
|
||||
});
|
||||
|
@ -93,14 +93,14 @@ main() {
|
|||
..orWhere((where) => where
|
||||
..familyFriendly.isTrue
|
||||
..make.equals('Honda'));
|
||||
print(query.compile());
|
||||
print(query.compile(Set()));
|
||||
var cars = await query.get(connection);
|
||||
expect(cars, hasLength(1));
|
||||
});
|
||||
|
||||
test('limit obeyed', () async {
|
||||
var query = new CarQuery()..limit(0);
|
||||
print(query.compile());
|
||||
print(query.compile(Set()));
|
||||
var cars = await query.get(connection);
|
||||
expect(cars, isEmpty);
|
||||
});
|
||||
|
@ -126,7 +126,7 @@ main() {
|
|||
var query = new CarQuery()
|
||||
..where.make.equals('Ferrari東')
|
||||
..orWhere((w) => w.familyFriendly.isTrue);
|
||||
print(query.compile(preamble: 'DELETE FROM "cars"'));
|
||||
print(query.compile(Set(), preamble: 'DELETE FROM "cars"'));
|
||||
|
||||
var cars = await query.delete(connection);
|
||||
expect(cars, hasLength(1));
|
||||
|
|
Loading…
Reference in a new issue