Added Optional package
This commit is contained in:
parent
7644d8c2d2
commit
d241d7ca77
11 changed files with 74 additions and 56 deletions
|
@ -15,7 +15,9 @@ void main() async {
|
||||||
..join('companies', 'company_id', 'id');
|
..join('companies', 'company_id', 'id');
|
||||||
|
|
||||||
var richPerson = await query.getOne(_FakeExecutor());
|
var richPerson = await query.getOne(_FakeExecutor());
|
||||||
print(richPerson?.toJson());
|
if (richPerson.isPresent) {
|
||||||
|
print(richPerson.first.toJson());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FakeExecutor extends QueryExecutor {
|
class _FakeExecutor extends QueryExecutor {
|
||||||
|
@ -24,7 +26,7 @@ class _FakeExecutor extends QueryExecutor {
|
||||||
@override
|
@override
|
||||||
Future<List<List>> query(
|
Future<List<List>> query(
|
||||||
String tableName, String? query, Map<String, dynamic> substitutionValues,
|
String tableName, String? query, Map<String, dynamic> substitutionValues,
|
||||||
[returningFields]) async {
|
[returningFields = const []]) async {
|
||||||
var now = DateTime.now();
|
var now = DateTime.now();
|
||||||
print(
|
print(
|
||||||
'_FakeExecutor received query: $query and values: $substitutionValues');
|
'_FakeExecutor received query: $query and values: $substitutionValues');
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'query_base.dart';
|
||||||
import 'query_executor.dart';
|
import 'query_executor.dart';
|
||||||
import 'query_values.dart';
|
import 'query_values.dart';
|
||||||
import 'query_where.dart';
|
import 'query_where.dart';
|
||||||
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
/// A SQL `SELECT` query builder.
|
/// A SQL `SELECT` query builder.
|
||||||
abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
|
@ -125,7 +126,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _joinAlias(Set<String>? trampoline) {
|
String _joinAlias(Set<String>? trampoline) {
|
||||||
int i = _joins.length;
|
var i = _joins.length;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var a = 'a$i';
|
var a = 'a$i';
|
||||||
|
@ -137,13 +138,13 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? Function() _compileJoin(tableName, Set<String>? trampoline) {
|
String? Function() _compileJoin(tableName, Set<String> trampoline) {
|
||||||
if (tableName is String) {
|
if (tableName is String) {
|
||||||
return () => tableName;
|
return () => tableName;
|
||||||
} else if (tableName is Query) {
|
} else if (tableName is Query) {
|
||||||
return () {
|
return () {
|
||||||
var c = tableName.compile(trampoline);
|
var c = tableName.compile(trampoline);
|
||||||
if (c == null) return c;
|
//if (c == null) return c;
|
||||||
return '($c)';
|
return '($c)';
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -160,7 +161,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
String foreignKey,
|
String foreignKey,
|
||||||
String op,
|
String op,
|
||||||
List<String> additionalFields) {
|
List<String> additionalFields) {
|
||||||
trampoline ??= Set();
|
trampoline ??= <String>{};
|
||||||
|
|
||||||
// Pivot tables guard against ambiguous fields by excluding tables
|
// Pivot tables guard against ambiguous fields by excluding tables
|
||||||
// that have already been queried in this scope.
|
// that have already been queried in this scope.
|
||||||
|
@ -170,19 +171,17 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
var to = _compileJoin(tableName, trampoline);
|
var to = _compileJoin(tableName, trampoline);
|
||||||
if (to != null) {
|
var alias = _joinAlias(trampoline);
|
||||||
var alias = _joinAlias(trampoline);
|
if (tableName is Query) {
|
||||||
if (tableName is Query) {
|
for (var field in tableName.fields) {
|
||||||
for (var field in tableName.fields) {
|
tableName.aliases[field] = '${alias}_$field';
|
||||||
tableName.aliases[field] = '${alias}_$field';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_joins.add(JoinBuilder(type, this, to, localKey, foreignKey,
|
|
||||||
op: op,
|
|
||||||
alias: alias,
|
|
||||||
additionalFields: additionalFields,
|
|
||||||
aliasAllFields: tableName is Query));
|
|
||||||
}
|
}
|
||||||
|
_joins.add(JoinBuilder(type, this, to, localKey, foreignKey,
|
||||||
|
op: op,
|
||||||
|
alias: alias,
|
||||||
|
additionalFields: additionalFields,
|
||||||
|
aliasAllFields: tableName is Query));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute an `INNER JOIN` against another table.
|
/// Execute an `INNER JOIN` against another table.
|
||||||
|
@ -231,14 +230,15 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? compile(Set<String>? trampoline,
|
String compile(Set<String> trampoline,
|
||||||
{bool includeTableName = false,
|
{bool includeTableName = false,
|
||||||
String? preamble,
|
String? preamble,
|
||||||
bool withFields = true,
|
bool withFields = true,
|
||||||
String? fromQuery}) {
|
String? fromQuery}) {
|
||||||
// One table MAY appear multiple times in a query.
|
// One table MAY appear multiple times in a query.
|
||||||
if (!canCompile(trampoline)) {
|
if (!canCompile(trampoline)) {
|
||||||
return null;
|
//return null;
|
||||||
|
throw Exception('One table appear multiple times in a query');
|
||||||
}
|
}
|
||||||
|
|
||||||
includeTableName = includeTableName || _joins.isNotEmpty;
|
includeTableName = includeTableName || _joins.isNotEmpty;
|
||||||
|
@ -320,7 +320,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<T?> getOne(QueryExecutor executor) {
|
Future<Optional<T>> getOne(QueryExecutor executor) {
|
||||||
//limit(1);
|
//limit(1);
|
||||||
return super.getOne(executor);
|
return super.getOne(executor);
|
||||||
}
|
}
|
||||||
|
@ -358,7 +358,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
} else {
|
} else {
|
||||||
// TODO: How to do this in a non-Postgres DB?
|
// TODO: How to do this in a non-Postgres DB?
|
||||||
var returning = fields.map(adornWithTableName).join(', ');
|
var returning = fields.map(adornWithTableName).join(', ');
|
||||||
var sql = compile({})!;
|
var sql = compile({});
|
||||||
sql = 'WITH $tableName as ($insertion RETURNING $returning) ' + sql;
|
sql = 'WITH $tableName as ($insertion RETURNING $returning) ' + sql;
|
||||||
return executor
|
return executor
|
||||||
.query(tableName, sql, substitutionValues)
|
.query(tableName, sql, substitutionValues)
|
||||||
|
@ -381,7 +381,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
|
||||||
if (_limit != null) updateSql.write(' LIMIT $_limit');
|
if (_limit != null) updateSql.write(' LIMIT $_limit');
|
||||||
|
|
||||||
var returning = fields.map(adornWithTableName).join(', ');
|
var returning = fields.map(adornWithTableName).join(', ');
|
||||||
var sql = compile({})!;
|
var sql = compile({});
|
||||||
sql = 'WITH $tableName as ($updateSql RETURNING $returning) ' + sql;
|
sql = 'WITH $tableName as ($updateSql RETURNING $returning) ' + sql;
|
||||||
|
|
||||||
return executor
|
return executor
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'query_executor.dart';
|
import 'query_executor.dart';
|
||||||
import 'union.dart';
|
import 'union.dart';
|
||||||
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
/// A base class for objects that compile to SQL queries, typically within an ORM.
|
/// A base class for objects that compile to SQL queries, typically within an ORM.
|
||||||
abstract class QueryBase<T> {
|
abstract class QueryBase<T> {
|
||||||
|
@ -32,9 +33,9 @@ abstract class QueryBase<T> {
|
||||||
}
|
}
|
||||||
}).join(', ');
|
}).join(', ');
|
||||||
|
|
||||||
String? compile(Set<String> trampoline,
|
String compile(Set<String> trampoline,
|
||||||
{bool includeTableName = false,
|
{bool includeTableName = false,
|
||||||
String? preamble,
|
String preamble = '',
|
||||||
bool withFields = true});
|
bool withFields = true});
|
||||||
|
|
||||||
T deserialize(List row);
|
T deserialize(List row);
|
||||||
|
@ -46,8 +47,10 @@ abstract class QueryBase<T> {
|
||||||
.then((it) => it.map(deserialize).toList());
|
.then((it) => it.map(deserialize).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<T?> getOne(QueryExecutor executor) {
|
Future<Optional<T>> getOne(QueryExecutor executor) {
|
||||||
return get(executor).then((it) => it.isEmpty ? null : it.first);
|
//return get(executor).then((it) => it.isEmpty ? : it.first);
|
||||||
|
return get(executor).then(
|
||||||
|
(it) => it.isEmpty ? Optional.empty() : Optional.ofNullable(it.first));
|
||||||
}
|
}
|
||||||
|
|
||||||
Union<T> union(QueryBase<T> other) {
|
Union<T> union(QueryBase<T> other) {
|
||||||
|
|
|
@ -8,8 +8,8 @@ abstract class QueryExecutor {
|
||||||
|
|
||||||
/// Executes a single query.
|
/// Executes a single query.
|
||||||
Future<List<List>> query(
|
Future<List<List>> query(
|
||||||
String tableName, String? query, Map<String, dynamic> substitutionValues,
|
String tableName, String query, Map<String, dynamic> substitutionValues,
|
||||||
[List<String>? returningFields]);
|
[List<String> returningFields = const []]);
|
||||||
|
|
||||||
/// Enters a database transaction, performing the actions within,
|
/// Enters a database transaction, performing the actions within,
|
||||||
/// and returning the results of [f].
|
/// and returning the results of [f].
|
||||||
|
|
|
@ -28,3 +28,4 @@ dev_dependencies:
|
||||||
build_runner: ^2.0.1
|
build_runner: ^2.0.1
|
||||||
pedantic: ^1.11.0
|
pedantic: ^1.11.0
|
||||||
test: ^1.17.3
|
test: ^1.17.3
|
||||||
|
optional: ^6.0.0-nullsafety.2
|
||||||
|
|
|
@ -27,3 +27,8 @@ dev_dependencies:
|
||||||
ref: sdk-2.12.x_nnbd
|
ref: sdk-2.12.x_nnbd
|
||||||
path: packages/pretty_logging
|
path: packages/pretty_logging
|
||||||
test: ^1.17.3
|
test: ^1.17.3
|
||||||
|
#dependency_overrides:
|
||||||
|
# angel_orm_test:
|
||||||
|
# path: ../angel_orm_test
|
||||||
|
# angel_orm:
|
||||||
|
# path: ../angel_orm
|
||||||
|
|
|
@ -160,13 +160,13 @@ class TreeQuery extends Query<Tree?, TreeQueryWhere?> {
|
||||||
@override
|
@override
|
||||||
delete(QueryExecutor executor) {
|
delete(QueryExecutor executor) {
|
||||||
return super.delete(executor).then((result) {
|
return super.delete(executor).then((result) {
|
||||||
return result.fold<List<Tree?>>([], (out, model) {
|
return result.fold<List<Tree>>([], (out, model) {
|
||||||
var idx = out.indexWhere((m) => m!.id == model!.id);
|
var idx = out.indexWhere((m) => m.id == model!.id);
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return out..add(model);
|
return out..add(model!);
|
||||||
} else {
|
} else {
|
||||||
var l = out[idx]!;
|
var l = out[idx];
|
||||||
return out
|
return out
|
||||||
..[idx] = l.copyWith(
|
..[idx] = l.copyWith(
|
||||||
fruits: List<_Fruit>.from(l.fruits ?? [])
|
fruits: List<_Fruit>.from(l.fruits ?? [])
|
||||||
|
|
|
@ -304,18 +304,21 @@ class WeirdJoinQuery extends Query<WeirdJoin?, WeirdJoinQueryWhere?> {
|
||||||
@override
|
@override
|
||||||
get(QueryExecutor executor) {
|
get(QueryExecutor executor) {
|
||||||
return super.get(executor).then((result) {
|
return super.get(executor).then((result) {
|
||||||
return result.fold<List<WeirdJoin?>>([], (out, model) {
|
return result.fold<List<WeirdJoin>>([], (out, model) {
|
||||||
var idx = out.indexWhere((m) => m!.id == model!.id);
|
var idx = out.indexWhere((m) => m.id == model!.id);
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return out..add(model);
|
return out..add(model!);
|
||||||
} else {
|
} else {
|
||||||
var l = out[idx]!;
|
var l = out[idx];
|
||||||
return out
|
return out
|
||||||
..[idx] = l.copyWith(
|
..[idx] = l.copyWith(
|
||||||
numbas: List<_Numba?>.from(l.numbas ?? [])
|
numbas: List<_Numba>.from(l.numbas ?? [])
|
||||||
..addAll(model!.numbas ?? []),
|
..addAll(model == null
|
||||||
foos: List<_Foo?>.from(l.foos ?? [])..addAll(model.foos ?? []));
|
? []
|
||||||
|
: List<_Numba>.from(model.numbas ?? [])),
|
||||||
|
foos: List<_Foo?>.from(l.foos ?? [])
|
||||||
|
..addAll(model?.foos ?? []));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -324,13 +327,13 @@ class WeirdJoinQuery extends Query<WeirdJoin?, WeirdJoinQueryWhere?> {
|
||||||
@override
|
@override
|
||||||
update(QueryExecutor executor) {
|
update(QueryExecutor executor) {
|
||||||
return super.update(executor).then((result) {
|
return super.update(executor).then((result) {
|
||||||
return result.fold<List<WeirdJoin?>>([], (out, model) {
|
return result.fold<List<WeirdJoin>>([], (out, model) {
|
||||||
var idx = out.indexWhere((m) => m!.id == model!.id);
|
var idx = out.indexWhere((m) => m.id == model!.id);
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return out..add(model);
|
return out..add(model!);
|
||||||
} else {
|
} else {
|
||||||
var l = out[idx]!;
|
var l = out[idx];
|
||||||
return out
|
return out
|
||||||
..[idx] = l.copyWith(
|
..[idx] = l.copyWith(
|
||||||
numbas: List<_Numba?>.from(l.numbas ?? [])
|
numbas: List<_Numba?>.from(l.numbas ?? [])
|
||||||
|
@ -344,13 +347,13 @@ class WeirdJoinQuery extends Query<WeirdJoin?, WeirdJoinQueryWhere?> {
|
||||||
@override
|
@override
|
||||||
delete(QueryExecutor executor) {
|
delete(QueryExecutor executor) {
|
||||||
return super.delete(executor).then((result) {
|
return super.delete(executor).then((result) {
|
||||||
return result.fold<List<WeirdJoin?>>([], (out, model) {
|
return result.fold<List<WeirdJoin>>([], (out, model) {
|
||||||
var idx = out.indexWhere((m) => m!.id == model!.id);
|
var idx = out.indexWhere((m) => m.id == model!.id);
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return out..add(model);
|
return out..add(model!);
|
||||||
} else {
|
} else {
|
||||||
var l = out[idx]!;
|
var l = out[idx];
|
||||||
return out
|
return out
|
||||||
..[idx] = l.copyWith(
|
..[idx] = l.copyWith(
|
||||||
numbas: List<_Numba?>.from(l.numbas ?? [])
|
numbas: List<_Numba?>.from(l.numbas ?? [])
|
||||||
|
|
|
@ -473,13 +473,13 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
|
||||||
@override
|
@override
|
||||||
get(QueryExecutor executor) {
|
get(QueryExecutor executor) {
|
||||||
return super.get(executor).then((result) {
|
return super.get(executor).then((result) {
|
||||||
return result.fold<List<Role?>>([], (out, model) {
|
return result.fold<List<Role>>([], (out, model) {
|
||||||
var idx = out.indexWhere((m) => m!.id == model!.id);
|
var idx = out.indexWhere((m) => m.id == model!.id);
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return out..add(model);
|
return out..add(model!);
|
||||||
} else {
|
} else {
|
||||||
var l = out[idx]!;
|
var l = out[idx];
|
||||||
return out
|
return out
|
||||||
..[idx] = l.copyWith(
|
..[idx] = l.copyWith(
|
||||||
users: List<_User>.from(l.users)..addAll(model!.users));
|
users: List<_User>.from(l.users)..addAll(model!.users));
|
||||||
|
@ -509,13 +509,13 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
|
||||||
@override
|
@override
|
||||||
delete(QueryExecutor executor) {
|
delete(QueryExecutor executor) {
|
||||||
return super.delete(executor).then((result) {
|
return super.delete(executor).then((result) {
|
||||||
return result.fold<List<Role?>>([], (out, model) {
|
return result.fold<List<Role>>([], (out, model) {
|
||||||
var idx = out.indexWhere((m) => m!.id == model!.id);
|
var idx = out.indexWhere((m) => m.id == model!.id);
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return out..add(model);
|
return out..add(model!);
|
||||||
} else {
|
} else {
|
||||||
var l = out[idx]!;
|
var l = out[idx];
|
||||||
return out
|
return out
|
||||||
..[idx] = l.copyWith(
|
..[idx] = l.copyWith(
|
||||||
users: List<_User>.from(l.users)..addAll(model!.users));
|
users: List<_User>.from(l.users)..addAll(model!.users));
|
||||||
|
|
|
@ -130,7 +130,7 @@ standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
..orWhere((w) => w!.familyFriendly.isTrue);
|
..orWhere((w) => w!.familyFriendly.isTrue);
|
||||||
print(query.compile(Set(), preamble: 'DELETE FROM "cars"'));
|
print(query.compile(Set(), preamble: 'DELETE FROM "cars"'));
|
||||||
|
|
||||||
List<Car?> cars = await query.delete(executor);
|
List<Car?>? cars = await query.delete(executor);
|
||||||
expect(cars, hasLength(1));
|
expect(cars, hasLength(1));
|
||||||
expect(cars.first!.toJson(), ferrari!.toJson());
|
expect(cars.first!.toJson(), ferrari!.toJson());
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,3 +38,7 @@ dev_dependencies:
|
||||||
ref: sdk-2.12.x_nnbd
|
ref: sdk-2.12.x_nnbd
|
||||||
path: packages/framework
|
path: packages/framework
|
||||||
build_runner: ^2.0.1
|
build_runner: ^2.0.1
|
||||||
|
|
||||||
|
#dependency_overrides:
|
||||||
|
# angel_orm:
|
||||||
|
# path: ../angel_orm
|
||||||
|
|
Loading…
Reference in a new issue