lists
This commit is contained in:
parent
599104f353
commit
50c4b394c7
24 changed files with 377 additions and 229 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
# 2.0.0-dev.18
|
||||||
|
* Add `ListSqlExpressionBuilder` (still in development).
|
||||||
|
|
||||||
# 2.0.0-dev.17
|
# 2.0.0-dev.17
|
||||||
* Add `EnumSqlExpressionBuilder`.
|
* Add `EnumSqlExpressionBuilder`.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:charcode/ascii.dart';
|
import 'package:charcode/ascii.dart';
|
||||||
import 'package:intl/intl.dart' show DateFormat;
|
import 'package:intl/intl.dart' show DateFormat;
|
||||||
import 'package:string_scanner/string_scanner.dart';
|
import 'package:string_scanner/string_scanner.dart';
|
||||||
|
@ -47,14 +49,6 @@ abstract class SqlExpressionBuilder<T> {
|
||||||
bool get hasValue;
|
bool get hasValue;
|
||||||
|
|
||||||
String compile();
|
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>
|
class NumericSqlExpressionBuilder<T extends num>
|
||||||
|
@ -116,25 +110,21 @@ class NumericSqlExpressionBuilder<T extends num>
|
||||||
_change('!=', value);
|
_change('!=', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isBetween(T lower, T upper) {
|
void isBetween(T lower, T upper) {
|
||||||
_raw = 'BETWEEN $lower AND $upper';
|
_raw = 'BETWEEN $lower AND $upper';
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotBetween(T lower, T upper) {
|
void isNotBetween(T lower, T upper) {
|
||||||
_raw = 'NOT BETWEEN $lower AND $upper';
|
_raw = 'NOT BETWEEN $lower AND $upper';
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isIn(Iterable<T> values) {
|
void isIn(Iterable<T> values) {
|
||||||
_raw = 'IN (' + values.join(', ') + ')';
|
_raw = 'IN (' + values.join(', ') + ')';
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotIn(Iterable<T> values) {
|
void isNotIn(Iterable<T> values) {
|
||||||
_raw = 'NOT IN (' + values.join(', ') + ')';
|
_raw = 'NOT IN (' + values.join(', ') + ')';
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
|
@ -189,19 +179,15 @@ class EnumSqlExpressionBuilder<T> extends SqlExpressionBuilder<T> {
|
||||||
_change('!=', value);
|
_change('!=', value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isBetween(T lower, T upper) => throw _unsupported();
|
void isBetween(T lower, T upper) => throw _unsupported();
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotBetween(T lower, T upper) => throw _unsupported();
|
void isNotBetween(T lower, T upper) => throw _unsupported();
|
||||||
|
|
||||||
@override
|
|
||||||
void isIn(Iterable<T> values) {
|
void isIn(Iterable<T> values) {
|
||||||
_raw = 'IN (' + values.map(_getValue).join(', ') + ')';
|
_raw = 'IN (' + values.map(_getValue).join(', ') + ')';
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotIn(Iterable<T> values) {
|
void isNotIn(Iterable<T> values) {
|
||||||
_raw = 'NOT IN (' + values.map(_getValue).join(', ') + ')';
|
_raw = 'NOT IN (' + values.map(_getValue).join(', ') + ')';
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
|
@ -262,7 +248,6 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isBetween(String lower, String upper) {
|
void isBetween(String lower, String upper) {
|
||||||
query.substitutionValues[lowerName] = lower;
|
query.substitutionValues[lowerName] = lower;
|
||||||
query.substitutionValues[upperName] = upper;
|
query.substitutionValues[upperName] = upper;
|
||||||
|
@ -270,7 +255,6 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotBetween(String lower, String upper) {
|
void isNotBetween(String lower, String upper) {
|
||||||
query.substitutionValues[lowerName] = lower;
|
query.substitutionValues[lowerName] = lower;
|
||||||
query.substitutionValues[upperName] = upper;
|
query.substitutionValues[upperName] = upper;
|
||||||
|
@ -288,13 +272,11 @@ class StringSqlExpressionBuilder extends SqlExpressionBuilder<String> {
|
||||||
')';
|
')';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isIn(Iterable<String> values) {
|
void isIn(Iterable<String> values) {
|
||||||
_raw = _in(values);
|
_raw = _in(values);
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotIn(Iterable<String> values) {
|
void isNotIn(Iterable<String> values) {
|
||||||
_raw = 'NOT ' + _in(values);
|
_raw = 'NOT ' + _in(values);
|
||||||
_hasValue = true;
|
_hasValue = true;
|
||||||
|
@ -338,26 +320,6 @@ class BooleanSqlExpressionBuilder extends SqlExpressionBuilder<bool> {
|
||||||
void notEquals(bool value) {
|
void notEquals(bool value) {
|
||||||
_change('!=', 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> {
|
class DateTimeSqlExpressionBuilder extends SqlExpressionBuilder<DateTime> {
|
||||||
|
@ -425,27 +387,23 @@ class DateTimeSqlExpressionBuilder extends SqlExpressionBuilder<DateTime> {
|
||||||
_change('>=', value, includeTime != false);
|
_change('>=', value, includeTime != false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isIn(Iterable<DateTime> values) {
|
void isIn(Iterable<DateTime> values) {
|
||||||
_raw = '$columnName IN (' +
|
_raw = '$columnName IN (' +
|
||||||
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
|
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
|
||||||
')';
|
')';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotIn(Iterable<DateTime> values) {
|
void isNotIn(Iterable<DateTime> values) {
|
||||||
_raw = '$columnName NOT IN (' +
|
_raw = '$columnName NOT IN (' +
|
||||||
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
|
values.map(dateYmdHms.format).map((s) => '$s').join(', ') +
|
||||||
')';
|
')';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isBetween(DateTime lower, DateTime upper) {
|
void isBetween(DateTime lower, DateTime upper) {
|
||||||
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
|
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
|
||||||
_raw = "$columnName BETWEEN '$l' and '$u'";
|
_raw = "$columnName BETWEEN '$l' and '$u'";
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void isNotBetween(DateTime lower, DateTime upper) {
|
void isNotBetween(DateTime lower, DateTime upper) {
|
||||||
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
|
var l = dateYmdHms.format(lower), u = dateYmdHms.format(upper);
|
||||||
_raw = "$columnName NOT BETWEEN '$l' and '$u'";
|
_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;
|
bool _hasValue = false;
|
||||||
Map _value;
|
T _value;
|
||||||
String _op;
|
String _op;
|
||||||
String _raw;
|
String _raw;
|
||||||
|
|
||||||
MapSqlExpressionBuilder(Query query, String columnName)
|
JsonSqlExpressionBuilder(Query query, String columnName)
|
||||||
: super(query, columnName);
|
: super(query, columnName);
|
||||||
|
|
||||||
MapSqlExpressionBuilderProperty operator [](String name) {
|
JsonSqlExpressionBuilderProperty operator [](K name) {
|
||||||
return MapSqlExpressionBuilderProperty(this, 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
|
@override
|
||||||
bool get hasValue => _hasValue;
|
bool get hasValue => _hasValue || _properties.any((p) => p.hasValue);
|
||||||
|
|
||||||
UnsupportedError _unsupported() =>
|
_encodeValue(T v) => v;
|
||||||
UnsupportedError('JSON/JSONB does not support this operation.');
|
|
||||||
|
|
||||||
void _append(SqlExpressionBuilder b) {
|
bool _change(String op, T value) {
|
||||||
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) {
|
|
||||||
_raw = null;
|
_raw = null;
|
||||||
_op = op;
|
_op = op;
|
||||||
_value = value;
|
_value = value;
|
||||||
query.substitutionValues[substitution] = _value;
|
query.substitutionValues[substitution] = _encodeValue(_value);
|
||||||
return _hasValue = true;
|
return _hasValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String compile() {
|
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 (_raw != null) return _raw;
|
||||||
if (_value == null) return null;
|
if (_value == null) return null;
|
||||||
return "::jsonb $_op @$substitution::jsonb";
|
return "::jsonb $_op @$substitution::jsonb";
|
||||||
}
|
}
|
||||||
|
|
||||||
void contains(Map value) {
|
void contains(T value) {
|
||||||
_change('@>', 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) {
|
void containsKey(String key) {
|
||||||
this[key].isNotNull();
|
this[key].isNotNull();
|
||||||
}
|
}
|
||||||
|
@ -532,89 +519,96 @@ class MapSqlExpressionBuilder extends SqlExpressionBuilder {
|
||||||
void containsPair(key, value) {
|
void containsPair(key, value) {
|
||||||
contains({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 {
|
class ListSqlExpressionBuilder extends JsonSqlExpressionBuilder<List, int> {
|
||||||
final MapSqlExpressionBuilder builder;
|
ListSqlExpressionBuilder(Query query, String columnName)
|
||||||
final String name;
|
: 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() {
|
void isNotNull() {
|
||||||
builder
|
builder
|
||||||
.._hasValue = true
|
.._hasValue = true
|
||||||
.._raw ??= ''
|
.._raw ??= ''
|
||||||
.._raw += "${builder.columnName}->>'$name' IS NOT NULL";
|
.._raw += "$nameString IS NOT NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
void isNull() {
|
void isNull() {
|
||||||
builder
|
builder
|
||||||
.._hasValue = true
|
.._hasValue = true
|
||||||
.._raw ??= ''
|
.._raw ??= ''
|
||||||
.._raw += "${builder.columnName}->>'$name' IS NULL";
|
.._raw += "$nameString IS NULL";
|
||||||
}
|
}
|
||||||
|
|
||||||
void asString(void Function(StringSqlExpressionBuilder) f) {
|
StringSqlExpressionBuilder get asString {
|
||||||
var b = StringSqlExpressionBuilder(
|
return _set(() => StringSqlExpressionBuilder(builder.query, nameString));
|
||||||
builder.query, "${builder.columnName}->>'$name'")
|
|
||||||
.._isProperty = true;
|
|
||||||
f(b);
|
|
||||||
builder._append(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void asBool(void Function(BooleanSqlExpressionBuilder) f) {
|
BooleanSqlExpressionBuilder get asBool {
|
||||||
var b = BooleanSqlExpressionBuilder(
|
return _set(() => BooleanSqlExpressionBuilder(builder.query, nameString));
|
||||||
builder.query, "${builder.columnName}->>'$name'")
|
|
||||||
.._isProperty = true;
|
|
||||||
f(b);
|
|
||||||
builder._append(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void asDateTime(void Function(DateTimeSqlExpressionBuilder) f) {
|
DateTimeSqlExpressionBuilder get asDateTime {
|
||||||
var b = DateTimeSqlExpressionBuilder(
|
return _set(() => DateTimeSqlExpressionBuilder(builder.query, nameString));
|
||||||
builder.query, "${builder.columnName}->>'$name'")
|
|
||||||
.._isProperty = true;
|
|
||||||
f(b);
|
|
||||||
builder._append(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void asDouble(void Function(NumericSqlExpressionBuilder<double>) f) {
|
NumericSqlExpressionBuilder<double> get asDouble {
|
||||||
var b = NumericSqlExpressionBuilder<double>(
|
return _set(
|
||||||
builder.query, "${builder.columnName}->>'$name'")
|
() => NumericSqlExpressionBuilder<double>(builder.query, nameString));
|
||||||
.._isProperty = true;
|
|
||||||
f(b);
|
|
||||||
builder._append(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void asInt(void Function(NumericSqlExpressionBuilder<int>) f) {
|
NumericSqlExpressionBuilder<int> get asInt {
|
||||||
var b = NumericSqlExpressionBuilder<int>(
|
return _set(
|
||||||
builder.query, "${builder.columnName}->>'$name'")
|
() => NumericSqlExpressionBuilder<int>(builder.query, nameString));
|
||||||
.._isProperty = true;
|
|
||||||
f(b);
|
|
||||||
builder._append(b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void asMap(void Function(MapSqlExpressionBuilder) f) {
|
MapSqlExpressionBuilder get asMap {
|
||||||
var b = MapSqlExpressionBuilder(
|
return _set(() => MapSqlExpressionBuilder(builder.query, nameString));
|
||||||
builder.query, "${builder.columnName}->>'$name'")
|
}
|
||||||
.._isProperty = true;
|
|
||||||
f(b);
|
ListSqlExpressionBuilder get asList {
|
||||||
builder._append(b);
|
return _set(() => ListSqlExpressionBuilder(builder.query, nameString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,8 +341,19 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class QueryValues {
|
abstract class QueryValues {
|
||||||
|
Map<String, String> get casts => {};
|
||||||
|
|
||||||
Map<String, dynamic> toMap();
|
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) {
|
String compileInsert(Query query, String tableName) {
|
||||||
var data = toMap();
|
var data = toMap();
|
||||||
if (data.isEmpty) return null;
|
if (data.isEmpty) return null;
|
||||||
|
@ -355,8 +366,9 @@ abstract class QueryValues {
|
||||||
if (i++ > 0) b.write(', ');
|
if (i++ > 0) b.write(', ');
|
||||||
|
|
||||||
var name = query.reserveName(entry.key);
|
var name = query.reserveName(entry.key);
|
||||||
|
var s = applyCast(entry.key, '@$name');
|
||||||
query.substitutionValues[name] = entry.value;
|
query.substitutionValues[name] = entry.value;
|
||||||
b.write('@$name');
|
b.write(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
b.write(')');
|
b.write(')');
|
||||||
|
@ -376,8 +388,9 @@ abstract class QueryValues {
|
||||||
b.write('=');
|
b.write('=');
|
||||||
|
|
||||||
var name = query.reserveName(entry.key);
|
var name = query.reserveName(entry.key);
|
||||||
|
var s = applyCast(entry.key, '@$name');
|
||||||
query.substitutionValues[name] = entry.value;
|
query.substitutionValues[name] = entry.value;
|
||||||
b.write('@$name');
|
b.write(s);
|
||||||
}
|
}
|
||||||
return b.toString();
|
return b.toString();
|
||||||
}
|
}
|
||||||
|
@ -421,7 +434,7 @@ abstract class QueryWhere {
|
||||||
if (builder.hasValue) {
|
if (builder.hasValue) {
|
||||||
if (i++ > 0) b.write(' AND ');
|
if (i++ > 0) b.write(' AND ');
|
||||||
if (builder is DateTimeSqlExpressionBuilder ||
|
if (builder is DateTimeSqlExpressionBuilder ||
|
||||||
(builder is MapSqlExpressionBuilder && builder.hasRaw)) {
|
(builder is JsonSqlExpressionBuilder && builder.hasRaw)) {
|
||||||
if (tableName != null) b.write('$tableName.');
|
if (tableName != null) b.write('$tableName.');
|
||||||
b.write(builder.compile());
|
b.write(builder.compile());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel_orm
|
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.
|
description: Runtime support for Angel's ORM. Includes base classes for queries.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/orm
|
homepage: https://github.com/angel-dart/orm
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# 2.0.0-dev.4
|
||||||
|
* List generation support.
|
||||||
|
|
||||||
# 2.0.0-dev.3
|
# 2.0.0-dev.3
|
||||||
* Add JSON/JSONB support for Maps.
|
* Add JSON/JSONB support for Maps.
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,8 @@ ColumnType inferColumnType(DartType type) {
|
||||||
return ColumnType.timeStamp;
|
return ColumnType.timeStamp;
|
||||||
if (const TypeChecker.fromRuntime(Map).isAssignableFromType(type))
|
if (const TypeChecker.fromRuntime(Map).isAssignableFromType(type))
|
||||||
return ColumnType.jsonb;
|
return ColumnType.jsonb;
|
||||||
|
if (const TypeChecker.fromRuntime(List).isAssignableFromType(type))
|
||||||
|
return ColumnType.jsonb;
|
||||||
if (type is InterfaceType && type.element.isEnum) return ColumnType.int;
|
if (type is InterfaceType && type.element.isEnum) return ColumnType.int;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -515,6 +515,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
} else if (const TypeChecker.fromRuntime(Map)
|
} else if (const TypeChecker.fromRuntime(Map)
|
||||||
.isAssignableFromType(type)) {
|
.isAssignableFromType(type)) {
|
||||||
builderType = refer('MapSqlExpressionBuilder');
|
builderType = refer('MapSqlExpressionBuilder');
|
||||||
|
} else if (const TypeChecker.fromRuntime(List)
|
||||||
|
.isAssignableFromType(type)) {
|
||||||
|
builderType = refer('ListSqlExpressionBuilder');
|
||||||
} else if (ctx.relations.containsKey(field.name)) {
|
} else if (ctx.relations.containsKey(field.name)) {
|
||||||
var relation = ctx.relations[field.name];
|
var relation = ctx.relations[field.name];
|
||||||
if (relation.type != RelationshipType.belongsTo)
|
if (relation.type != RelationshipType.belongsTo)
|
||||||
|
@ -565,6 +568,30 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
..name = '${rc.pascalCase}QueryValues'
|
..name = '${rc.pascalCase}QueryValues'
|
||||||
..extend = refer('MapQueryValues');
|
..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
|
// Each field generates a getter for setter
|
||||||
for (var field in ctx.effectiveFields) {
|
for (var field in ctx.effectiveFields) {
|
||||||
var fType = field.type;
|
var fType = field.type;
|
||||||
|
@ -580,6 +607,11 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
var asInt = value.asA(refer('int'));
|
var asInt = value.asA(refer('int'));
|
||||||
var t = convertTypeReference(fType);
|
var t = convertTypeReference(fType);
|
||||||
value = t.property('values').index(asInt);
|
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 {
|
} else {
|
||||||
value = value.asA(type);
|
value = value.asA(type);
|
||||||
}
|
}
|
||||||
|
@ -596,6 +628,9 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
|
|
||||||
if (fType is InterfaceType && fType.element.isEnum) {
|
if (fType is InterfaceType && fType.element.isEnum) {
|
||||||
value = value.property('index');
|
value = value.property('index');
|
||||||
|
} else if (const TypeChecker.fromRuntime(List)
|
||||||
|
.isAssignableFromType(fType)) {
|
||||||
|
value = refer('json').property('encode').call([value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
b
|
b
|
||||||
|
@ -618,18 +653,13 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
|
||||||
..name = 'model'
|
..name = 'model'
|
||||||
..type = ctx.buildContext.modelClassType))
|
..type = ctx.buildContext.modelClassType))
|
||||||
..body = new Block((b) {
|
..body = new Block((b) {
|
||||||
var args = <String, Expression>{};
|
|
||||||
|
|
||||||
for (var field in ctx.effectiveFields) {
|
for (var field in ctx.effectiveFields) {
|
||||||
if (isSpecialId(ctx, field) || field is RelationFieldImpl)
|
if (isSpecialId(ctx, field) || field is RelationFieldImpl)
|
||||||
continue;
|
continue;
|
||||||
args[ctx.buildContext.resolveFieldName(field.name)] =
|
b.addExpression(refer(field.name)
|
||||||
refer('model').property(field.name);
|
.assign(refer('model').property(field.name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
b.addExpression(
|
|
||||||
refer('values').property('addAll').call([literalMap(args)]));
|
|
||||||
|
|
||||||
for (var field in ctx.effectiveFields) {
|
for (var field in ctx.effectiveFields) {
|
||||||
if (field is RelationFieldImpl) {
|
if (field is RelationFieldImpl) {
|
||||||
var original = field.originalFieldName;
|
var original = field.originalFieldName;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel_orm_generator
|
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.
|
description: Code generators for Angel's ORM. Generates query builder classes.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/orm
|
homepage: https://github.com/angel-dart/orm
|
||||||
|
|
|
@ -35,6 +35,7 @@ class PostgresExecutor extends QueryExecutor {
|
||||||
if (!Platform.environment.containsKey('STFU')) {
|
if (!Platform.environment.containsKey('STFU')) {
|
||||||
print('Running: $query');
|
print('Running: $query');
|
||||||
if (substitutionValues.isNotEmpty) print('Values: $substitutionValues');
|
if (substitutionValues.isNotEmpty) print('Values: $substitutionValues');
|
||||||
|
print(substitutionValues.map((k, v) => MapEntry(k, v.runtimeType)));
|
||||||
}
|
}
|
||||||
return connection.query(query, substitutionValues: substitutionValues);
|
return connection.query(query, substitutionValues: substitutionValues);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,20 @@ main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insert', () async {
|
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);
|
var model = await query.insert(executor);
|
||||||
print(model.toJson());
|
print(model.toJson());
|
||||||
expect(model, HasMap(value: {'foo': 'bar'}));
|
expect(model, HasMap(value: {'foo': 'bar'}, list: ['1', 2, 3.0]));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('insert', () async {
|
test('update', () 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);
|
var model = await query.insert(executor);
|
||||||
print(model.toJson());
|
print(model.toJson());
|
||||||
|
|
||||||
|
@ -29,7 +35,10 @@ main() {
|
||||||
HasMap initialValue;
|
HasMap initialValue;
|
||||||
|
|
||||||
setUp(() async {
|
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);
|
initialValue = await query.insert(executor);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -42,15 +51,35 @@ main() {
|
||||||
var query = HasMapQuery();
|
var query = HasMapQuery();
|
||||||
query.where.value.equals({'foo': 'bar'});
|
query.where.value.equals({'foo': 'bar'});
|
||||||
expect(await query.get(executor), [initialValue]);
|
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();
|
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]);
|
expect(await query.get(executor), [initialValue]);
|
||||||
|
|
||||||
query = HasMapQuery();
|
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), []);
|
expect(await query.get(executor), []);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
CREATE TEMPORARY TABLE "has_maps" (
|
CREATE TEMPORARY TABLE "has_maps" (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
value jsonb not null,
|
value jsonb not null,
|
||||||
|
list jsonb not null,
|
||||||
created_at timestamp,
|
created_at timestamp,
|
||||||
updated_at timestamp
|
updated_at timestamp
|
||||||
);
|
);
|
|
@ -95,6 +95,11 @@ class AuthorQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AuthorQueryValues extends MapQueryValues {
|
class AuthorQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -116,11 +121,9 @@ class AuthorQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Author model) {
|
void copyFrom(Author model) {
|
||||||
values.addAll({
|
name = model.name;
|
||||||
'name': model.name,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,11 @@ class BookQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class BookQueryValues extends MapQueryValues {
|
class BookQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -154,11 +159,9 @@ class BookQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Book model) {
|
void copyFrom(Book model) {
|
||||||
values.addAll({
|
name = model.name;
|
||||||
'name': model.name,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
if (model.author != null) {
|
if (model.author != null) {
|
||||||
values['author_id'] = int.parse(model.author.id);
|
values['author_id'] = int.parse(model.author.id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,11 @@ class CarQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CarQueryValues extends MapQueryValues {
|
class CarQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -163,14 +168,12 @@ class CarQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Car model) {
|
void copyFrom(Car model) {
|
||||||
values.addAll({
|
make = model.make;
|
||||||
'make': model.make,
|
description = model.description;
|
||||||
'description': model.description,
|
familyFriendly = model.familyFriendly;
|
||||||
'family_friendly': model.familyFriendly,
|
recalledAt = model.recalledAt;
|
||||||
'recalled_at': model.recalledAt,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,11 @@ class CustomerQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomerQueryValues extends MapQueryValues {
|
class CustomerQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -106,8 +111,8 @@ class CustomerQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Customer model) {
|
void copyFrom(Customer model) {
|
||||||
values
|
createdAt = model.createdAt;
|
||||||
.addAll({'created_at': model.createdAt, 'updated_at': model.updatedAt});
|
updatedAt = model.updatedAt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,11 @@ class FootQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FootQueryValues extends MapQueryValues {
|
class FootQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -126,12 +131,10 @@ class FootQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Foot model) {
|
void copyFrom(Foot model) {
|
||||||
values.addAll({
|
legId = model.legId;
|
||||||
'leg_id': model.legId,
|
nToes = model.nToes;
|
||||||
'n_toes': model.nToes,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,11 @@ class FruitQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FruitQueryValues extends MapQueryValues {
|
class FruitQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -126,12 +131,10 @@ class FruitQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Fruit model) {
|
void copyFrom(Fruit model) {
|
||||||
values.addAll({
|
treeId = model.treeId;
|
||||||
'tree_id': model.treeId,
|
commonName = model.commonName;
|
||||||
'common_name': model.commonName,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,11 @@ class HasCarQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class HasCarQueryValues extends MapQueryValues {
|
class HasCarQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -117,11 +122,9 @@ class HasCarQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(HasCar model) {
|
void copyFrom(HasCar model) {
|
||||||
values.addAll({
|
type = model.type;
|
||||||
'type': model.type,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,4 +10,6 @@ part 'has_map.g.dart';
|
||||||
@serializable
|
@serializable
|
||||||
abstract class _HasMap {
|
abstract class _HasMap {
|
||||||
Map get value;
|
Map get value;
|
||||||
|
|
||||||
|
List get list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ class HasMapMigration extends Migration {
|
||||||
up(Schema schema) {
|
up(Schema schema) {
|
||||||
schema.create('has_maps', (table) {
|
schema.create('has_maps', (table) {
|
||||||
table.declare('value', new ColumnType('jsonb'));
|
table.declare('value', new ColumnType('jsonb'));
|
||||||
|
table.declare('list', new ColumnType('jsonb'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
get fields {
|
get fields {
|
||||||
return const ['value'];
|
return const ['value', 'list'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -56,7 +57,9 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
|
||||||
|
|
||||||
static HasMap parseRow(List row) {
|
static HasMap parseRow(List row) {
|
||||||
if (row.every((x) => x == null)) return null;
|
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;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,24 +71,38 @@ class HasMapQuery extends Query<HasMap, HasMapQueryWhere> {
|
||||||
|
|
||||||
class HasMapQueryWhere extends QueryWhere {
|
class HasMapQueryWhere extends QueryWhere {
|
||||||
HasMapQueryWhere(HasMapQuery query)
|
HasMapQueryWhere(HasMapQuery query)
|
||||||
: value = new MapSqlExpressionBuilder(query, 'value');
|
: value = new MapSqlExpressionBuilder(query, 'value'),
|
||||||
|
list = new ListSqlExpressionBuilder(query, 'list');
|
||||||
|
|
||||||
final MapSqlExpressionBuilder value;
|
final MapSqlExpressionBuilder value;
|
||||||
|
|
||||||
|
final ListSqlExpressionBuilder list;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
get expressionBuilders {
|
get expressionBuilders {
|
||||||
return [value];
|
return [value, list];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HasMapQueryValues extends MapQueryValues {
|
class HasMapQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {'list': 'jsonb'};
|
||||||
|
}
|
||||||
|
|
||||||
Map<dynamic, dynamic> get value {
|
Map<dynamic, dynamic> get value {
|
||||||
return (values['value'] as Map<dynamic, dynamic>);
|
return (values['value'] as Map<dynamic, dynamic>);
|
||||||
}
|
}
|
||||||
|
|
||||||
set value(Map<dynamic, dynamic> value) => values['value'] = value;
|
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) {
|
void copyFrom(HasMap model) {
|
||||||
values.addAll({'value': model.value});
|
value = model.value;
|
||||||
|
list = model.list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,25 +112,30 @@ class HasMapQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
@generatedSerializable
|
@generatedSerializable
|
||||||
class HasMap implements _HasMap {
|
class HasMap implements _HasMap {
|
||||||
const HasMap({Map<dynamic, dynamic> this.value});
|
const HasMap({Map<dynamic, dynamic> this.value, List<dynamic> this.list});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final Map<dynamic, dynamic> value;
|
final Map<dynamic, dynamic> value;
|
||||||
|
|
||||||
HasMap copyWith({Map<dynamic, dynamic> value}) {
|
@override
|
||||||
return new HasMap(value: value ?? this.value);
|
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) {
|
bool operator ==(other) {
|
||||||
return other is _HasMap &&
|
return other is _HasMap &&
|
||||||
const MapEquality<dynamic, dynamic>(
|
const MapEquality<dynamic, dynamic>(
|
||||||
keys: const DefaultEquality(), values: const DefaultEquality())
|
keys: const DefaultEquality(), values: const DefaultEquality())
|
||||||
.equals(other.value, value);
|
.equals(other.value, value) &&
|
||||||
|
const ListEquality<dynamic>(const DefaultEquality())
|
||||||
|
.equals(other.list, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return hashObjects([value]);
|
return hashObjects([value, list]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
|
@ -130,6 +152,9 @@ abstract class HasMapSerializer {
|
||||||
return new HasMap(
|
return new HasMap(
|
||||||
value: map['value'] is Map
|
value: map['value'] is Map
|
||||||
? (map['value'] as Map).cast<dynamic, dynamic>()
|
? (map['value'] as Map).cast<dynamic, dynamic>()
|
||||||
|
: null,
|
||||||
|
list: map['list'] is Iterable
|
||||||
|
? (map['list'] as Iterable).cast<dynamic>().toList()
|
||||||
: null);
|
: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,12 +162,14 @@ abstract class HasMapSerializer {
|
||||||
if (model == null) {
|
if (model == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return {'value': model.value};
|
return {'value': model.value, 'list': model.list};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class HasMapFields {
|
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 value = 'value';
|
||||||
|
|
||||||
|
static const String list = 'list';
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,11 @@ class LegQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class LegQueryValues extends MapQueryValues {
|
class LegQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -125,11 +130,9 @@ class LegQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Leg model) {
|
void copyFrom(Leg model) {
|
||||||
values.addAll({
|
name = model.name;
|
||||||
'name': model.name,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,11 @@ class OrderQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class OrderQueryValues extends MapQueryValues {
|
class OrderQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -167,13 +172,11 @@ class OrderQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Order model) {
|
void copyFrom(Order model) {
|
||||||
values.addAll({
|
employeeId = model.employeeId;
|
||||||
'employee_id': model.employeeId,
|
orderDate = model.orderDate;
|
||||||
'order_date': model.orderDate,
|
shipperId = model.shipperId;
|
||||||
'shipper_id': model.shipperId,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
if (model.customer != null) {
|
if (model.customer != null) {
|
||||||
values['customer_id'] = int.parse(model.customer.id);
|
values['customer_id'] = int.parse(model.customer.id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,11 @@ class TreeQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TreeQueryValues extends MapQueryValues {
|
class TreeQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -186,11 +191,9 @@ class TreeQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Tree model) {
|
void copyFrom(Tree model) {
|
||||||
values.addAll({
|
rings = model.rings;
|
||||||
'rings': model.rings,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,6 +147,11 @@ class UserQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserQueryValues extends MapQueryValues {
|
class UserQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -178,13 +183,11 @@ class UserQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(User model) {
|
void copyFrom(User model) {
|
||||||
values.addAll({
|
username = model.username;
|
||||||
'username': model.username,
|
password = model.password;
|
||||||
'password': model.password,
|
email = model.email;
|
||||||
'email': model.email,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,6 +276,11 @@ class RoleUserQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoleUserQueryValues extends MapQueryValues {
|
class RoleUserQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -299,8 +307,8 @@ class RoleUserQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(RoleUser model) {
|
void copyFrom(RoleUser model) {
|
||||||
values
|
createdAt = model.createdAt;
|
||||||
.addAll({'created_at': model.createdAt, 'updated_at': model.updatedAt});
|
updatedAt = model.updatedAt;
|
||||||
if (model.role != null) {
|
if (model.role != null) {
|
||||||
values['role_id'] = int.parse(model.role.id);
|
values['role_id'] = int.parse(model.role.id);
|
||||||
}
|
}
|
||||||
|
@ -378,6 +386,11 @@ class RoleQueryWhere extends QueryWhere {
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoleQueryValues extends MapQueryValues {
|
class RoleQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
int get id {
|
int get id {
|
||||||
return (values['id'] as int);
|
return (values['id'] as int);
|
||||||
}
|
}
|
||||||
|
@ -399,11 +412,9 @@ class RoleQueryValues extends MapQueryValues {
|
||||||
|
|
||||||
set updatedAt(DateTime value) => values['updated_at'] = value;
|
set updatedAt(DateTime value) => values['updated_at'] = value;
|
||||||
void copyFrom(Role model) {
|
void copyFrom(Role model) {
|
||||||
values.addAll({
|
name = model.name;
|
||||||
'name': model.name,
|
createdAt = model.createdAt;
|
||||||
'created_at': model.createdAt,
|
updatedAt = model.updatedAt;
|
||||||
'updated_at': model.updatedAt
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue