Added Optional package

This commit is contained in:
thomashii@dukefirehawk.com 2021-05-03 21:27:12 +08:00
parent 7644d8c2d2
commit d241d7ca77
11 changed files with 74 additions and 56 deletions

View file

@ -15,7 +15,9 @@ void main() async {
..join('companies', 'company_id', 'id');
var richPerson = await query.getOne(_FakeExecutor());
print(richPerson?.toJson());
if (richPerson.isPresent) {
print(richPerson.first.toJson());
}
}
class _FakeExecutor extends QueryExecutor {
@ -24,7 +26,7 @@ class _FakeExecutor extends QueryExecutor {
@override
Future<List<List>> query(
String tableName, String? query, Map<String, dynamic> substitutionValues,
[returningFields]) async {
[returningFields = const []]) async {
var now = DateTime.now();
print(
'_FakeExecutor received query: $query and values: $substitutionValues');

View file

@ -6,6 +6,7 @@ import 'query_base.dart';
import 'query_executor.dart';
import 'query_values.dart';
import 'query_where.dart';
import 'package:optional/optional.dart';
/// A SQL `SELECT` query builder.
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) {
int i = _joins.length;
var i = _joins.length;
while (true) {
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) {
return () => tableName;
} else if (tableName is Query) {
return () {
var c = tableName.compile(trampoline);
if (c == null) return c;
//if (c == null) return c;
return '($c)';
};
} else {
@ -160,7 +161,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
String foreignKey,
String op,
List<String> additionalFields) {
trampoline ??= Set();
trampoline ??= <String>{};
// Pivot tables guard against ambiguous fields by excluding tables
// 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);
if (to != null) {
var alias = _joinAlias(trampoline);
if (tableName is Query) {
for (var field in tableName.fields) {
tableName.aliases[field] = '${alias}_$field';
}
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: 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.
@ -231,14 +230,15 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
}
@override
String? compile(Set<String>? trampoline,
String compile(Set<String> trampoline,
{bool includeTableName = false,
String? preamble,
bool withFields = true,
String? fromQuery}) {
// One table MAY appear multiple times in a query.
if (!canCompile(trampoline)) {
return null;
//return null;
throw Exception('One table appear multiple times in a query');
}
includeTableName = includeTableName || _joins.isNotEmpty;
@ -320,7 +320,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
}
@override
Future<T?> getOne(QueryExecutor executor) {
Future<Optional<T>> getOne(QueryExecutor executor) {
//limit(1);
return super.getOne(executor);
}
@ -358,7 +358,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({});
sql = 'WITH $tableName as ($insertion RETURNING $returning) ' + sql;
return executor
.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');
var returning = fields.map(adornWithTableName).join(', ');
var sql = compile({})!;
var sql = compile({});
sql = 'WITH $tableName as ($updateSql RETURNING $returning) ' + sql;
return executor

View file

@ -1,6 +1,7 @@
import 'dart:async';
import 'query_executor.dart';
import 'union.dart';
import 'package:optional/optional.dart';
/// A base class for objects that compile to SQL queries, typically within an ORM.
abstract class QueryBase<T> {
@ -32,9 +33,9 @@ abstract class QueryBase<T> {
}
}).join(', ');
String? compile(Set<String> trampoline,
String compile(Set<String> trampoline,
{bool includeTableName = false,
String? preamble,
String preamble = '',
bool withFields = true});
T deserialize(List row);
@ -46,8 +47,10 @@ abstract class QueryBase<T> {
.then((it) => it.map(deserialize).toList());
}
Future<T?> getOne(QueryExecutor executor) {
return get(executor).then((it) => it.isEmpty ? null : it.first);
Future<Optional<T>> getOne(QueryExecutor executor) {
//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) {

View file

@ -8,8 +8,8 @@ abstract class QueryExecutor {
/// Executes a single query.
Future<List<List>> query(
String tableName, String? query, Map<String, dynamic> substitutionValues,
[List<String>? returningFields]);
String tableName, String query, Map<String, dynamic> substitutionValues,
[List<String> returningFields = const []]);
/// Enters a database transaction, performing the actions within,
/// and returning the results of [f].

View file

@ -28,3 +28,4 @@ dev_dependencies:
build_runner: ^2.0.1
pedantic: ^1.11.0
test: ^1.17.3
optional: ^6.0.0-nullsafety.2

View file

@ -27,3 +27,8 @@ dev_dependencies:
ref: sdk-2.12.x_nnbd
path: packages/pretty_logging
test: ^1.17.3
#dependency_overrides:
# angel_orm_test:
# path: ../angel_orm_test
# angel_orm:
# path: ../angel_orm

View file

@ -160,13 +160,13 @@ class TreeQuery extends Query<Tree?, TreeQueryWhere?> {
@override
delete(QueryExecutor executor) {
return super.delete(executor).then((result) {
return result.fold<List<Tree?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.id == model!.id);
return result.fold<List<Tree>>([], (out, model) {
var idx = out.indexWhere((m) => m.id == model!.id);
if (idx == -1) {
return out..add(model);
return out..add(model!);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
fruits: List<_Fruit>.from(l.fruits ?? [])

View file

@ -304,18 +304,21 @@ class WeirdJoinQuery extends Query<WeirdJoin?, WeirdJoinQueryWhere?> {
@override
get(QueryExecutor executor) {
return super.get(executor).then((result) {
return result.fold<List<WeirdJoin?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.id == model!.id);
return result.fold<List<WeirdJoin>>([], (out, model) {
var idx = out.indexWhere((m) => m.id == model!.id);
if (idx == -1) {
return out..add(model);
return out..add(model!);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
numbas: List<_Numba?>.from(l.numbas ?? [])
..addAll(model!.numbas ?? []),
foos: List<_Foo?>.from(l.foos ?? [])..addAll(model.foos ?? []));
numbas: List<_Numba>.from(l.numbas ?? [])
..addAll(model == null
? []
: 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
update(QueryExecutor executor) {
return super.update(executor).then((result) {
return result.fold<List<WeirdJoin?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.id == model!.id);
return result.fold<List<WeirdJoin>>([], (out, model) {
var idx = out.indexWhere((m) => m.id == model!.id);
if (idx == -1) {
return out..add(model);
return out..add(model!);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
numbas: List<_Numba?>.from(l.numbas ?? [])
@ -344,13 +347,13 @@ class WeirdJoinQuery extends Query<WeirdJoin?, WeirdJoinQueryWhere?> {
@override
delete(QueryExecutor executor) {
return super.delete(executor).then((result) {
return result.fold<List<WeirdJoin?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.id == model!.id);
return result.fold<List<WeirdJoin>>([], (out, model) {
var idx = out.indexWhere((m) => m.id == model!.id);
if (idx == -1) {
return out..add(model);
return out..add(model!);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
numbas: List<_Numba?>.from(l.numbas ?? [])

View file

@ -473,13 +473,13 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
@override
get(QueryExecutor executor) {
return super.get(executor).then((result) {
return result.fold<List<Role?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.id == model!.id);
return result.fold<List<Role>>([], (out, model) {
var idx = out.indexWhere((m) => m.id == model!.id);
if (idx == -1) {
return out..add(model);
return out..add(model!);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
users: List<_User>.from(l.users)..addAll(model!.users));
@ -509,13 +509,13 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
@override
delete(QueryExecutor executor) {
return super.delete(executor).then((result) {
return result.fold<List<Role?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.id == model!.id);
return result.fold<List<Role>>([], (out, model) {
var idx = out.indexWhere((m) => m.id == model!.id);
if (idx == -1) {
return out..add(model);
return out..add(model!);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
users: List<_User>.from(l.users)..addAll(model!.users));

View file

@ -130,7 +130,7 @@ standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
..orWhere((w) => w!.familyFriendly.isTrue);
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.first!.toJson(), ferrari!.toJson());
});

View file

@ -38,3 +38,7 @@ dev_dependencies:
ref: sdk-2.12.x_nnbd
path: packages/framework
build_runner: ^2.0.1
#dependency_overrides:
# angel_orm:
# path: ../angel_orm