Updated ORM

This commit is contained in:
thomashii@dukefirehawk.com 2021-05-04 12:03:08 +08:00
parent a4ff96a831
commit e11f8f77e1
7 changed files with 92 additions and 90 deletions

View file

@ -141,9 +141,13 @@ class EnumSqlExpressionBuilder<T> extends SqlExpressionBuilder<T> {
UnsupportedError('Enums do not support this operation.');
@override
String? compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
String compile() {
if (_raw != null) {
return _raw!;
}
if (_value == null) {
return '';
}
return '$_op $_value';
}
@ -243,7 +247,7 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
void isBetween(String lower, String upper) {
query.substitutionValues[lowerName] = lower;
query.substitutionValues[upperName] = upper;
_raw = "BETWEEN @$lowerName AND @$upperName";
_raw = 'BETWEEN @$lowerName AND @$upperName';
_hasValue = true;
}
@ -506,10 +510,10 @@ abstract class JsonSqlExpressionBuilder<T, K> extends SqlExpressionBuilder<T> {
}
@override
String? compile() {
String compile() {
var s = _compile();
if (!_properties.any((p) => p.hasValue)) return s;
s ??= '';
//s ??= '';
for (var p in _properties) {
if (p.hasValue) {
@ -517,7 +521,7 @@ abstract class JsonSqlExpressionBuilder<T, K> extends SqlExpressionBuilder<T> {
if (c != null) {
_hasValue = true;
s ??= '';
//s ??= '';
if (p.typed is! DateTimeSqlExpressionBuilder) {
s += '${p.typed!.columnName} ';
@ -531,10 +535,14 @@ abstract class JsonSqlExpressionBuilder<T, K> extends SqlExpressionBuilder<T> {
return s;
}
String? _compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
return "::jsonb $_op @$substitution::jsonb";
String _compile() {
if (_raw != null) {
return _raw!;
}
if (_value == null) {
return '';
}
return '::jsonb $_op @$substitution::jsonb';
}
void contains(T value) {

View file

@ -9,7 +9,7 @@ import 'query_where.dart';
import 'package:optional/optional.dart';
/// 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> {
final List<JoinBuilder> _joins = [];
final Map<String, int> _names = {};
final List<OrderBy> _orderBy = [];
@ -80,27 +80,27 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
/// Determines whether this query can be compiled.
///
/// Used to prevent ambiguities in joins.
bool canCompile(Set<String>? trampoline) => true;
bool canCompile(Set<String> trampoline) => true;
/// Shorthand for calling [where].or with a [Where] clause.
void andWhere(void Function(Where) f) {
var w = newWhereClause();
f(w);
where?.and(w);
where.and(w);
}
/// Shorthand for calling [where].or with a [Where] clause.
void notWhere(void Function(Where) f) {
var w = newWhereClause();
f(w);
where?.not(w);
where.not(w);
}
/// Shorthand for calling [where].or with a [Where] clause.
void orWhere(void Function(Where) f) {
var w = newWhereClause();
f(w);
where?.or(w);
where.or(w);
}
/// Limit the number of rows to return.
@ -128,12 +128,12 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
_crossJoin = tableName;
}
String _joinAlias(Set<String>? trampoline) {
String _joinAlias(Set<String> trampoline) {
var i = _joins.length;
while (true) {
var a = 'a$i';
if (trampoline!.add(a)) {
if (trampoline.add(a)) {
return a;
} else {
i++;
@ -310,8 +310,8 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
}
var whereClause =
where?.compile(tableName: includeTableName ? tableName : null);
if (whereClause?.isNotEmpty == true) {
where.compile(tableName: includeTableName ? tableName : null);
if (whereClause.isNotEmpty == true) {
b.write(' WHERE $whereClause');
}
if (_groupBy != null) b.write(' GROUP BY $_groupBy');
@ -357,7 +357,7 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
Future<Optional<T>> insert(QueryExecutor executor) {
var insertion = values.compileInsert(this, tableName);
if (insertion == null) {
if (insertion == '') {
throw StateError('No values have been specified for update.');
} else {
// TODO: How to do this in a non-Postgres DB?
@ -375,12 +375,12 @@ abstract class Query<T, Where extends QueryWhere?> extends QueryBase<T> {
var updateSql = StringBuffer('UPDATE $tableName ');
var valuesClause = values.compileForUpdate(this);
if (valuesClause == null) {
if (valuesClause == '') {
throw StateError('No values have been specified for update.');
} else {
updateSql.write(' $valuesClause');
var whereClause = where?.compile();
if (whereClause?.isNotEmpty == true) {
var whereClause = where.compile();
if (whereClause.isNotEmpty == true) {
updateSql.write(' WHERE $whereClause');
}
if (_limit != null) updateSql.write(' LIMIT $_limit');

View file

@ -14,12 +14,13 @@ abstract class QueryValues {
}
}
String? compileInsert(Query query, String tableName) {
String compileInsert(Query query, String tableName) {
var data = Map<String, dynamic>.from(toMap());
var keys = data.keys.toList();
keys.where((k) => !query.fields.contains(k)).forEach(data.remove);
if (data.isEmpty) return null;
if (data.isEmpty) {
return '';
}
var fieldSet = data.keys.join(', ');
var b = StringBuffer('INSERT INTO $tableName ($fieldSet) VALUES (');
var i = 0;
@ -37,9 +38,11 @@ abstract class QueryValues {
return b.toString();
}
String? compileForUpdate(Query query) {
String compileForUpdate(Query query) {
var data = toMap();
if (data.isEmpty) return null;
if (data.isEmpty) {
return '';
}
var b = StringBuffer('SET');
var i = 0;

View file

@ -2,27 +2,27 @@ import 'builder.dart';
/// Builds a SQL `WHERE` clause.
abstract class QueryWhere {
final Set<QueryWhere?> _and = Set();
final Set<QueryWhere?> _not = Set();
final Set<QueryWhere?> _or = Set();
final Set<QueryWhere> _and = {};
final Set<QueryWhere> _not = {};
final Set<QueryWhere> _or = {};
Iterable<SqlExpressionBuilder> get expressionBuilders;
void and(QueryWhere? other) {
void and(QueryWhere other) {
_and.add(other);
}
void not(QueryWhere? other) {
void not(QueryWhere other) {
_not.add(other);
}
void or(QueryWhere? other) {
void or(QueryWhere other) {
_or.add(other);
}
String compile({String? tableName}) {
var b = StringBuffer();
int i = 0;
var i = 0;
for (var builder in expressionBuilders) {
var key = builder.columnName;
@ -40,17 +40,17 @@ abstract class QueryWhere {
}
for (var other in _and) {
var sql = other!.compile();
var sql = other.compile();
if (sql.isNotEmpty) b.write(' AND ($sql)');
}
for (var other in _not) {
var sql = other!.compile();
var sql = other.compile();
if (sql.isNotEmpty) b.write(' NOT ($sql)');
}
for (var other in _or) {
var sql = other!.compile();
var sql = other.compile();
if (sql.isNotEmpty) b.write(' OR ($sql)');
}

View file

@ -7,7 +7,7 @@ import 'package:angel_orm_test/src/models/car.dart';
class CarController extends Controller {
@Expose('/luxury')
Future<List<Car?>> getLuxuryCars(QueryExecutor connection) {
var query = new CarQuery();
var query = CarQuery();
query.where
?..familyFriendly.equals(false)
..createdAt.year.greaterThanOrEqualTo(2014)

View file

@ -12,7 +12,7 @@ abstract class _Role {
String? get role;
@ManyToMany(_RoleUser)
List<_User?>? get users;
List<_User> get users;
}
@serializable
@ -35,5 +35,5 @@ abstract class _User {
String? get password;
@ManyToMany(_RoleUser)
List<_Role?>? get roles;
List<_Role> get roles;
}

View file

@ -59,7 +59,7 @@ class UserMigration extends Migration {
// OrmGenerator
// **************************************************************************
class RoleQuery extends Query<Role?, RoleQueryWhere?> {
class RoleQuery extends Query<Role, RoleQueryWhere> {
RoleQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= Set();
trampoline.add(tableName);
@ -137,8 +137,7 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
var l = out[idx];
return out
..[idx] = l.copyWith(
users: List<_User?>.from(l.users ?? [])
..addAll(model!.users ?? []));
users: List<_User>.from(l.users)..addAll(model!.users));
}
});
});
@ -156,8 +155,7 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
var l = out[idx]!;
return out
..[idx] = l.copyWith(
users: List<_User?>.from(l.users ?? [])
..addAll(model!.users ?? []));
users: List<_User>.from(l.users)..addAll(model!.users));
}
});
});
@ -175,8 +173,7 @@ class RoleQuery extends Query<Role?, RoleQueryWhere?> {
var l = out[idx];
return out
..[idx] = l.copyWith(
users: List<_User?>.from(l.users ?? [])
..addAll(model!.users ?? []));
users: List<_User>.from(l.users)..addAll(model!.users));
}
});
});
@ -329,7 +326,7 @@ class RoleUserQueryValues extends MapQueryValues {
}
}
class UserQuery extends Query<User?, UserQueryWhere?> {
class UserQuery extends Query<User, UserQueryWhere> {
UserQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
trampoline ??= Set();
trampoline.add(tableName);
@ -345,7 +342,7 @@ class UserQuery extends Query<User?, UserQueryWhere?> {
@override
final UserQueryValues values = UserQueryValues();
UserQueryWhere? _where;
UserQueryWhere _where;
@override
get casts {
@ -363,7 +360,7 @@ class UserQuery extends Query<User?, UserQueryWhere?> {
}
@override
UserQueryWhere? get where {
UserQueryWhere get where {
return _where;
}
@ -401,17 +398,16 @@ class UserQuery extends Query<User?, UserQueryWhere?> {
@override
get(QueryExecutor executor) {
return super.get(executor).then((result) {
return result.fold<List<User?>>([], (out, model) {
var idx = out.indexWhere((m) => m!.email == model!.email);
return result.fold<List<User>>([], (out, model) {
var idx = out.indexWhere((m) => m.email == model.email);
if (idx == -1) {
return out..add(model);
} else {
var l = out[idx]!;
var l = out[idx];
return out
..[idx] = l.copyWith(
roles: List<_Role?>.from(l.roles ?? [])
..addAll(model!.roles ?? []));
roles: List<_Role>.from(l.roles)..addAll(model.roles));
}
});
});
@ -421,16 +417,15 @@ class UserQuery extends Query<User?, UserQueryWhere?> {
update(QueryExecutor executor) {
return super.update(executor).then((result) {
return result.fold<List<User>>([], (out, model) {
var idx = out.indexWhere((m) => m.email == model!.email);
var idx = out.indexWhere((m) => m.email == model.email);
if (idx == -1) {
return out..add(model!);
return out..add(model);
} else {
var l = out[idx];
return out
..[idx] = l.copyWith(
roles: List<_Role?>.from(l.roles ?? [])
..addAll(model!.roles ?? []));
roles: List<_Role>.from(l.roles)..addAll(model.roles));
}
});
});
@ -440,16 +435,15 @@ class UserQuery extends Query<User?, UserQueryWhere?> {
delete(QueryExecutor executor) {
return super.delete(executor).then((result) {
return result.fold<List<User>>([], (out, model) {
var idx = out.indexWhere((m) => m.email == model!.email);
var idx = out.indexWhere((m) => m.email == model.email);
if (idx == -1) {
return out..add(model!);
return out..add(model);
} else {
var l = out[idx];
return out
..[idx] = l.copyWith(
roles: List<_Role?>.from(l.roles ?? [])
..addAll(model!.roles ?? []));
roles: List<_Role>.from(l.roles)..addAll(model.roles));
}
});
});
@ -508,16 +502,16 @@ class UserQueryValues extends MapQueryValues {
@generatedSerializable
class Role implements _Role {
const Role({this.role, this.users});
const Role({this.role, this.users = const []});
@override
final String? role;
@override
final List<_User?>? users;
final List<_User> users;
Role copyWith({String? role, List<_User?>? users}) {
return Role(role: role ?? this.role, users: users ?? this.users);
Role copyWith({String? role, List<_User> users = const []}) {
return Role(role: role ?? this.role, users: users);
}
bool operator ==(other) {
@ -537,7 +531,7 @@ class Role implements _Role {
return "Role(role=$role, users=$users)";
}
Map<String, dynamic>? toJson() {
Map<String, dynamic> toJson() {
return RoleSerializer.toMap(this);
}
}
@ -577,7 +571,7 @@ class RoleUser implements _RoleUser {
@generatedSerializable
class User implements _User {
const User({this.email, this.name, this.password, this.roles});
const User({this.email, this.name, this.password, this.roles = const []});
@override
final String? email;
@ -589,15 +583,18 @@ class User implements _User {
final String? password;
@override
final List<_Role?>? roles;
final List<_Role> roles;
User copyWith(
{String? email, String? name, String? password, List<_Role?>? roles}) {
{String? email,
String? name,
String? password,
List<_Role> roles = const []}) {
return User(
email: email ?? this.email,
name: name ?? this.name,
password: password ?? this.password,
roles: roles ?? this.roles);
roles: roles);
}
bool operator ==(other) {
@ -605,7 +602,7 @@ class User implements _User {
other.email == email &&
other.name == name &&
other.password == password &&
ListEquality<_Role?>(DefaultEquality<_Role>())
ListEquality<_Role>(DefaultEquality<_Role>())
.equals(other.roles, roles);
}
@ -619,7 +616,7 @@ class User implements _User {
return "User(email=$email, name=$name, password=$password, roles=$roles)";
}
Map<String, dynamic>? toJson() {
Map<String, dynamic> toJson() {
return UserSerializer.toMap(this);
}
}
@ -657,16 +654,13 @@ class RoleSerializer extends Codec<Role, Map?> {
users: map['users'] is Iterable
? List.unmodifiable(((map['users'] as Iterable).whereType<Map>())
.map(UserSerializer.fromMap))
: null);
: []);
}
static Map<String, dynamic>? toMap(_Role? model) {
if (model == null) {
return null;
}
static Map<String, dynamic> toMap(_Role model) {
return {
'role': model.role,
'users': model.users?.map((m) => UserSerializer.toMap(m)).toList()
'users': model.users.map((m) => UserSerializer.toMap(m)).toList()
};
}
}
@ -714,8 +708,8 @@ class RoleUserSerializer extends Codec<RoleUser, Map> {
static Map<String, dynamic> toMap(_RoleUser model) {
return {
'role': RoleSerializer.toMap(model.role),
'user': UserSerializer.toMap(model.user)
'role': (model.role != null) ? RoleSerializer.toMap(model.role!) : '',
'user': (model.user != null) ? UserSerializer.toMap(model.user!) : ''
};
}
}
@ -759,18 +753,15 @@ class UserSerializer extends Codec<User, Map?> {
roles: map['roles'] is Iterable
? List.unmodifiable(((map['roles'] as Iterable).whereType<Map>())
.map(RoleSerializer.fromMap))
: null);
: []);
}
static Map<String, dynamic>? toMap(_User? model) {
if (model == null) {
return null;
}
static Map<String, dynamic> toMap(_User model) {
return {
'email': model.email,
'name': model.name,
'password': model.password,
'roles': model.roles?.map((m) => RoleSerializer.toMap(m)).toList()
'roles': model.roles.map((m) => RoleSerializer.toMap(m)).toList()
};
}
}