Alias all fields in child queries

This commit is contained in:
Tobe O 2019-10-12 14:36:24 -04:00
parent 2a8a186bca
commit 8222230c8a
5 changed files with 43 additions and 13 deletions

View file

@ -1,3 +1,7 @@
# 2.1.0-beta.1
* Calls to `leftJoin`, etc. alias all fields in a child query, to prevent
`ambiguous column a0.id` errors.
# 2.1.0-beta
* Split the formerly 600+ line `src/query.dart` up into
separate files.

View file

@ -6,6 +6,7 @@ class JoinBuilder {
final JoinType type;
final Query from;
final String key, value, op, alias;
final bool aliasAllFields;
/// A callback to produces the expression to join against, i.e.
/// a table name, or the result of compiling a query.
@ -13,34 +14,37 @@ 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 [],
this.aliasAllFields = false}) {
assert(to != null,
'computation of this join threw an error, and returned null.');
}
String get fieldName {
var right = '$to.$value';
if (alias != null) right = '$alias.$value';
var v = value;
if (aliasAllFields) {
v = '${alias}_$v';
}
var right = '${from.tableName}.$v';
if (alias != null) right = '$alias.$v';
return right;
}
String nameFor(String name) {
var right = '$to.$name';
if (aliasAllFields) name = '${alias}_$name';
var right = '${from.tableName}.$name';
if (alias != null) right = '$alias.$name';
return right;
}
String compile(Set<String> trampoline) {
var compiledTo = to();
if (compiledTo == null) {
print(
'NULLLLL $to; from $from; key: $key, value: $value, addl: $additionalFields');
}
if (compiledTo == null) return null;
var b = StringBuffer();
var left = '${from.tableName}.$key';
var right = fieldName;
switch (type) {
case JoinType.inner:
b.write(' INNER JOIN');

View file

@ -151,10 +151,17 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
var to = _compileJoin(tableName, trampoline);
if (to != null) {
var alias = _joinAlias(trampoline);
if (tableName is Query) {
for (var field in tableName.fields) {
tableName.aliases[field] = '${alias}_$field';
}
}
_joins.add(JoinBuilder(type, this, to, localKey, foreignKey,
op: op,
alias: _joinAlias(trampoline),
additionalFields: additionalFields));
alias: alias,
additionalFields: additionalFields,
aliasAllFields: tableName is Query));
}
}
@ -228,6 +235,13 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
var ss = includeTableName ? '$tableName.$s' : s;
var cast = casts[s];
if (cast != null) ss = 'CAST ($ss AS $cast)';
if (aliases.containsKey(s)) {
if (cast != null) {
ss = '($ss) AS ${aliases[s]}';
} else {
ss = '$ss AS ${aliases[s]}';
}
}
return ss;
}));
_joins.forEach((j) {

View file

@ -7,6 +7,9 @@ abstract class QueryBase<T> {
/// Casts to perform when querying the database.
Map<String, String> get casts => {};
/// `AS` aliases to inject into the query, if any.
Map<String, String> aliases = {};
/// Values to insert into a prepared statement.
final Map<String, dynamic> substitutionValues = {};
@ -21,7 +24,12 @@ abstract class QueryBase<T> {
/// A String of all [fields], joined by a comma (`,`).
String get fieldSet => fields.map((k) {
var cast = casts[k];
return cast == null ? k : 'CAST ($k AS $cast)';
if (!aliases.containsKey(k)) {
return cast == null ? k : 'CAST ($k AS $cast)';
} else {
var inner = cast == null ? k : '(CAST ($k AS $cast))';
return '$inner AS ${aliases[k]}';
}
}).join(', ');
String compile(Set<String> trampoline,

View file

@ -1,5 +1,5 @@
name: angel_orm
version: 2.1.0-beta
version: 2.1.0-beta.1
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