This commit is contained in:
Tobe O 2019-01-24 12:20:34 -05:00
parent 599104f353
commit 50c4b394c7
24 changed files with 377 additions and 229 deletions

View file

@ -1,3 +1,6 @@
# 2.0.0-dev.18
* Add `ListSqlExpressionBuilder` (still in development).
# 2.0.0-dev.17
* Add `EnumSqlExpressionBuilder`.

View file

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:charcode/ascii.dart';
import 'package:intl/intl.dart' show DateFormat;
import 'package:string_scanner/string_scanner.dart';
@ -47,14 +49,6 @@ 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>
@ -116,25 +110,21 @@ class NumericSqlExpressionBuilder<T extends num>
_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;
@ -189,19 +179,15 @@ class EnumSqlExpressionBuilder<T> extends SqlExpressionBuilder<T> {
_change('!=', value);
}
@override
void isBetween(T lower, T upper) => throw _unsupported();
@override
void isNotBetween(T lower, T upper) => throw _unsupported();
@override
void isIn(Iterable<T> values) {
_raw = 'IN (' + values.map(_getValue).join(', ') + ')';
_hasValue = true;
}
@override
void isNotIn(Iterable<T> values) {
_raw = 'NOT IN (' + values.map(_getValue).join(', ') + ')';
_hasValue = true;
@ -262,7 +248,6 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
_hasValue = true;
}
@override
void isBetween(String lower, String upper) {
query.substitutionValues[lowerName] = lower;
query.substitutionValues[upperName] = upper;
@ -270,7 +255,6 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
_hasValue = true;
}
@override
void isNotBetween(String lower, String upper) {
query.substitutionValues[lowerName] = lower;
query.substitutionValues[upperName] = upper;
@ -288,13 +272,11 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
')';
}
@override
void isIn(Iterable<String> values) {
_raw = _in(values);
_hasValue = true;
}
@override
void isNotIn(Iterable<String> values) {
_raw = 'NOT ' + _in(values);
_hasValue = true;
@ -338,26 +320,6 @@ class BooleanSqlExpressionBuilder extends SqlExpressionBuilder<bool> {
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 extends SqlExpressionBuilder<DateTime> {
@ -425,27 +387,23 @@ class DateTimeSqlExpressionBuilder extends SqlExpressionBuilder<DateTime> {
_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'";
@ -471,60 +429,89 @@ class DateTimeSqlExpressionBuilder extends SqlExpressionBuilder<DateTime> {
}
}
class MapSqlExpressionBuilder extends SqlExpressionBuilder {
abstract class JsonSqlExpressionBuilder<T, K> extends SqlExpressionBuilder<T> {
final List<JsonSqlExpressionBuilderProperty> _properties = [];
bool _hasValue = false;
Map _value;
T _value;
String _op;
String _raw;
MapSqlExpressionBuilder(Query query, String columnName)
JsonSqlExpressionBuilder(Query query, String columnName)
: super(query, columnName);
MapSqlExpressionBuilderProperty operator [](String name) {
return MapSqlExpressionBuilderProperty(this, name);
JsonSqlExpressionBuilderProperty operator [](K name) {
var p = _property(name);
_properties.add(p);
return p;
}
bool get hasRaw => _raw != null;
JsonSqlExpressionBuilderProperty _property(K name);
bool get hasRaw => _raw != null || _properties.any((p) => p.hasValue);
@override
bool get hasValue => _hasValue;
bool get hasValue => _hasValue || _properties.any((p) => p.hasValue);
UnsupportedError _unsupported() =>
UnsupportedError('JSON/JSONB does not support this operation.');
_encodeValue(T v) => v;
void _append(SqlExpressionBuilder b) {
var c = b.compile();
if (c != null) {
_hasValue = true;
_raw ??= '';
if (b is! DateTimeSqlExpressionBuilder) {
_raw += '${b.columnName} ';
}
_raw += c;
}
}
bool _change(String op, Map value) {
bool _change(String op, T value) {
_raw = null;
_op = op;
_value = value;
query.substitutionValues[substitution] = _value;
query.substitutionValues[substitution] = _encodeValue(_value);
return _hasValue = true;
}
@override
String compile() {
var s = _compile();
if (!_properties.any((p) => p.hasValue)) return s;
s ??= '';
for (var p in _properties) {
if (p.hasValue) {
var c = p.compile();
if (c != null) {
_hasValue = true;
s ??= '';
if (p.typed is! DateTimeSqlExpressionBuilder) {
s += '${p.typed.columnName} ';
}
s += c;
}
}
}
return s;
}
String _compile() {
if (_raw != null) return _raw;
if (_value == null) return null;
return "::jsonb $_op @$substitution::jsonb";
}
void contains(Map value) {
void contains(T value) {
_change('@>', value);
}
void equals(T value) {
_change('=', value);
}
}
class MapSqlExpressionBuilder extends JsonSqlExpressionBuilder<Map, String> {
MapSqlExpressionBuilder(Query query, String columnName)
: super(query, columnName);
@override
JsonSqlExpressionBuilderProperty _property(String name) {
return JsonSqlExpressionBuilderProperty(this, name, false);
}
void containsKey(String key) {
this[key].isNotNull();
}
@ -532,89 +519,96 @@ class MapSqlExpressionBuilder extends SqlExpressionBuilder {
void containsPair(key, value) {
contains({key: value});
}
void equals(Map value) {
_change('=', value);
}
@override
void isBetween(lower, upper) => throw _unsupported();
@override
void isIn(Iterable values) => throw _unsupported();
@override
void isNotBetween(lower, upper) => throw _unsupported();
@override
void isNotIn(Iterable values) => throw _unsupported();
}
class MapSqlExpressionBuilderProperty {
final MapSqlExpressionBuilder builder;
final String name;
class ListSqlExpressionBuilder extends JsonSqlExpressionBuilder<List, int> {
ListSqlExpressionBuilder(Query query, String columnName)
: super(query, columnName);
MapSqlExpressionBuilderProperty(this.builder, this.name);
@override
_encodeValue(List v) => json.encode(v);
@override
JsonSqlExpressionBuilderProperty _property(int name) {
return JsonSqlExpressionBuilderProperty(this, name.toString(), true);
}
}
class JsonSqlExpressionBuilderProperty {
final JsonSqlExpressionBuilder builder;
final String name;
final bool isInt;
SqlExpressionBuilder _typed;
JsonSqlExpressionBuilderProperty(this.builder, this.name, this.isInt);
SqlExpressionBuilder get typed => _typed;
bool get hasValue => _typed?.hasValue == true;
String compile() => _typed?.compile();
T _set<T extends SqlExpressionBuilder>(T Function() value) {
if (_typed is T) {
return _typed as T;
} else if (_typed != null) {
throw StateError(
'$nameString is already typed as $_typed, and cannot be changed.');
} else {
_typed = value().._isProperty = true;
return _typed as T;
}
}
String get nameString {
if (isInt) {
return '(${builder.columnName}->>$name)::jsonb';
} else {
return "(${builder.columnName}->>'$name')::jsonb";
}
}
void isNotNull() {
builder
.._hasValue = true
.._raw ??= ''
.._raw += "${builder.columnName}->>'$name' IS NOT NULL";
.._raw += "$nameString IS NOT NULL";
}
void isNull() {
builder
.._hasValue = true
.._raw ??= ''
.._raw += "${builder.columnName}->>'$name' IS NULL";
.._raw += "$nameString IS NULL";
}
void asString(void Function(StringSqlExpressionBuilder) f) {
var b = StringSqlExpressionBuilder(
builder.query, "${builder.columnName}->>'$name'")
.._isProperty = true;
f(b);
builder._append(b);
StringSqlExpressionBuilder get asString {
return _set(() => StringSqlExpressionBuilder(builder.query, nameString));
}
void asBool(void Function(BooleanSqlExpressionBuilder) f) {
var b = BooleanSqlExpressionBuilder(
builder.query, "${builder.columnName}->>'$name'")
.._isProperty = true;
f(b);
builder._append(b);
BooleanSqlExpressionBuilder get asBool {
return _set(() => BooleanSqlExpressionBuilder(builder.query, nameString));
}
void asDateTime(void Function(DateTimeSqlExpressionBuilder) f) {
var b = DateTimeSqlExpressionBuilder(
builder.query, "${builder.columnName}->>'$name'")
.._isProperty = true;
f(b);
builder._append(b);
DateTimeSqlExpressionBuilder get asDateTime {
return _set(() => DateTimeSqlExpressionBuilder(builder.query, nameString));
}
void asDouble(void Function(NumericSqlExpressionBuilder<double>) f) {
var b = NumericSqlExpressionBuilder<double>(
builder.query, "${builder.columnName}->>'$name'")
.._isProperty = true;
f(b);
builder._append(b);
NumericSqlExpressionBuilder<double> get asDouble {
return _set(
() => NumericSqlExpressionBuilder<double>(builder.query, nameString));
}
void asInt(void Function(NumericSqlExpressionBuilder<int>) f) {
var b = NumericSqlExpressionBuilder<int>(
builder.query, "${builder.columnName}->>'$name'")
.._isProperty = true;
f(b);
builder._append(b);
NumericSqlExpressionBuilder<int> get asInt {
return _set(
() => NumericSqlExpressionBuilder<int>(builder.query, nameString));
}
void asMap(void Function(MapSqlExpressionBuilder) f) {
var b = MapSqlExpressionBuilder(
builder.query, "${builder.columnName}->>'$name'")
.._isProperty = true;
f(b);
builder._append(b);
MapSqlExpressionBuilder get asMap {
return _set(() => MapSqlExpressionBuilder(builder.query, nameString));
}
ListSqlExpressionBuilder get asList {
return _set(() => ListSqlExpressionBuilder(builder.query, nameString));
}
}

View file

@ -341,8 +341,19 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
}
abstract class QueryValues {
Map<String, String> get casts => {};
Map<String, dynamic> toMap();
String applyCast(String name, String sub) {
if (casts.containsKey(name)) {
var type = casts[name];
return 'CAST ($sub as $type)';
} else {
return sub;
}
}
String compileInsert(Query query, String tableName) {
var data = toMap();
if (data.isEmpty) return null;
@ -355,8 +366,9 @@ abstract class QueryValues {
if (i++ > 0) b.write(', ');
var name = query.reserveName(entry.key);
var s = applyCast(entry.key, '@$name');
query.substitutionValues[name] = entry.value;
b.write('@$name');
b.write(s);
}
b.write(')');
@ -376,8 +388,9 @@ abstract class QueryValues {
b.write('=');
var name = query.reserveName(entry.key);
var s = applyCast(entry.key, '@$name');
query.substitutionValues[name] = entry.value;
b.write('@$name');
b.write(s);
}
return b.toString();
}
@ -421,7 +434,7 @@ abstract class QueryWhere {
if (builder.hasValue) {
if (i++ > 0) b.write(' AND ');
if (builder is DateTimeSqlExpressionBuilder ||
(builder is MapSqlExpressionBuilder && builder.hasRaw)) {
(builder is JsonSqlExpressionBuilder && builder.hasRaw)) {
if (tableName != null) b.write('$tableName.');
b.write(builder.compile());
} else {

View file

@ -1,5 +1,5 @@
name: angel_orm
version: 2.0.0-dev.17
version: 2.0.0-dev.18
description: Runtime support for Angel's ORM. Includes base classes for queries.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/orm

View file

@ -1,3 +1,6 @@
# 2.0.0-dev.4
* List generation support.
# 2.0.0-dev.3
* Add JSON/JSONB support for Maps.

View file

@ -217,6 +217,8 @@ ColumnType inferColumnType(DartType type) {
return ColumnType.timeStamp;
if (const TypeChecker.fromRuntime(Map).isAssignableFromType(type))
return ColumnType.jsonb;
if (const TypeChecker.fromRuntime(List).isAssignableFromType(type))
return ColumnType.jsonb;
if (type is InterfaceType && type.element.isEnum) return ColumnType.int;
return null;
}

View file

@ -515,6 +515,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} else if (const TypeChecker.fromRuntime(Map)
.isAssignableFromType(type)) {
builderType = refer('MapSqlExpressionBuilder');
} else if (const TypeChecker.fromRuntime(List)
.isAssignableFromType(type)) {
builderType = refer('ListSqlExpressionBuilder');
} else if (ctx.relations.containsKey(field.name)) {
var relation = ctx.relations[field.name];
if (relation.type != RelationshipType.belongsTo)
@ -565,6 +568,30 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..name = '${rc.pascalCase}QueryValues'
..extend = refer('MapQueryValues');
// Override casts so that we can cast Lists
clazz.methods.add(Method((b) {
b
..name = 'casts'
..annotations.add(refer('override'))
..type = MethodType.getter
..body = Block((b) {
var args = <String, Expression>{};
for (var field in ctx.effectiveFields) {
var fType = field.type;
var name = ctx.buildContext.resolveFieldName(field.name);
var type = ctx.columns[field.name]?.type?.name;
if (type == null) continue;
if (const TypeChecker.fromRuntime(List)
.isAssignableFromType(fType)) {
args[name] = literalString(type);
}
}
b.addExpression(literalMap(args).returned);
});
}));
// Each field generates a getter for setter
for (var field in ctx.effectiveFields) {
var fType = field.type;
@ -580,6 +607,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
var asInt = value.asA(refer('int'));
var t = convertTypeReference(fType);
value = t.property('values').index(asInt);
} else if (const TypeChecker.fromRuntime(List)
.isAssignableFromType(fType)) {
value = refer('json')
.property('decode')
.call([value.asA(refer('String'))]).asA(refer('List'));
} else {
value = value.asA(type);
}
@ -596,6 +628,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
if (fType is InterfaceType && fType.element.isEnum) {
value = value.property('index');
} else if (const TypeChecker.fromRuntime(List)
.isAssignableFromType(fType)) {
value = refer('json').property('encode').call([value]);
}
b
@ -618,18 +653,13 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
..name = 'model'
..type = ctx.buildContext.modelClassType))
..body = new Block((b) {
var args = <String, Expression>{};
for (var field in ctx.effectiveFields) {
if (isSpecialId(ctx, field) || field is RelationFieldImpl)
continue;
args[ctx.buildContext.resolveFieldName(field.name)] =
refer('model').property(field.name);
b.addExpression(refer(field.name)
.assign(refer('model').property(field.name)));
}
b.addExpression(
refer('values').property('addAll').call([literalMap(args)]));
for (var field in ctx.effectiveFields) {
if (field is RelationFieldImpl) {
var original = field.originalFieldName;

View file

@ -1,5 +1,5 @@
name: angel_orm_generator
version: 2.0.0-dev.3
version: 2.0.0-dev.4
description: Code generators for Angel's ORM. Generates query builder classes.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/orm

View file

@ -35,6 +35,7 @@ class PostgresExecutor extends QueryExecutor {
if (!Platform.environment.containsKey('STFU')) {
print('Running: $query');
if (substitutionValues.isNotEmpty) print('Values: $substitutionValues');
print(substitutionValues.map((k, v) => MapEntry(k, v.runtimeType)));
}
return connection.query(query, substitutionValues: substitutionValues);
}

View file

@ -10,14 +10,20 @@ main() {
});
test('insert', () async {
var query = HasMapQuery()..values.value = {'foo': 'bar'};
var query = HasMapQuery();
query.values
..value = {'foo': 'bar'}
..list = ['1', 2, 3.0];
var model = await query.insert(executor);
print(model.toJson());
expect(model, HasMap(value: {'foo': 'bar'}));
expect(model, HasMap(value: {'foo': 'bar'}, list: ['1', 2, 3.0]));
});
test('insert', () async {
var query = HasMapQuery()..values.value = {'foo': 'bar'};
test('update', () async {
var query = HasMapQuery();
query.values
..value = {'foo': 'bar'}
..list = ['1', 2, 3.0];
var model = await query.insert(executor);
print(model.toJson());
@ -29,7 +35,10 @@ main() {
HasMap initialValue;
setUp(() async {
var query = HasMapQuery()..values.value = {'foo': 'bar'};
var query = HasMapQuery();
query.values
..value = {'foo': 'bar'}
..list = ['1', 2, 3.0];
initialValue = await query.insert(executor);
});
@ -42,15 +51,35 @@ main() {
var query = HasMapQuery();
query.where.value.equals({'foo': 'bar'});
expect(await query.get(executor), [initialValue]);
query = HasMapQuery();
query.where.value.equals({'foo': 'baz'});
expect(await query.get(executor), isEmpty);
});
test('property equals', () async {
test('list equals', () async {
var query = HasMapQuery();
query.where.value['foo'].asString((b) => b.equals('bar'));
query.where.list.equals(['1', 2, 3.0]);
expect(await query.get(executor), [initialValue]);
query = HasMapQuery();
query.where.value['foo'].asString((b) => b.equals('baz'));
query.where.list.equals(['10', 20, 30.0]);
expect(await query.get(executor), isEmpty);
});
test('property equals', () async {
var query = HasMapQuery()..where.value['foo'].asString.equals('bar');
expect(await query.get(executor), [initialValue]);
query = HasMapQuery()..where.value['foo'].asString.equals('baz');
expect(await query.get(executor), []);
});
test('index equals', () async {
var query = HasMapQuery()..where.list[0].asString.equals('1');
expect(await query.get(executor), [initialValue]);
query = HasMapQuery()..where.list[1].asInt.equals(3);
expect(await query.get(executor), []);
});
});

View file

@ -1,6 +1,7 @@
CREATE TEMPORARY TABLE "has_maps" (
id serial PRIMARY KEY,
value jsonb not null,
list jsonb not null,
created_at timestamp,
updated_at timestamp
);

View file

@ -95,6 +95,11 @@ class AuthorQueryWhere extends QueryWhere {
}
class AuthorQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -116,11 +121,9 @@ class AuthorQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Author model) {
values.addAll({
'name': model.name,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
name = model.name;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -123,6 +123,11 @@ class BookQueryWhere extends QueryWhere {
}
class BookQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -154,11 +159,9 @@ class BookQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Book model) {
values.addAll({
'name': model.name,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
name = model.name;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
if (model.author != null) {
values['author_id'] = int.parse(model.author.id);
}

View file

@ -127,6 +127,11 @@ class CarQueryWhere extends QueryWhere {
}
class CarQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -163,14 +168,12 @@ class CarQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Car model) {
values.addAll({
'make': model.make,
'description': model.description,
'family_friendly': model.familyFriendly,
'recalled_at': model.recalledAt,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
make = model.make;
description = model.description;
familyFriendly = model.familyFriendly;
recalledAt = model.recalledAt;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -90,6 +90,11 @@ class CustomerQueryWhere extends QueryWhere {
}
class CustomerQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -106,8 +111,8 @@ class CustomerQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Customer model) {
values
.addAll({'created_at': model.createdAt, 'updated_at': model.updatedAt});
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -100,6 +100,11 @@ class FootQueryWhere extends QueryWhere {
}
class FootQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -126,12 +131,10 @@ class FootQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Foot model) {
values.addAll({
'leg_id': model.legId,
'n_toes': model.nToes,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
legId = model.legId;
nToes = model.nToes;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -100,6 +100,11 @@ class FruitQueryWhere extends QueryWhere {
}
class FruitQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -126,12 +131,10 @@ class FruitQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Fruit model) {
values.addAll({
'tree_id': model.treeId,
'common_name': model.commonName,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
treeId = model.treeId;
commonName = model.commonName;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -96,6 +96,11 @@ class HasCarQueryWhere extends QueryWhere {
}
class HasCarQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -117,11 +122,9 @@ class HasCarQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(HasCar model) {
values.addAll({
'type': model.type,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
type = model.type;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -10,4 +10,6 @@ part 'has_map.g.dart';
@serializable
abstract class _HasMap {
Map get value;
List get list;
}

View file

@ -11,6 +11,7 @@ class HasMapMigration extends Migration {
up(Schema schema) {
schema.create('has_maps', (table) {
table.declare('value', new ColumnType('jsonb'));
table.declare('list', new ColumnType('jsonb'));
});
}
@ -41,7 +42,7 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
@override
get fields {
return const ['value'];
return const ['value', 'list'];
}
@override
@ -56,7 +57,9 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
static HasMap parseRow(List row) {
if (row.every((x) => x == null)) return null;
var model = new HasMap(value: (row[0] as Map<dynamic, dynamic>));
var model = new HasMap(
value: (row[0] as Map<dynamic, dynamic>),
list: (row[1] as List<dynamic>));
return model;
}
@ -68,24 +71,38 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
class HasMapQueryWhere extends QueryWhere {
HasMapQueryWhere(HasMapQuery query)
: value = new MapSqlExpressionBuilder(query, 'value');
: value = new MapSqlExpressionBuilder(query, 'value'),
list = new ListSqlExpressionBuilder(query, 'list');
final MapSqlExpressionBuilder value;
final ListSqlExpressionBuilder list;
@override
get expressionBuilders {
return [value];
return [value, list];
}
}
class HasMapQueryValues extends MapQueryValues {
@override
get casts {
return {'list': 'jsonb'};
}
Map<dynamic, dynamic> get value {
return (values['value'] as Map<dynamic, dynamic>);
}
set value(Map<dynamic, dynamic> value) => values['value'] = value;
List<dynamic> get list {
return (json.decode((values['list'] as String)) as List);
}
set list(List<dynamic> value) => values['list'] = json.encode(value);
void copyFrom(HasMap model) {
values.addAll({'value': model.value});
value = model.value;
list = model.list;
}
}
@ -95,25 +112,30 @@ class HasMapQueryValues extends MapQueryValues {
@generatedSerializable
class HasMap implements _HasMap {
const HasMap({Map<dynamic, dynamic> this.value});
const HasMap({Map<dynamic, dynamic> this.value, List<dynamic> this.list});
@override
final Map<dynamic, dynamic> value;
HasMap copyWith({Map<dynamic, dynamic> value}) {
return new HasMap(value: value ?? this.value);
@override
final List<dynamic> list;
HasMap copyWith({Map<dynamic, dynamic> value, List<dynamic> list}) {
return new HasMap(value: value ?? this.value, list: list ?? this.list);
}
bool operator ==(other) {
return other is _HasMap &&
const MapEquality<dynamic, dynamic>(
keys: const DefaultEquality(), values: const DefaultEquality())
.equals(other.value, value);
.equals(other.value, value) &&
const ListEquality<dynamic>(const DefaultEquality())
.equals(other.list, list);
}
@override
int get hashCode {
return hashObjects([value]);
return hashObjects([value, list]);
}
Map<String, dynamic> toJson() {
@ -130,6 +152,9 @@ abstract class HasMapSerializer {
return new HasMap(
value: map['value'] is Map
? (map['value'] as Map).cast<dynamic, dynamic>()
: null,
list: map['list'] is Iterable
? (map['list'] as Iterable).cast<dynamic>().toList()
: null);
}
@ -137,12 +162,14 @@ abstract class HasMapSerializer {
if (model == null) {
return null;
}
return {'value': model.value};
return {'value': model.value, 'list': model.list};
}
}
abstract class HasMapFields {
static const List<String> allFields = const <String>[value];
static const List<String> allFields = const <String>[value, list];
static const String value = 'value';
static const String list = 'list';
}

View file

@ -104,6 +104,11 @@ class LegQueryWhere extends QueryWhere {
}
class LegQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -125,11 +130,9 @@ class LegQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Leg model) {
values.addAll({
'name': model.name,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
name = model.name;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -131,6 +131,11 @@ class OrderQueryWhere extends QueryWhere {
}
class OrderQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -167,13 +172,11 @@ class OrderQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Order model) {
values.addAll({
'employee_id': model.employeeId,
'order_date': model.orderDate,
'shipper_id': model.shipperId,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
employeeId = model.employeeId;
orderDate = model.orderDate;
shipperId = model.shipperId;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
if (model.customer != null) {
values['customer_id'] = int.parse(model.customer.id);
}

View file

@ -165,6 +165,11 @@ class TreeQueryWhere extends QueryWhere {
}
class TreeQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -186,11 +191,9 @@ class TreeQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Tree model) {
values.addAll({
'rings': model.rings,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
rings = model.rings;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}

View file

@ -147,6 +147,11 @@ class UserQueryWhere extends QueryWhere {
}
class UserQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -178,13 +183,11 @@ class UserQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(User model) {
values.addAll({
'username': model.username,
'password': model.password,
'email': model.email,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
username = model.username;
password = model.password;
email = model.email;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}
@ -273,6 +276,11 @@ class RoleUserQueryWhere extends QueryWhere {
}
class RoleUserQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -299,8 +307,8 @@ class RoleUserQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(RoleUser model) {
values
.addAll({'created_at': model.createdAt, 'updated_at': model.updatedAt});
createdAt = model.createdAt;
updatedAt = model.updatedAt;
if (model.role != null) {
values['role_id'] = int.parse(model.role.id);
}
@ -378,6 +386,11 @@ class RoleQueryWhere extends QueryWhere {
}
class RoleQueryValues extends MapQueryValues {
@override
get casts {
return {};
}
int get id {
return (values['id'] as int);
}
@ -399,11 +412,9 @@ class RoleQueryValues extends MapQueryValues {
set updatedAt(DateTime value) => values['updated_at'] = value;
void copyFrom(Role model) {
values.addAll({
'name': model.name,
'created_at': model.createdAt,
'updated_at': model.updatedAt
});
name = model.name;
createdAt = model.createdAt;
updatedAt = model.updatedAt;
}
}