Updated ORM
This commit is contained in:
parent
a4ff96a831
commit
e11f8f77e1
7 changed files with 92 additions and 90 deletions
|
@ -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) {
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)');
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue