bring back older query builder

This commit is contained in:
Tobe O 2018-12-01 12:21:34 -05:00
parent 007ea0b5e0
commit cb73f4a112
9 changed files with 721 additions and 342 deletions

View file

@ -0,0 +1,67 @@
// **************************************************************************
// 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<String, dynamic> toJson() {
return EmployeeSerializer.toMap(this);
}
}

View file

@ -1,27 +1,92 @@
import 'package:angel_model/angel_model.dart'; import 'package:angel_model/angel_model.dart';
import 'package:angel_orm/angel_orm.dart'; import 'package:angel_orm/angel_orm.dart';
import 'package:angel_serialize/angel_serialize.dart';
part 'main.g.dart';
part 'main.serializer.g.dart';
main() { main() async {
var query = new EmployeeQuery();
query.where
..firstName.equals('Rich')
..lastName.equals('Person')
..or(new EmployeeQueryWhere()..salary.greaterThanOrEqualTo(75000));
var richPerson = await query.getOne(new _FakeExecutor());
print(richPerson.toJson());
} }
@postgreSqlOrm class _FakeExecutor extends QueryExecutor {
abstract class Company extends Model { const _FakeExecutor();
String get name;
bool get isFortune500; @override
Future<List<List>> query(String query) async {
var now = new DateTime.now();
print('_FakeExecutor received query: $query');
return [
[1, 'Rich', 'Person', 100000.0, now, now]
];
}
} }
@postgreSqlOrm @orm
@serializable
abstract class _Employee extends Model { abstract class _Employee extends Model {
@belongsTo
Company get company;
String get firstName; String get firstName;
String get lastName; String get lastName;
double get salary; double get salary;
}
bool get isFortune500Employee => company.isFortune500;
class EmployeeQuery extends Query<Employee, EmployeeQueryWhere> {
@override
final EmployeeQueryWhere where = new EmployeeQueryWhere();
@override
String get tableName => 'employees';
@override
List<String> get fields =>
['id', 'first_name', 'last_name', 'salary', 'created_at', 'updated_at'];
@override
Employee deserialize(List row) {
return new 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 {
@override
Map<String, SqlExpressionBuilder> get expressionBuilders {
return {
'id': id,
'first_name': firstName,
'last_name': lastName,
'salary': salary,
'created_at': createdAt,
'updated_at': updatedAt
};
}
final NumericSqlExpressionBuilder<int> id =
new NumericSqlExpressionBuilder<int>();
final StringSqlExpressionBuilder firstName = new StringSqlExpressionBuilder();
final StringSqlExpressionBuilder lastName = new StringSqlExpressionBuilder();
final NumericSqlExpressionBuilder<double> salary =
new NumericSqlExpressionBuilder<double>();
final DateTimeSqlExpressionBuilder createdAt =
new DateTimeSqlExpressionBuilder('created_at');
final DateTimeSqlExpressionBuilder updatedAt =
new DateTimeSqlExpressionBuilder('updated_at');
} }

View file

@ -0,0 +1,71 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'main.dart';
// **************************************************************************
// 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<String, dynamic> toJson() {
return EmployeeSerializer.toMap(this);
}
}

View file

@ -0,0 +1,64 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'main.dart';
// **************************************************************************
// SerializerGenerator
// **************************************************************************
abstract class EmployeeSerializer {
static Employee fromMap(Map map) {
return new 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<String, dynamic> toMap(Employee model) {
if (model == null) {
return null;
}
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<String> allFields = const <String>[
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';
}

View file

@ -1,4 +1,5 @@
export 'src/annotations.dart'; export 'src/annotations.dart';
export 'src/builder.dart';
export 'src/migration.dart'; export 'src/migration.dart';
export 'src/relations.dart'; export 'src/relations.dart';
export 'src/query.dart'; export 'src/query.dart';

View file

@ -1,23 +1,9 @@
const Orm mongoDBOrm = const Orm(OrmType.mongoDB); const Orm orm = const Orm();
const Orm rethinkDBOrm = const Orm(OrmType.rethinkDB);
const Orm postgreSqlOrm = const Orm(OrmType.postgreSql);
const Orm mySqlOrm = const Orm(OrmType.mySql);
class Orm { class Orm {
final OrmType type;
final String tableName; final String tableName;
const Orm(this.type, {this.tableName}); const Orm({this.tableName});
}
enum OrmType {
mongoDB,
rethinkDB,
mySql,
postgreSql,
} }
class CanJoin { class CanJoin {

View file

@ -0,0 +1,340 @@
import 'package:intl/intl.dart' show DateFormat;
import 'package:string_scanner/string_scanner.dart';
final DateFormat dateYmd = new DateFormat('yyyy-MM-dd');
final DateFormat dateYmdHms = new DateFormat('yyyy-MM-dd HH:mm:ss');
/// Cleans an input SQL expression of common SQL injection points.
String sanitizeExpression(String unsafe) {
var buf = new StringBuffer();
var scanner = new StringScanner(unsafe);
int ch;
while (!scanner.isDone) {
// Ignore comment starts
if (scanner.scan('--') || scanner.scan('/*'))
continue;
// Ignore all single quotes and attempted escape sequences
else if (scanner.scan("'") || scanner.scan('\\'))
continue;
// Otherwise, add the next char, unless it's a null byte.
else if ((ch = scanner.readChar()) != 0 && ch != null)
buf.writeCharCode(ch);
}
return buf.toString();
}
abstract class SqlExpressionBuilder<T> {
bool get hasValue;
String compile();
void isBetween(T lower, T upper);
void isNotBetween(T lower, T upper);
void isIn(Iterable<T> values);
void isNotIn(Iterable<T> values);
}
class NumericSqlExpressionBuilder<T extends num>
implements SqlExpressionBuilder<T> {
bool _hasValue = false;
String _op = '=';
String _raw;
T _value;
@override
bool get hasValue => _hasValue;
bool _change(String op, T value) {
_raw = null;
_op = op;
_value = value;
return _hasValue = true;
}
@override
String compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
return '$_op $_value';
}
operator <(T value) => _change('<', value);
operator >(T value) => _change('>', value);
operator <=(T value) => _change('<=', value);
operator >=(T value) => _change('>=', value);
void lessThan(T value) {
_change('<', value);
}
void lessThanOrEqualTo(T value) {
_change('<=', value);
}
void greaterThan(T value) {
_change('>', value);
}
void greaterThanOrEqualTo(T value) {
_change('>=', value);
}
void equals(T value) {
_change('=', value);
}
void notEquals(T value) {
_change('!=', value);
}
@override
void isBetween(T lower, T upper) {
_raw = 'BETWEEN $lower AND $upper';
_hasValue = true;
}
@override
void isNotBetween(T lower, T upper) {
_raw = 'NOT BETWEEN $lower AND $upper';
_hasValue = true;
}
@override
void isIn(Iterable<T> values) {
_raw = 'IN (' + values.join(', ') + ')';
_hasValue = true;
}
@override
void isNotIn(Iterable<T> values) {
_raw = 'NOT IN (' + values.join(', ') + ')';
_hasValue = true;
}
}
class StringSqlExpressionBuilder implements SqlExpressionBuilder<String> {
bool _hasValue = false;
String _op = '=', _raw, _value;
@override
bool get hasValue => _hasValue;
bool _change(String op, String value) {
_raw = null;
_op = op;
_value = value;
return _hasValue = true;
}
@override
String compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
var v = sanitizeExpression(_value);
return "$_op '$v'";
}
void isEmpty() => equals('');
void equals(String value) {
_change('=', value);
}
void notEquals(String value) {
_change('!=', value);
}
void like(String value) {
_change('LIKE', value);
}
@override
void isBetween(String lower, String upper) {
var l = sanitizeExpression(lower), u = sanitizeExpression(upper);
_raw = "BETWEEN '$l' AND '$u'";
_hasValue = true;
}
@override
void isNotBetween(String lower, String upper) {
var l = sanitizeExpression(lower), u = sanitizeExpression(upper);
_raw = "NOT BETWEEN '$l' AND '$u'";
_hasValue = true;
}
@override
void isIn(Iterable<String> values) {
_raw = 'IN (' +
values.map(sanitizeExpression).map((s) => "'$s'").join(', ') +
')';
_hasValue = true;
}
@override
void isNotIn(Iterable<String> values) {
_raw = 'NOT IN (' +
values.map(sanitizeExpression).map((s) => "'$s'").join(', ') +
')';
_hasValue = true;
}
}
class BooleanSqlExpressionBuilder implements SqlExpressionBuilder<bool> {
bool _hasValue = false;
String _op = '=', _raw;
bool _value;
@override
bool get hasValue => _hasValue;
bool _change(String op, bool value) {
_raw = null;
_op = op;
_value = value;
return _hasValue = true;
}
@override
String compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
var v = _value ? 'TRUE' : 'FALSE';
return '$_op $v';
}
void equals(bool value) {
_change('=', value);
}
void notEquals(bool value) {
_change('!=', value);
}
@override
void isBetween(bool lower, bool upper) => throw new UnsupportedError(
'Booleans do not support BETWEEN expressions.');
@override
void isNotBetween(bool lower, bool upper) => isBetween(lower, upper);
@override
void isIn(Iterable<bool> values) {
_raw = 'IN (' + values.map((b) => b ? 'TRUE' : 'FALSE').join(', ') + ')';
_hasValue = true;
}
@override
void isNotIn(Iterable<bool> values) {
_raw =
'NOT IN (' + values.map((b) => b ? 'TRUE' : 'FALSE').join(', ') + ')';
_hasValue = true;
}
}
class DateTimeSqlExpressionBuilder implements SqlExpressionBuilder<DateTime> {
final NumericSqlExpressionBuilder<int> year =
new NumericSqlExpressionBuilder<int>(),
month = new NumericSqlExpressionBuilder<int>(),
day = new NumericSqlExpressionBuilder<int>(),
hour = new NumericSqlExpressionBuilder<int>(),
minute = new NumericSqlExpressionBuilder<int>(),
second = new NumericSqlExpressionBuilder<int>();
final String columnName;
String _raw;
DateTimeSqlExpressionBuilder(this.columnName);
@override
bool get hasValue =>
_raw?.isNotEmpty == true ||
year.hasValue ||
month.hasValue ||
day.hasValue ||
hour.hasValue ||
minute.hasValue ||
second.hasValue;
bool _change(String _op, DateTime dt, bool time) {
var dateString = time ? dateYmdHms.format(dt) : dateYmd.format(dt);
_raw = '$columnName $_op \'$dateString\'';
return true;
}
operator <(DateTime value) => _change('<', value, true);
operator <=(DateTime value) => _change('<=', value, true);
operator >(DateTime value) => _change('>', value, true);
operator >=(DateTime value) => _change('>=', value, true);
void equals(DateTime value, {bool includeTime: true}) {
_change('=', value, includeTime != false);
}
void lessThan(DateTime value, {bool includeTime: true}) {
_change('<', value, includeTime != false);
}
void lessThanOrEqualTo(DateTime value, {bool includeTime: true}) {
_change('<=', value, includeTime != false);
}
void greaterThan(DateTime value, {bool includeTime: true}) {
_change('>', value, includeTime != false);
}
void greaterThanOrEqualTo(DateTime value, {bool includeTime: true}) {
_change('>=', value, includeTime != false);
}
@override
void isIn(Iterable<DateTime> values) {
_raw = '$columnName IN (' +
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
')';
}
@override
void isNotIn(Iterable<DateTime> values) {
_raw = '$columnName NOT IN (' +
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
')';
}
@override
void isBetween(DateTime lower, DateTime upper) {
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
_raw = "$columnName BETWEEN '$l' and '$u'";
}
@override
void isNotBetween(DateTime lower, DateTime upper) {
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
_raw = "$columnName NOT BETWEEN '$l' and '$u'";
}
@override
String compile() {
if (_raw?.isNotEmpty == true) return _raw;
List<String> parts = [];
if (year.hasValue) parts.add('YEAR($columnName) ${year.compile()}');
if (month.hasValue) parts.add('MONTH($columnName) ${month.compile()}');
if (day.hasValue) parts.add('DAY($columnName) ${day.compile()}');
if (hour.hasValue) parts.add('HOUR($columnName) ${hour.compile()}');
if (minute.hasValue) parts.add('MINUTE($columnName) ${minute.compile()}');
if (second.hasValue) parts.add('SECOND($columnName) ${second.compile()}');
return parts.isEmpty ? null : parts.join(' AND ');
}
}

View file

@ -1,340 +1,122 @@
import 'package:intl/intl.dart'; import 'dart:async';
import 'package:string_scanner/string_scanner.dart'; import 'builder.dart';
final DateFormat dateYmd = new DateFormat('yyyy-MM-dd');
final DateFormat dateYmdHms = new DateFormat('yyyy-MM-dd HH:mm:ss');
/// Cleans an input SQL expression of common SQL injection points.
String sanitizeExpression(String unsafe) {
var buf = new StringBuffer();
var scanner = new StringScanner(unsafe);
int ch;
while (!scanner.isDone) {
// Ignore comment starts
if (scanner.scan('--') || scanner.scan('/*'))
continue;
// Ignore all single quotes and attempted escape sequences
else if (scanner.scan("'") || scanner.scan('\\'))
continue;
// Otherwise, add the next char, unless it's a null byte.
else if ((ch = scanner.readChar()) != 0 && ch != null)
buf.writeCharCode(ch);
}
return buf.toString();
}
abstract class SqlExpressionBuilder<T> {
bool get hasValue;
/// A base class for objects that compile to SQL queries, typically within an ORM.
abstract class QueryBase<T> {
String compile(); String compile();
void isBetween(T lower, T upper); T deserialize(List row);
void isNotBetween(T lower, T upper); Future<List<T>> get(QueryExecutor executor) async {
var sql = compile();
return executor.query(sql).then((it) => it.map(deserialize).toList());
}
void isIn(Iterable<T> values); Future<T> getOne(QueryExecutor executor) {
return get(executor).then((it) => it.isEmpty ? null : it.first);
}
void isNotIn(Iterable<T> values); Union<T> union(QueryBase<T> other) {
return new Union(this, other);
}
Union<T> unionAll(QueryBase<T> other) {
return new Union(this, other, all: true);
}
} }
class NumericSqlExpressionBuilder<T extends num> /// A SQL `SELECT` query builder.
implements SqlExpressionBuilder<T> { abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
bool _hasValue = false; /// The table against which to execute this query.
String _op = '='; String get tableName;
String _raw;
T _value;
@override /// The list of fields returned by this query.
bool get hasValue => _hasValue; ///
/// If it's `null`, then this query will perform a `SELECT *`.
List<String> get fields;
bool _change(String op, T value) { /// A reference to an abstract query builder.
_raw = null; ///
_op = op; /// This is often a generated class.
_value = value; Where get where;
return _hasValue = true;
}
@override @override
String compile() { String compile() {
if (_raw != null) return _raw; var b = new StringBuffer('SELECT ');
if (_value == null) return null; if (fields == null)
return '$_op $_value'; b.write('*');
} else
b.write(fields.join(', '));
operator <(T value) => _change('<', value); b.write(' FROM $tableName');
var whereClause = where.compile();
operator >(T value) => _change('>', value); if (whereClause.isNotEmpty) b.write(' WHERE $whereClause');
return b.toString();
operator <=(T value) => _change('<=', value);
operator >=(T value) => _change('>=', value);
void lessThan(T value) {
_change('<', value);
}
void lessThanOrEqualTo(T value) {
_change('<=', value);
}
void greaterThan(T value) {
_change('>', value);
}
void greaterThanOrEqualTo(T value) {
_change('>=', value);
}
void equals(T value) {
_change('=', value);
}
void notEquals(T value) {
_change('!=', value);
}
@override
void isBetween(T lower, T upper) {
_raw = 'BETWEEN $lower AND $upper';
_hasValue = true;
}
@override
void isNotBetween(T lower, T upper) {
_raw = 'NOT BETWEEN $lower AND $upper';
_hasValue = true;
}
@override
void isIn(Iterable<T> values) {
_raw = 'IN (' + values.join(', ') + ')';
_hasValue = true;
}
@override
void isNotIn(Iterable<T> values) {
_raw = 'NOT IN (' + values.join(', ') + ')';
_hasValue = true;
} }
} }
class StringSqlExpressionBuilder implements SqlExpressionBuilder<String> { /// Builds a SQL `WHERE` clause.
bool _hasValue = false; abstract class QueryWhere {
String _op = '=', _raw, _value; final Set<QueryWhere> _and = new Set();
final Set<QueryWhere> _or = new Set();
Map<String, SqlExpressionBuilder> get expressionBuilders;
void and(QueryWhere other) {
_and.add(other);
}
void or(QueryWhere other) {
_or.add(other);
}
String compile() {
var b = new StringBuffer();
int i = 0;
for (var entry in expressionBuilders.entries) {
var key = entry.key, builder = entry.value;
if (builder.hasValue) {
if (i++ > 0) b.write(' AND ');
b.write('$key ${builder.compile()}');
}
}
for (var other in _and) {
var sql = other.compile();
if (sql.isNotEmpty) b.write(' AND $sql');
}
for (var other in _or) {
var sql = other.compile();
if (sql.isNotEmpty) b.write(' OR $sql');
}
return b.toString();
}
}
/// Represents the `UNION` of two subqueries.
class Union<T> extends QueryBase<T> {
final QueryBase<T> left, right;
final bool all;
Union(this.left, this.right, {this.all: false});
@override @override
bool get hasValue => _hasValue; T deserialize(List row) => left.deserialize(row);
bool _change(String op, String value) {
_raw = null;
_op = op;
_value = value;
return _hasValue = true;
}
@override @override
String compile() { String compile() {
if (_raw != null) return _raw; var selector = all == true ? 'UNION ALL' : 'UNION';
if (_value == null) return null; return '(${left.compile()}) $selector (${right.compile()})';
var v = sanitizeExpression(_value);
return "$_op '$v'";
}
void isEmpty() => equals('');
void equals(String value) {
_change('=', value);
}
void notEquals(String value) {
_change('!=', value);
}
void like(String value) {
_change('LIKE', value);
}
@override
void isBetween(String lower, String upper) {
var l = sanitizeExpression(lower), u = sanitizeExpression(upper);
_raw = "BETWEEN '$l' AND '$u'";
_hasValue = true;
}
@override
void isNotBetween(String lower, String upper) {
var l = sanitizeExpression(lower), u = sanitizeExpression(upper);
_raw = "NOT BETWEEN '$l' AND '$u'";
_hasValue = true;
}
@override
void isIn(Iterable<String> values) {
_raw = 'IN (' +
values.map(sanitizeExpression).map((s) => "'$s'").join(', ') +
')';
_hasValue = true;
}
@override
void isNotIn(Iterable<String> values) {
_raw = 'NOT IN (' +
values.map(sanitizeExpression).map((s) => "'$s'").join(', ') +
')';
_hasValue = true;
} }
} }
class BooleanSqlExpressionBuilder implements SqlExpressionBuilder<bool> { /// An abstract interface that performs queries.
bool _hasValue = false; ///
String _op = '=', _raw; /// This class should be implemented.
bool _value; abstract class QueryExecutor {
const QueryExecutor();
@override Future<List<List>> query(String query);
bool get hasValue => _hasValue;
bool _change(String op, bool value) {
_raw = null;
_op = op;
_value = value;
return _hasValue = true;
}
@override
String compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
var v = _value ? 'TRUE' : 'FALSE';
return '$_op $v';
}
void equals(bool value) {
_change('=', value);
}
void notEquals(bool value) {
_change('!=', value);
}
@override
void isBetween(bool lower, bool upper) => throw new UnsupportedError(
'Booleans do not support BETWEEN expressions.');
@override
void isNotBetween(bool lower, bool upper) => isBetween(lower, upper);
@override
void isIn(Iterable<bool> values) {
_raw = 'IN (' + values.map((b) => b ? 'TRUE' : 'FALSE').join(', ') + ')';
_hasValue = true;
}
@override
void isNotIn(Iterable<bool> values) {
_raw =
'NOT IN (' + values.map((b) => b ? 'TRUE' : 'FALSE').join(', ') + ')';
_hasValue = true;
}
}
class DateTimeSqlExpressionBuilder implements SqlExpressionBuilder<DateTime> {
final NumericSqlExpressionBuilder<int> year =
new NumericSqlExpressionBuilder<int>(),
month = new NumericSqlExpressionBuilder<int>(),
day = new NumericSqlExpressionBuilder<int>(),
hour = new NumericSqlExpressionBuilder<int>(),
minute = new NumericSqlExpressionBuilder<int>(),
second = new NumericSqlExpressionBuilder<int>();
final String columnName;
String _raw;
DateTimeSqlExpressionBuilder(this.columnName);
@override
bool get hasValue =>
_raw?.isNotEmpty == true ||
year.hasValue ||
month.hasValue ||
day.hasValue ||
hour.hasValue ||
minute.hasValue ||
second.hasValue;
bool _change(String _op, DateTime dt, bool time) {
var dateString = time ? dateYmdHms.format(dt) : dateYmd.format(dt);
_raw = '$columnName $_op \'$dateString\'';
return true;
}
operator <(DateTime value) => _change('<', value, true);
operator <=(DateTime value) => _change('<=', value, true);
operator >(DateTime value) => _change('>', value, true);
operator >=(DateTime value) => _change('>=', value, true);
void equals(DateTime value, {bool includeTime: true}) {
_change('=', value, includeTime != false);
}
void lessThan(DateTime value, {bool includeTime: true}) {
_change('<', value, includeTime != false);
}
void lessThanOrEqualTo(DateTime value, {bool includeTime: true}) {
_change('<=', value, includeTime != false);
}
void greaterThan(DateTime value, {bool includeTime: true}) {
_change('>', value, includeTime != false);
}
void greaterThanOrEqualTo(DateTime value, {bool includeTime: true}) {
_change('>=', value, includeTime != false);
}
@override
void isIn(Iterable<DateTime> values) {
_raw = '$columnName IN (' +
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
')';
}
@override
void isNotIn(Iterable<DateTime> values) {
_raw = '$columnName NOT IN (' +
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
')';
}
@override
void isBetween(DateTime lower, DateTime upper) {
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
_raw = "$columnName BETWEEN '$l' and '$u'";
}
@override
void isNotBetween(DateTime lower, DateTime upper) {
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
_raw = "$columnName NOT BETWEEN '$l' and '$u'";
}
@override
String compile() {
if (_raw?.isNotEmpty == true) return _raw;
List<String> parts = [];
if (year.hasValue) parts.add('YEAR($columnName) ${year.compile()}');
if (month.hasValue) parts.add('MONTH($columnName) ${month.compile()}');
if (day.hasValue) parts.add('DAY($columnName) ${day.compile()}');
if (hour.hasValue) parts.add('HOUR($columnName) ${hour.compile()}');
if (minute.hasValue) parts.add('MINUTE($columnName) ${minute.compile()}');
if (second.hasValue) parts.add('SECOND($columnName) ${second.compile()}');
return parts.isEmpty ? null : parts.join(' AND ');
}
} }

View file

@ -10,4 +10,7 @@ dependencies:
meta: ^1.0.0 meta: ^1.0.0
string_scanner: ^1.0.0 string_scanner: ^1.0.0
dev_dependencies: dev_dependencies:
angel_model: ^1.0.0 angel_model: ^1.0.0
angel_serialize: ^2.0.0
angel_serialize_generator: ^2.0.0
build_runner: ^1.0.0