From a21b5a35e3569f961ee059d19e575633f2e080e1 Mon Sep 17 00:00:00 2001 From: debuggerx01 Date: Thu, 6 Jan 2022 12:06:56 +0800 Subject: [PATCH] Add Where.raw(String where Sql)' to use join table fields as query conditions --- .../example/main.angel_serialize.g.part | 67 ---- packages/orm/angel_orm/example/main.dart | 69 +--- packages/orm/angel_orm/example/main.g.dart | 306 ++++++++++++++++-- .../angel_orm/example/main.serializer.g.dart | 61 ---- packages/orm/angel_orm/lib/src/query.dart | 28 +- .../orm/angel_orm/lib/src/query_where.dart | 10 + 6 files changed, 312 insertions(+), 229 deletions(-) delete mode 100644 packages/orm/angel_orm/example/main.angel_serialize.g.part delete mode 100644 packages/orm/angel_orm/example/main.serializer.g.dart diff --git a/packages/orm/angel_orm/example/main.angel_serialize.g.part b/packages/orm/angel_orm/example/main.angel_serialize.g.part deleted file mode 100644 index 708a0a9d..00000000 --- a/packages/orm/angel_orm/example/main.angel_serialize.g.part +++ /dev/null @@ -1,67 +0,0 @@ -// ************************************************************************** -// JsonModelGenerator -// ************************************************************************** - -@generatedSerializable -class Employee extends _Employee { - Employee( - {this.id, - this.firstName, - this.lastName, - this.salary, - this.createdAt, - this.updatedAt}); - - @override - final String id; - - @override - final String firstName; - - @override - final String lastName; - - @override - final double salary; - - @override - final DateTime createdAt; - - @override - final DateTime updatedAt; - - Employee copyWith( - {String id, - String firstName, - String lastName, - double salary, - DateTime createdAt, - DateTime updatedAt}) { - return new Employee( - id: id ?? this.id, - firstName: firstName ?? this.firstName, - lastName: lastName ?? this.lastName, - salary: salary ?? this.salary, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt); - } - - bool operator ==(other) { - return other is _Employee && - other.id == id && - other.firstName == firstName && - other.lastName == lastName && - other.salary == salary && - other.createdAt == createdAt && - other.updatedAt == updatedAt; - } - - @override - int get hashCode { - return hashObjects([id, firstName, lastName, salary, createdAt, updatedAt]); - } - - Map toJson() { - return EmployeeSerializer.toMap(this); - } -} diff --git a/packages/orm/angel_orm/example/main.dart b/packages/orm/angel_orm/example/main.dart index e04ad2cc..7724e8f7 100644 --- a/packages/orm/angel_orm/example/main.dart +++ b/packages/orm/angel_orm/example/main.dart @@ -1,18 +1,19 @@ import 'dart:async'; +import 'package:angel3_migration/angel3_migration.dart'; import 'package:angel3_orm/angel3_orm.dart'; import 'package:angel3_serialize/angel3_serialize.dart'; import 'package:optional/optional.dart'; part 'main.g.dart'; -part 'main.serializer.g.dart'; void main() async { var query = EmployeeQuery() ..where?.firstName.equals('Rich') ..where?.lastName.equals('Person') + ..where?.raw('COM.deleted = false') ..orWhere((w) => w.salary.greaterThanOrEqualTo(75000)) - ..join('companies', 'company_id', 'id'); + ..join('companies', 'company_id', 'id', alias: 'COM'); var richPerson = await query.getOne(_FakeExecutor()); if (richPerson.isPresent) { @@ -31,7 +32,7 @@ class _FakeExecutor extends QueryExecutor { print( '_FakeExecutor received query: $query and values: $substitutionValues'); return [ - [1, 'Rich', 'Person', 100000.0, now, now] + [1, now, now, 'Rich', 'Person', 100000.0] ]; } @@ -50,65 +51,3 @@ abstract class _Employee extends Model { double? get salary; } - -class EmployeeQuery extends Query { - @override - final QueryValues values = MapQueryValues(); - - EmployeeQueryWhere? _where; - - EmployeeQuery() { - _where = EmployeeQueryWhere(this); - } - - @override - EmployeeQueryWhere? get where => _where; - - @override - String get tableName => 'employees'; - - @override - List get fields => - ['id', 'first_name', 'last_name', 'salary', 'created_at', 'updated_at']; - - @override - EmployeeQueryWhere newWhereClause() => EmployeeQueryWhere(this); - - @override - Optional deserialize(List row) { - return Optional.ofNullable(Employee( - id: row[0].toString(), - firstName: row[1] as String, - lastName: row[2] as String, - salary: row[3] as double, - createdAt: row[4] as DateTime, - updatedAt: row[5] as DateTime)); - } -} - -class EmployeeQueryWhere extends QueryWhere { - EmployeeQueryWhere(EmployeeQuery query) - : id = NumericSqlExpressionBuilder(query, 'id'), - firstName = StringSqlExpressionBuilder(query, 'first_name'), - lastName = StringSqlExpressionBuilder(query, 'last_name'), - salary = NumericSqlExpressionBuilder(query, 'salary'), - createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'), - updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'); - - @override - Iterable get expressionBuilders { - return [id, firstName, lastName, salary, createdAt, updatedAt]; - } - - final NumericSqlExpressionBuilder id; - - final StringSqlExpressionBuilder firstName; - - final StringSqlExpressionBuilder lastName; - - final NumericSqlExpressionBuilder salary; - - final DateTimeSqlExpressionBuilder createdAt; - - final DateTimeSqlExpressionBuilder updatedAt; -} diff --git a/packages/orm/angel_orm/example/main.g.dart b/packages/orm/angel_orm/example/main.g.dart index 80c3d42c..134cb153 100644 --- a/packages/orm/angel_orm/example/main.g.dart +++ b/packages/orm/angel_orm/example/main.g.dart @@ -2,6 +2,171 @@ part of 'main.dart'; +// ************************************************************************** +// MigrationGenerator +// ************************************************************************** + +class EmployeeMigration extends Migration { + @override + void up(Schema schema) { + schema.create('employees', (table) { + table.serial('id').primaryKey(); + table.timeStamp('created_at'); + table.timeStamp('updated_at'); + table.varChar('first_name', length: 255); + table.varChar('last_name', length: 255); + table.declareColumn( + 'salary', Column(type: ColumnType('decimal'), length: 255)); + }); + } + + @override + void down(Schema schema) { + schema.drop('employees'); + } +} + +// ************************************************************************** +// OrmGenerator +// ************************************************************************** + +class EmployeeQuery extends Query { + EmployeeQuery({Query? parent, Set? trampoline}) + : super(parent: parent) { + trampoline ??= {}; + trampoline.add(tableName); + _where = EmployeeQueryWhere(this); + } + + @override + final EmployeeQueryValues values = EmployeeQueryValues(); + + EmployeeQueryWhere? _where; + + @override + Map get casts { + return {'salary': 'text'}; + } + + @override + String get tableName { + return 'employees'; + } + + @override + List get fields { + return const [ + 'id', + 'created_at', + 'updated_at', + 'first_name', + 'last_name', + 'salary' + ]; + } + + @override + EmployeeQueryWhere? get where { + return _where; + } + + @override + EmployeeQueryWhere newWhereClause() { + return EmployeeQueryWhere(this); + } + + static Optional parseRow(List row) { + if (row.every((x) => x == null)) { + return Optional.empty(); + } + var model = Employee( + id: row[0].toString(), + createdAt: (row[1] as DateTime?), + updatedAt: (row[2] as DateTime?), + firstName: (row[3] as String?), + lastName: (row[4] as String?), + salary: double.tryParse(row[5].toString())); + return Optional.of(model); + } + + @override + Optional deserialize(List row) { + return parseRow(row); + } +} + +class EmployeeQueryWhere extends QueryWhere { + EmployeeQueryWhere(EmployeeQuery query) + : id = NumericSqlExpressionBuilder(query, 'id'), + createdAt = DateTimeSqlExpressionBuilder(query, 'created_at'), + updatedAt = DateTimeSqlExpressionBuilder(query, 'updated_at'), + firstName = StringSqlExpressionBuilder(query, 'first_name'), + lastName = StringSqlExpressionBuilder(query, 'last_name'), + salary = NumericSqlExpressionBuilder(query, 'salary'); + + final NumericSqlExpressionBuilder id; + + final DateTimeSqlExpressionBuilder createdAt; + + final DateTimeSqlExpressionBuilder updatedAt; + + final StringSqlExpressionBuilder firstName; + + final StringSqlExpressionBuilder lastName; + + final NumericSqlExpressionBuilder salary; + + @override + List get expressionBuilders { + return [id, createdAt, updatedAt, firstName, lastName, salary]; + } +} + +class EmployeeQueryValues extends MapQueryValues { + @override + Map get casts { + return {'salary': 'decimal'}; + } + + String? get id { + return (values['id'] as String?); + } + + set id(String? value) => values['id'] = value; + DateTime? get createdAt { + return (values['created_at'] as DateTime?); + } + + set createdAt(DateTime? value) => values['created_at'] = value; + DateTime? get updatedAt { + return (values['updated_at'] as DateTime?); + } + + set updatedAt(DateTime? value) => values['updated_at'] = value; + String? get firstName { + return (values['first_name'] as String?); + } + + set firstName(String? value) => values['first_name'] = value; + String? get lastName { + return (values['last_name'] as String?); + } + + set lastName(String? value) => values['last_name'] = value; + double? get salary { + return double.tryParse((values['salary'] as String)); + } + + set salary(double? value) => values['salary'] = value.toString(); + void copyFrom(Employee model) { + createdAt = model.createdAt; + updatedAt = model.updatedAt; + firstName = model.firstName; + lastName = model.lastName; + salary = model.salary; + } +} + // ************************************************************************** // JsonModelGenerator // ************************************************************************** @@ -10,63 +175,154 @@ part of 'main.dart'; class Employee extends _Employee { Employee( {this.id, + this.createdAt, + this.updatedAt, this.firstName, this.lastName, - this.salary, - this.createdAt, - this.updatedAt}); + this.salary}); + + /// A unique identifier corresponding to this item. + @override + String? id; + + /// The time at which this item was created. + @override + DateTime? createdAt; + + /// The last time at which this item was updated. + @override + DateTime? updatedAt; @override - final String? id; + String? firstName; @override - final String? firstName; + String? lastName; @override - final String? lastName; - - @override - final double? salary; - - @override - final DateTime? createdAt; - - @override - final DateTime? updatedAt; + double? salary; Employee copyWith( {String? id, + DateTime? createdAt, + DateTime? updatedAt, String? firstName, String? lastName, - double? salary, - DateTime? createdAt, - DateTime? updatedAt}) { + double? salary}) { return Employee( id: id ?? this.id, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, firstName: firstName ?? this.firstName, lastName: lastName ?? this.lastName, - salary: salary ?? this.salary, - createdAt: createdAt ?? this.createdAt, - updatedAt: updatedAt ?? this.updatedAt); + salary: salary ?? this.salary); } @override bool operator ==(other) { return other is _Employee && other.id == id && + other.createdAt == createdAt && + other.updatedAt == updatedAt && other.firstName == firstName && other.lastName == lastName && - other.salary == salary && - other.createdAt == createdAt && - other.updatedAt == updatedAt; + other.salary == salary; } @override int get hashCode { - return hashObjects([id, firstName, lastName, salary, createdAt, updatedAt]); + return hashObjects([id, createdAt, updatedAt, firstName, lastName, salary]); + } + + @override + String toString() { + return 'Employee(id=$id, createdAt=$createdAt, updatedAt=$updatedAt, firstName=$firstName, lastName=$lastName, salary=$salary)'; } Map toJson() { return EmployeeSerializer.toMap(this); } } + +// ************************************************************************** +// SerializerGenerator +// ************************************************************************** + +const EmployeeSerializer employeeSerializer = EmployeeSerializer(); + +class EmployeeEncoder extends Converter { + const EmployeeEncoder(); + + @override + Map convert(Employee model) => EmployeeSerializer.toMap(model); +} + +class EmployeeDecoder extends Converter { + const EmployeeDecoder(); + + @override + Employee convert(Map map) => EmployeeSerializer.fromMap(map); +} + +class EmployeeSerializer extends Codec { + const EmployeeSerializer(); + + @override + EmployeeEncoder get encoder => const EmployeeEncoder(); + @override + EmployeeDecoder get decoder => const EmployeeDecoder(); + static Employee fromMap(Map map) { + return Employee( + id: map['id'] as String?, + createdAt: map['created_at'] != null + ? (map['created_at'] is DateTime + ? (map['created_at'] as DateTime) + : DateTime.parse(map['created_at'].toString())) + : null, + updatedAt: map['updated_at'] != null + ? (map['updated_at'] is DateTime + ? (map['updated_at'] as DateTime) + : DateTime.parse(map['updated_at'].toString())) + : null, + firstName: map['first_name'] as String?, + lastName: map['last_name'] as String?, + salary: map['salary'] as double?); + } + + static Map toMap(_Employee? model) { + if (model == null) { + return {}; + } + return { + 'id': model.id, + 'created_at': model.createdAt?.toIso8601String(), + 'updated_at': model.updatedAt?.toIso8601String(), + 'first_name': model.firstName, + 'last_name': model.lastName, + 'salary': model.salary + }; + } +} + +abstract class EmployeeFields { + static const List allFields = [ + id, + createdAt, + updatedAt, + firstName, + lastName, + salary + ]; + + static const String id = 'id'; + + static const String createdAt = 'created_at'; + + static const String updatedAt = 'updated_at'; + + static const String firstName = 'first_name'; + + static const String lastName = 'last_name'; + + static const String salary = 'salary'; +} diff --git a/packages/orm/angel_orm/example/main.serializer.g.dart b/packages/orm/angel_orm/example/main.serializer.g.dart deleted file mode 100644 index 48e27fa8..00000000 --- a/packages/orm/angel_orm/example/main.serializer.g.dart +++ /dev/null @@ -1,61 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'main.dart'; - -// ************************************************************************** -// SerializerGenerator -// ************************************************************************** - -abstract class EmployeeSerializer { - static Employee fromMap(Map map) { - return Employee( - id: map['id'] as String?, - firstName: map['first_name'] as String?, - lastName: map['last_name'] as String?, - salary: map['salary'] as double?, - createdAt: map['created_at'] != null - ? (map['created_at'] is DateTime - ? (map['created_at'] as DateTime?) - : DateTime.parse(map['created_at'].toString())) - : null, - updatedAt: map['updated_at'] != null - ? (map['updated_at'] is DateTime - ? (map['updated_at'] as DateTime?) - : DateTime.parse(map['updated_at'].toString())) - : null); - } - - static Map toMap(Employee model) { - return { - 'id': model.id, - 'first_name': model.firstName, - 'last_name': model.lastName, - 'salary': model.salary, - 'created_at': model.createdAt?.toIso8601String(), - 'updated_at': model.updatedAt?.toIso8601String() - }; - } -} - -abstract class EmployeeFields { - static const List allFields = [ - id, - firstName, - lastName, - salary, - createdAt, - updatedAt - ]; - - static const String id = 'id'; - - static const String firstName = 'first_name'; - - static const String lastName = 'last_name'; - - static const String salary = 'salary'; - - static const String createdAt = 'created_at'; - - static const String updatedAt = 'updated_at'; -} diff --git a/packages/orm/angel_orm/lib/src/query.dart b/packages/orm/angel_orm/lib/src/query.dart index ae8e85a1..9ef44af0 100644 --- a/packages/orm/angel_orm/lib/src/query.dart +++ b/packages/orm/angel_orm/lib/src/query.dart @@ -167,6 +167,7 @@ abstract class Query extends QueryBase { void _makeJoin( tableName, Set? trampoline, + String? alias, JoinType type, String localKey, String foreignKey, @@ -182,7 +183,7 @@ abstract class Query extends QueryBase { } var to = _compileJoin(tableName, trampoline); - var alias = _joinAlias(trampoline); + alias ??= _joinAlias(trampoline); if (tableName is Query) { for (var field in tableName.fields) { tableName.aliases[field] = '${alias}_$field'; @@ -199,8 +200,9 @@ abstract class Query extends QueryBase { void join(tableName, String localKey, String foreignKey, {String op = '=', List additionalFields = const [], - Set? trampoline}) { - _makeJoin(tableName, trampoline, JoinType.inner, localKey, foreignKey, op, + Set? trampoline, + String? alias}) { + _makeJoin(tableName, trampoline, alias, JoinType.inner, localKey, foreignKey, op, additionalFields); } @@ -208,8 +210,9 @@ abstract class Query extends QueryBase { void leftJoin(tableName, String localKey, String foreignKey, {String op = '=', List additionalFields = const [], - Set? trampoline}) { - _makeJoin(tableName, trampoline, JoinType.left, localKey, foreignKey, op, + Set? trampoline, + String? alias}) { + _makeJoin(tableName, trampoline, alias, JoinType.left, localKey, foreignKey, op, additionalFields); } @@ -217,8 +220,9 @@ abstract class Query extends QueryBase { void rightJoin(tableName, String localKey, String foreignKey, {String op = '=', List additionalFields = const [], - Set? trampoline}) { - _makeJoin(tableName, trampoline, JoinType.right, localKey, foreignKey, op, + Set? trampoline, + String? alias}) { + _makeJoin(tableName, trampoline, alias, JoinType.right, localKey, foreignKey, op, additionalFields); } @@ -226,8 +230,9 @@ abstract class Query extends QueryBase { void fullOuterJoin(tableName, String localKey, String foreignKey, {String op = '=', List additionalFields = const [], - Set? trampoline}) { - _makeJoin(tableName, trampoline, JoinType.full, localKey, foreignKey, op, + Set? trampoline, + String? alias}) { + _makeJoin(tableName, trampoline, alias, JoinType.full, localKey, foreignKey, op, additionalFields); } @@ -235,8 +240,9 @@ abstract class Query extends QueryBase { void selfJoin(tableName, String localKey, String foreignKey, {String op = '=', List additionalFields = const [], - Set? trampoline}) { - _makeJoin(tableName, trampoline, JoinType.self, localKey, foreignKey, op, + Set? trampoline, + String? alias}) { + _makeJoin(tableName, trampoline, alias, JoinType.self, localKey, foreignKey, op, additionalFields); } diff --git a/packages/orm/angel_orm/lib/src/query_where.dart b/packages/orm/angel_orm/lib/src/query_where.dart index fdf5f05d..5a700c2d 100644 --- a/packages/orm/angel_orm/lib/src/query_where.dart +++ b/packages/orm/angel_orm/lib/src/query_where.dart @@ -5,6 +5,7 @@ abstract class QueryWhere { final Set _and = {}; final Set _not = {}; final Set _or = {}; + final Set _raw = {}; Iterable get expressionBuilders; @@ -20,6 +21,10 @@ abstract class QueryWhere { _or.add(other); } + void raw(String whereRaw) { + _raw.add(whereRaw); + } + String compile({String? tableName}) { var b = StringBuffer(); var i = 0; @@ -39,6 +44,11 @@ abstract class QueryWhere { } } + for (var raw in _raw) { + if (i++ > 0) b.write(' AND '); + b.write(' ($raw)'); + } + for (var other in _and) { var sql = other.compile(); if (sql.isNotEmpty) b.write(' AND ($sql)');