Merge pull request #65 from dukefirehawk/fix-bug/mysql-query

Fix bug/mysql query
This commit is contained in:
Thomas Hii 2022-05-16 13:09:36 +08:00 committed by GitHub
commit f4ba4fb25c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 322 additions and 276 deletions

View file

@ -1,5 +1,9 @@
# Change Log
## 6.0.1
* Added `mapToDateTime`
## 6.0.0
* Updated to SDK 2.16.x

View file

@ -19,3 +19,27 @@ String mapToText(dynamic value) {
}
return value;
}
DateTime? mapToDateTime(dynamic value) {
if (value == null) {
return value;
}
if (value is String) {
return DateTime.tryParse(value);
}
return value;
}
double mapToDouble(dynamic value) {
if (value == null) {
return 0.0;
}
if (value is String) {
return double.tryParse(value) ?? 0.0;
}
if (value is! double) {
return 0.0;
}
return value;
}

View file

@ -1,5 +1,5 @@
name: angel3_orm
version: 6.0.0
version: 6.0.1
description: Runtime support for Angel3 ORM. Includes base classes for queries.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm

View file

@ -1,5 +1,10 @@
# Change Log
## 6.0.1
* Fixed timestamp or date field to DateTime mapping
* Fixed double or float field to double mapping
## 6.0.0
* Updated to SDK 2.16.x

View file

@ -93,14 +93,12 @@ class EmployeeQuery extends Query<Employee, EmployeeQueryWhere> {
}
var model = Employee(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
uniqueId: fields.contains('unique_id') ? (row[3] as String?) : null,
firstName: fields.contains('first_name') ? (row[4] as String?) : null,
lastName: fields.contains('last_name') ? (row[5] as String?) : null,
salary: fields.contains('salary')
? double.tryParse(row[6].toString())
: null);
salary: fields.contains('salary') ? mapToDouble(row[6]) : null);
return Optional.of(model);
}

View file

@ -262,9 +262,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
.property('decode')
.call([expr.asA(refer('String'))]).asA(type);
} else if (floatTypes.contains(ctx.columns[field.name]?.type)) {
expr = refer('double')
.property('tryParse')
.call([expr.property('toString').call([])]);
//expr = refer('double')
// .property('tryParse')
// .call([expr.property('toString').call([])]);
expr = refer('mapToDouble').call([expr]);
} else if (fType is InterfaceType && fType.element.isEnum) {
var isNull = expr.equalTo(literalNull);
expr = isNull.conditional(literalNull,
@ -272,6 +273,10 @@ class OrmGenerator extends GeneratorForAnnotation<Orm> {
} else if (fType.isDartCoreBool) {
// Generated Code: mapToBool(row[i])
expr = refer('mapToBool').call([expr]);
} else if (fType.element?.displayName == 'DateTime') {
//print("fType: ${fType.element?.displayName}");
// Generated Code: mapToDateTime(row[i])
expr = refer('mapToDateTime').call([expr]);
} else {
// Generated Code: (row[i] as type?)
expr = expr.asA(type);

View file

@ -1,5 +1,5 @@
name: angel3_orm_generator
version: 6.0.0
version: 6.0.1
description: Code generators for Angel3 ORM. Generates query builder classes.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_generator
@ -30,7 +30,7 @@ dev_dependencies:
postgres: ^2.4.0
test: ^1.21.0
lints: ^1.0.0
# dependency_overrides:
dependency_overrides:
# angel3_container:
# path: ../../container/angel_container
# angel3_framework:
@ -47,8 +47,8 @@ dev_dependencies:
# path: ../../serialize/angel_serialize
# angel3_serialize_generator:
# path: ../../serialize/angel_serialize_generator
# angel3_orm:
# path: ../angel_orm
angel3_orm:
path: ../angel_orm
# angel3_migration:
# path: ../angel_migration

View file

@ -1,5 +1,12 @@
# Change Log
## 6.0.0-beta.3
* Fixed transaction for `MariaDbExecutor`
* Fixed transaction for `MySqlExecutor`
* Fixed error for non `id` primary key
* Changed test cases to use tables instead of temporary tables to overcome limitations
## 6.0.0-beta.2
* Updated README

View file

@ -7,7 +7,7 @@
This package contains the SQL Executor required by Angel3 ORM to work with MySQL and MariaDB respectively. In order to better support the differences in MySQL and MariaDb underlying protocols, two different drives have to be used. For MariaDb 10.2.x, `mysql1` driver provides the best results, while `mysql_client` driver handles MySQL 8.x.x without issues.
* MariaDbExecutor (stable)
* MariaDbExecutor (beta)
* MySqlExecutor (beta)
## Supported database version
@ -51,3 +51,9 @@ This package contains the SQL Executor required by Angel3 ORM to work with MySQL
await connection.connect(timeoutMs: 10000);
var executor = MySqlExecutor(connection, logger: logger);
```
## Known limitation
* UTC time is not supported
* Blob is not supported

View file

@ -81,8 +81,8 @@ class TodoQuery extends Query<Todo, TodoQueryWhere> {
}
var model = Todo(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
isComplete: fields.contains('is_complete') ? mapToBool(row[3]) : null,
text: fields.contains('text') ? (row[4] as String?) : null);
return Optional.of(model);

View file

@ -4,12 +4,14 @@ import 'package:logging/logging.dart';
import 'package:mysql1/mysql1.dart';
class MariaDbExecutor extends QueryExecutor {
/// An optional [Logger] to write to.
final Logger? logger;
/// An optional [Logger] print information to. A default logger will be used if not set
late Logger logger;
final MySqlConnection _connection;
MariaDbExecutor(this._connection, {this.logger});
MariaDbExecutor(this._connection, {Logger? logger}) {
this.logger = logger ?? Logger('MariaDbExecutor');
}
final Dialect _dialect = const MySQLDialect();
@ -18,66 +20,8 @@ class MariaDbExecutor extends QueryExecutor {
Future<void> close() {
return _connection.close();
/*
if (_connection is MySqlConnection) {
return (_connection as MySqlConnection).close();
} else {
return Future.value();
}
*/
}
/*
Future<Transaction> _startTransaction() {
if (_connection is Transaction) {
return Future.value(_connection as Transaction?);
} else if (_connection is MySqlConnection) {
return (_connection as MySqlConnection).begin();
} else {
throw StateError('Connection must be transaction or connection');
}
}
@override
Future<List<List>> query(
String tableName, String query, Map<String, dynamic> substitutionValues,
[List<String> returningFields = const []]) {
// Change @id -> ?
for (var name in substitutionValues.keys) {
query = query.replaceAll('@$name', '?');
}
logger?.fine('Query: $query');
logger?.fine('Values: $substitutionValues');
if (returningFields.isNotEmpty != true) {
return _connection!
.prepared(query, substitutionValues.values)
.then((results) => results.map((r) => r.toList()).toList());
} else {
return Future(() async {
var tx = await _startTransaction();
try {
var writeResults =
await tx.prepared(query, substitutionValues.values);
var fieldSet = returningFields.map((s) => '`$s`').join(',');
var fetchSql = 'select $fieldSet from $tableName where id = ?;';
logger?.fine(fetchSql);
var readResults =
await tx.prepared(fetchSql, [writeResults.insertId]);
var mapped = readResults.map((r) => r.toList()).toList();
await tx.commit();
return mapped;
} catch (_) {
await tx.rollback();
rethrow;
}
});
}
}
*/
@override
Future<List<List>> query(
String tableName, String query, Map<String, dynamic> substitutionValues,
@ -101,9 +45,8 @@ class MariaDbExecutor extends QueryExecutor {
var result = await _connection.query(query, params);
query = returningQuery;
//logger?.warning('Result.insertId: ${result.insertId}');
// logger?.warning('Result.insertId: ${result.insertId}');
// Has primary key
//if (result.insertId != 0) {
if (returningQuery.endsWith('.id=?')) {
params = [result.insertId];
}
@ -122,35 +65,20 @@ class MariaDbExecutor extends QueryExecutor {
@override
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
return f(this);
/*
if (_connection is! MySqlConnection) {
return await f(this);
}
await _connection.transaction((context) async {
var executor = MySqlExecutor(context, logger: logger);
T? returnValue = await _connection.transaction((ctx) async {
var conn = ctx as MySqlConnection;
try {
logger.fine('Entering transaction');
var tx = MariaDbExecutor(conn, logger: logger);
return await f(tx);
} catch (e) {
logger.severe('Failed to run transaction', e);
rethrow;
} finally {
logger.fine('Exiting transaction');
}
});
*/
}
/*
@override
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
if (_connection is Transaction) {
return await f(this);
}
Transaction? tx;
try {
tx = await _startTransaction();
var executor = MySqlExecutor(tx, logger: logger);
var result = await f(executor);
await tx.commit();
return result;
} catch (_) {
await tx?.rollback();
rethrow;
}
return returnValue!;
}
*/
}

View file

@ -4,12 +4,14 @@ import 'package:logging/logging.dart';
import 'package:mysql_client/mysql_client.dart';
class MySqlExecutor extends QueryExecutor {
/// An optional [Logger] to write to.
final Logger? logger;
/// An optional [Logger] to write to. A default logger will be used if not set
late Logger logger;
final MySQLConnection _connection;
MySqlExecutor(this._connection, {this.logger});
MySqlExecutor(this._connection, {Logger? logger}) {
this.logger = logger ?? Logger('MySqlExecutor');
}
final Dialect _dialect = const MySQLDialect();
@ -18,15 +20,10 @@ class MySqlExecutor extends QueryExecutor {
Future<void> close() {
return _connection.close();
/*
if (_connection is MySqlConnection) {
return (_connection as MySqlConnection).close();
} else {
return Future.value();
}
*/
}
MySQLConnection get rawConnection => _connection;
/*
Future<Transaction> _startTransaction() {
if (_connection is Transaction) {
@ -86,13 +83,23 @@ class MySqlExecutor extends QueryExecutor {
// Change @id -> ?
for (var name in substitutionValues.keys) {
query = query.replaceAll('@$name', ':$name');
// Convert UTC time to local time
var value = substitutionValues[name];
if (value is DateTime && value.isUtc) {
var t = value.toLocal();
logger.warning('Datetime deteted: $name');
logger.warning('Datetime: UTC -> $value, Local -> $t');
substitutionValues[name] = t;
}
}
//var params = substitutionValues.values.toList();
var params = [];
//var params = [];
logger?.warning('Query: $query');
logger?.warning('Values: $substitutionValues');
logger.warning('Query: $query');
logger.warning('Values: $substitutionValues');
//logger?.warning('Returning Query: $returningQuery');
if (returningQuery.isNotEmpty) {
@ -101,53 +108,64 @@ class MySqlExecutor extends QueryExecutor {
if (query.startsWith("INSERT")) {
var result = await _connection.execute(query, substitutionValues);
logger?.warning(result.lastInsertID);
logger.warning(result.lastInsertID);
query = returningQuery;
//logger?.warning('Result.insertId: ${result.insertId}');
// Has primary key
//if (result.insertId != 0) {
if (returningQuery.endsWith('.id=?')) {
query = query.replaceAll("?", ":id");
//params = [result.lastInsertID];
substitutionValues.clear();
substitutionValues['id'] = result.lastInsertID;
} else {
query = _convertSQL(query, substitutionValues);
}
} else if (query.startsWith("UPDATE")) {
await _connection.execute(query, substitutionValues);
query = returningQuery;
params = [];
}
}
logger?.warning('Query 2: $query');
logger?.warning('Values 2: $substitutionValues');
logger.warning('Query 2: $query');
logger.warning('Values 2: $substitutionValues');
// Handle select
return _connection.execute(query, substitutionValues).then((results) {
logger?.warning("SELECT");
//for (var element in results.cols) {
// print(
// '${element.name} ${element.type.toString()} ${element.runtimeType.toString()}');
//}
logger.warning("SELECT");
return results.rows.map((r) => r.typedAssoc().values.toList()).toList();
});
}
@override
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
logger?.warning("Transaction");
return f(this);
/*
if (_connection is! MySqlConnection) {
return await f(this);
String _convertSQL(String query, Map<String, dynamic> substitutionValues) {
var newQuery = query;
for (var k in substitutionValues.keys) {
var fromPattern = '.$k = ?';
var toPattern = '.$k = :$k';
newQuery = newQuery.replaceFirst(fromPattern, toPattern);
}
await _connection.transaction((context) async {
var executor = MySqlExecutor(context, logger: logger);
return newQuery;
}
@override
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
logger.warning("Transaction");
T? returnValue = await _connection.transactional((ctx) async {
try {
logger.fine('Entering transaction');
var tx = MySqlExecutor(ctx, logger: logger);
return await f(tx);
} catch (e) {
logger.severe('Failed to run transaction', e);
rethrow;
} finally {
logger.fine('Exiting transaction');
}
});
*/
return returnValue!;
}
/*
@override

View file

@ -1,5 +1,5 @@
name: angel3_orm_mysql
version: 6.0.0-beta.2
version: 6.0.0-beta.3
description: MySQL support for Angel3 ORM. Includes functionality for querying and transactions.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_mysql
@ -9,7 +9,7 @@ dependencies:
angel3_orm: ^6.0.0
logging: ^1.0.0
mysql1: ^0.19.0
mysql_client: ^0.0.11
mysql_client: ^0.0.15
optional: ^6.0.0
dev_dependencies:
angel3_orm_generator: ^6.0.0
@ -17,18 +17,18 @@ dev_dependencies:
build_runner: ^2.0.1
test: ^1.21.0
lints: ^1.0.0
# dependency_overrides:
dependency_overrides:
# angel3_serialize:
# path: ../../serialize/angel_serialize
# angel3_serialize_generator:
# path: ../../serialize/angel_serialize_generator
# angel3_model:
# path: ../../model
# angel3_orm_test:
# path: ../angel_orm_test
# angel3_orm:
# path: ../angel_orm
# angel3_migration:
# path: ../angel_migration
# angel3_orm_generator:
# path: ../angel_orm_generator
angel3_orm_test:
path: ../angel_orm_test
angel3_orm:
path: ../angel_orm
angel3_orm_generator:
path: ../angel_orm_generator
# angel3_migration:
# path: ../angel_migration

View file

@ -11,23 +11,28 @@ void main() {
});
group('mysql', () {
group('belongsTo',
() => belongsToTests(my(['author', 'book']), close: closeMy));
group(
'belongsTo',
() => belongsToTests(createTables(['author', 'book']),
close: dropTables));
group(
'edgeCase',
() => edgeCaseTests(my(['unorthodox', 'weird_join', 'song', 'numba']),
close: closeMy));
() => edgeCaseTests(
createTables(['unorthodox', 'weird_join', 'song', 'numba']),
close: dropTables));
group('enumAndNested',
() => enumAndNestedTests(my(['has_car']), close: closeMy));
group('hasMany', () => hasManyTests(my(['tree', 'fruit']), close: closeMy));
() => enumAndNestedTests(createTables(['has_car']), close: dropTables));
group('hasMany',
() => hasManyTests(createTables(['tree', 'fruit']), close: dropTables));
// NOTE: MySQL/MariaDB do not support jsonb data type
//group('hasMap', () => hasMapTests(my(['has_map']), close: closeMy));
//group('hasMap', () => hasMapTests(createTables(['has_maps']), close: dropTables));
// NOTE: mysql1 driver do not support CAST();
//group('hasOne', () => hasOneTests(my(['leg', 'foot']), close: closeMy));
//group('hasOne', () => hasOneTests(createTables(['legs', 'feet']), close: dropTables));
group(
'manyToMany',
() =>
manyToManyTests(my(['user', 'role', 'user_role']), close: closeMy));
group('standalone', () => standaloneTests(my(['car']), close: closeMy));
() => manyToManyTests(createTables(['user', 'role', 'user_role']),
close: dropTables));
group('standalone',
() => standaloneTests(createTables(['car']), close: dropTables));
});
}

View file

@ -6,15 +6,47 @@ import 'package:logging/logging.dart';
import 'package:mysql1/mysql1.dart';
import 'package:mysql_client/mysql_client.dart';
FutureOr<QueryExecutor> Function() my(Iterable<String> schemas) {
return () => connectToMySql(schemas);
List tmpTables = [];
FutureOr<QueryExecutor> Function() createTables(List<String> schemas) {
// For MySQL
return () => _connectToMySql(schemas);
// For MariaDB
// return () => _connectToMariaDb(tables);
}
Future<void> closeMy(QueryExecutor executor) =>
(executor as MySqlExecutor).close();
// For MySQL
Future<void> dropTables(QueryExecutor executor) async {
var sqlExecutor = (executor as MySqlExecutor);
for (var tableName in tmpTables.reversed) {
await sqlExecutor.rawConnection.execute('drop table $tableName;');
}
return sqlExecutor.close();
}
// Executor for MariaDB 10.2.x
Future<MariaDbExecutor> connectToMariaDb(Iterable<String> schemas) async {
// For MariaDB
/* Future<void> dropTables(QueryExecutor executor) {
var sqlExecutor = (executor as MariaDbExecutor);
for (var tableName in tmpTables.reversed) {
sqlExecutor.query(tableName, 'DROP TABLE $tableName', {});
}
return sqlExecutor.close();
} */
String extractTableName(String createQuery) {
var start = createQuery.indexOf('EXISTS');
var end = createQuery.indexOf('(');
if (start == -1 || end == -1) {
return '';
}
return createQuery.substring(start + 6, end).trim();
}
// Executor for MariaDB
Future<MariaDbExecutor> _connectToMariaDb(List<String> schemas) async {
var settings = ConnectionSettings(
host: 'localhost',
port: 3306,
@ -23,7 +55,9 @@ Future<MariaDbExecutor> connectToMariaDb(Iterable<String> schemas) async {
password: 'Test123*');
var connection = await MySqlConnection.connect(settings);
var logger = Logger('orm_mysql');
var logger = Logger('orm_mariadb');
tmpTables.clear();
for (var s in schemas) {
// MySQL driver does not support multiple sql queries
@ -34,6 +68,11 @@ Future<MariaDbExecutor> connectToMariaDb(Iterable<String> schemas) async {
if (q.trim().isNotEmpty) {
//await connection.execute(q);
await connection.query(q);
var tableName = extractTableName(q);
if (tableName != '') {
tmpTables.add(tableName);
}
}
}
}
@ -41,20 +80,22 @@ Future<MariaDbExecutor> connectToMariaDb(Iterable<String> schemas) async {
return MariaDbExecutor(connection, logger: logger);
}
// Executor for MySQL 8.x.x
Future<MySqlExecutor> connectToMySql(Iterable<String> schemas) async {
// Executor for MySQL
Future<MySqlExecutor> _connectToMySql(List<String> schemas) async {
var connection = await MySQLConnection.createConnection(
databaseName: 'orm_test',
port: 3306,
host: "localhost",
userName: Platform.environment['MYSQL_USERNAME'] ?? 'test',
password: Platform.environment['MYSQL_PASSWORD'] ?? 'Test123*',
);
databaseName: 'orm_test',
port: 3306,
host: "localhost",
userName: Platform.environment['MYSQL_USERNAME'] ?? 'test',
password: Platform.environment['MYSQL_PASSWORD'] ?? 'Test123*',
secure: false);
await connection.connect();
await connection.connect(timeoutMs: 10000);
var logger = Logger('orm_mysql');
tmpTables.clear();
for (var s in schemas) {
// MySQL driver does not support multiple sql queries
var data = await File('test/migrations/$s.sql').readAsString();
@ -63,6 +104,11 @@ Future<MySqlExecutor> connectToMySql(Iterable<String> schemas) async {
//print("Table: [$q]");
if (q.trim().isNotEmpty) {
await connection.execute(q);
var tableName = extractTableName(q);
if (tableName != '') {
tmpTables.add(tableName);
}
}
}
}

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE authors (
CREATE TABLE IF NOT EXISTS authors (
id serial PRIMARY KEY,
name varchar(255) UNIQUE NOT NULL,
created_at timestamp,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE books (
CREATE TABLE IF NOT EXISTS books (
id serial PRIMARY KEY,
author_id int NOT NULL,
partner_author_id int,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE cars (
CREATE TABLE IF NOT EXISTS cars (
id serial PRIMARY KEY,
make varchar(255) NOT NULL,
description TEXT NOT NULL,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE feet (
CREATE TABLE IF NOT EXISTS feet (
id serial PRIMARY KEY,
leg_id int NOT NULL,
n_toes int NOT NULL,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE fruits (
CREATE TABLE IF NOT EXISTS fruits (
id serial,
tree_id int,
common_name varchar(255),

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE has_cars (
CREATE TABLE IF NOT EXISTS has_cars (
id serial PRIMARY KEY,
type int not null,
created_at timestamp,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE has_maps (
CREATE TABLE IF NOT EXISTS has_maps (
id serial PRIMARY KEY,
value jsonb not null,
list jsonb not null,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE legs (
CREATE TABLE IF NOT EXISTS legs (
id serial PRIMARY KEY,
name varchar(255) NOT NULL,
created_at timestamp,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE numbas (
CREATE TABLE IF NOT EXISTS numbas (
i int NOT NULL UNIQUE,
parent int,
created_at TIMESTAMP,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE roles (
CREATE TABLE IF NOT EXISTS roles (
id serial PRIMARY KEY,
name varchar(255),
created_at timestamp,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE songs (
CREATE TABLE IF NOT EXISTS songs (
id serial,
weird_join_id int,
title varchar(255),

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE trees (
CREATE TABLE IF NOT EXISTS trees (
id serial,
rings smallint UNIQUE,
created_at timestamp,

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE unorthodoxes (
CREATE TABLE IF NOT EXISTS unorthodoxes (
name varchar(255) NOT NULL UNIQUE,
PRIMARY KEY(name)
);

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE users (
CREATE TABLE IF NOT EXISTS users (
id serial PRIMARY KEY,
username varchar(255),
password varchar(255),

View file

@ -1,4 +1,4 @@
CREATE TEMPORARY TABLE role_users (
CREATE TABLE IF NOT EXISTS role_users (
id serial PRIMARY KEY,
user_id int NOT NULL,
role_id int NOT NULL,

View file

@ -1,15 +1,15 @@
CREATE TEMPORARY TABLE weird_joins (
CREATE TABLE IF NOT EXISTS weird_joins (
id serial,
join_name varchar(255),
PRIMARY KEY(id)
);
CREATE TEMPORARY TABLE foos (
CREATE TABLE IF NOT EXISTS foos (
bar varchar(255) not null UNIQUE,
PRIMARY KEY(bar)
);
CREATE TEMPORARY TABLE foo_pivots (
CREATE TABLE IF NOT EXISTS foo_pivots (
weird_join_id int,
foo_bar varchar(255)
);

View file

@ -14,7 +14,7 @@ void main() async {
// if (rec.stackTrace != null) print(rec.stackTrace);
//});
belongsToTests(my(['author', 'book']), close: closeMy);
belongsToTests(createTables(['author', 'book']), close: dropTables);
//hasOneTests(my(['leg', 'foot']), close: closeMy);
//standaloneTests(my(['car']), close: closeMy);

View file

@ -9,7 +9,8 @@ import 'package:postgres/postgres.dart';
class PostgreSqlExecutor extends QueryExecutor {
final PostgreSQLExecutionContext _connection;
/// An optional [Logger] to print information to.
/// An optional [Logger] to print information to. A default logger will be used
/// if not set
late Logger logger;
PostgreSqlExecutor(this._connection, {Logger? logger}) {

View file

@ -16,14 +16,14 @@ dev_dependencies:
angel3_orm_test: ^6.0.0
test: ^1.21.0
lints: ^1.0.0
# dependency_overrides:
dependency_overrides:
# angel3_serialize:
# path: ../../serialize/angel_serialize
# angel3_model:
# path: ../../model
# angel3_orm_test:
# path: ../angel_orm_test
# angel3_orm:
# path: ../angel_orm
angel3_orm_test:
path: ../angel_orm_test
angel3_orm:
path: ../angel_orm
# angel3_migration:
# path: ../angel_migration

View file

@ -1,5 +1,9 @@
# Change Log
## 6.0.1
* Updated generated test cases
## 6.0.0
* Updated to SDK 2.16.x

View file

@ -61,7 +61,8 @@ void manyToManyTests(FutureOr<QueryExecutor> Function() createExecutor,
..username = 'thosakwe'
..password = 'Hahahahayoureallythoughtiwasstupidenoughtotypethishere'
..email = 'thosakwe AT gmail.com';
thosakwe = (await thosakweQuery.insert(executor)).value;
var result = await thosakweQuery.insert(executor);
thosakwe = result.value;
print('=== THOSAKWE: ${thosakwe?.toJson()}');
// Allow thosakwe to publish...

View file

@ -122,8 +122,8 @@ class BookQuery extends Query<Book, BookQueryWhere> {
}
var model = Book(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
name: fields.contains('name') ? (row[5] as String?) : null);
if (row.length > 6) {
var modelOpt = AuthorQuery().parseRow(row.skip(6).take(4).toList());
@ -285,8 +285,8 @@ class AuthorQuery extends Query<Author, AuthorQueryWhere> {
}
var model = Author(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
name: fields.contains('name') ? (row[3] as String?) : null);
return Optional.of(model);
}

View file

@ -91,15 +91,15 @@ class CarQuery extends Query<Car, CarQueryWhere> {
}
var model = Car(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
make: fields.contains('make') ? (row[3] as String?) : null,
description:
fields.contains('description') ? (row[4] as String?) : null,
familyFriendly:
fields.contains('family_friendly') ? mapToBool(row[5]) : null,
recalledAt:
fields.contains('recalled_at') ? (row[6] as DateTime?) : null);
fields.contains('recalled_at') ? mapToDateTime(row[6]) : null);
return Optional.of(model);
}

View file

@ -101,8 +101,8 @@ class NumbersQuery extends Query<Numbers, NumbersQueryWhere> {
}
var model = Numbers(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
two: fields.contains('two') ? (row[3] as int?) : null);
return Optional.of(model);
}
@ -218,8 +218,8 @@ class AlphabetQuery extends Query<Alphabet, AlphabetQueryWhere> {
}
var model = Alphabet(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
value: fields.contains('value') ? (row[3] as String?) : null);
if (row.length > 5) {
var modelOpt = NumbersQuery().parseRow(row.skip(5).take(4).toList());

View file

@ -81,8 +81,8 @@ class HasCarQuery extends Query<HasCar, HasCarQueryWhere> {
}
var model = HasCar(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
type: fields.contains('type')
? row[3] == null
? null

View file

@ -111,8 +111,8 @@ class LegQuery extends Query<Leg, LegQueryWhere> {
}
var model = Leg(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
name: fields.contains('name') ? (row[3] as String?) : null);
if (row.length > 4) {
var modelOpt = FootQuery().parseRow(row.skip(4).take(5).toList());
@ -240,12 +240,10 @@ class FootQuery extends Query<Foot, FootQueryWhere> {
}
var model = Foot(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
legId: fields.contains('leg_id') ? (row[3] as int?) : null,
nToes: fields.contains('n_toes')
? double.tryParse(row[4].toString())
: null);
nToes: fields.contains('n_toes') ? mapToDouble(row[4]) : null);
return Optional.of(model);
}

View file

@ -115,10 +115,10 @@ class OrderQuery extends Query<Order, OrderQueryWhere> {
}
var model = Order(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
employeeId: fields.contains('employee_id') ? (row[4] as int?) : null,
orderDate: fields.contains('order_date') ? (row[5] as DateTime?) : null,
orderDate: fields.contains('order_date') ? mapToDateTime(row[5]) : null,
shipperId: fields.contains('shipper_id') ? (row[6] as int?) : null);
if (row.length > 7) {
var modelOpt = CustomerQuery().parseRow(row.skip(7).take(3).toList());
@ -284,9 +284,9 @@ class CustomerQuery extends Query<Customer, CustomerQueryWhere> {
}
var model = Customer(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt:
fields.contains('updated_at') ? (row[2] as DateTime?) : null);
fields.contains('updated_at') ? mapToDateTime(row[2]) : null);
return Optional.of(model);
}

View file

@ -82,8 +82,8 @@ class PersonQuery extends Query<Person, PersonQueryWhere> {
}
var model = Person(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
name: fields.contains('name') ? (row[3] as String?) : null,
age: fields.contains('age') ? (row[4] as int?) : null);
return Optional.of(model);

View file

@ -93,13 +93,11 @@ class PersonOrderQuery extends Query<PersonOrder, PersonOrderQueryWhere> {
}
var model = PersonOrder(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
personId: fields.contains('person_id') ? (row[3] as int?) : null,
name: fields.contains('name') ? (row[4] as String?) : null,
price: fields.contains('price')
? double.tryParse(row[5].toString())
: null,
price: fields.contains('price') ? mapToDouble(row[5]) : null,
deleted: fields.contains('deleted') ? mapToBool(row[6]) : null);
return Optional.of(model);
}
@ -258,12 +256,10 @@ class OrderWithPersonInfoQuery
}
var model = OrderWithPersonInfo(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
name: fields.contains('name') ? (row[3] as String?) : null,
price: fields.contains('price')
? double.tryParse(row[4].toString())
: null,
price: fields.contains('price') ? mapToDouble(row[4]) : null,
deleted: fields.contains('deleted') ? mapToBool(row[5]) : null,
personName: fields.contains('person_name') ? (row[6] as String?) : null,
personAge: fields.contains('person_age') ? (row[7] as int?) : null);

View file

@ -110,8 +110,8 @@ class TreeQuery extends Query<Tree, TreeQueryWhere> {
}
var model = Tree(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
rings: fields.contains('rings') ? (row[3] as int?) : null);
if (row.length > 4) {
var modelOpt = FruitQuery().parseRow(row.skip(4).take(5).toList());
@ -299,8 +299,8 @@ class FruitQuery extends Query<Fruit, FruitQueryWhere> {
}
var model = Fruit(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
treeId: fields.contains('tree_id') ? (row[3] as int?) : null,
commonName:
fields.contains('common_name') ? (row[4] as String?) : null);

View file

@ -486,8 +486,8 @@ class SongQuery extends Query<Song, SongQueryWhere> {
}
var model = Song(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
weirdJoinId: fields.contains('weird_join_id') ? (row[3] as int?) : null,
title: fields.contains('title') ? (row[4] as String?) : null);
return Optional.of(model);

View file

@ -127,8 +127,8 @@ class UserQuery extends Query<User, UserQueryWhere> {
}
var model = User(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
username: fields.contains('username') ? (row[3] as String?) : null,
password: fields.contains('password') ? (row[4] as String?) : null,
email: fields.contains('email') ? (row[5] as String?) : null);
@ -487,8 +487,8 @@ class RoleQuery extends Query<Role, RoleQueryWhere> {
}
var model = Role(
id: fields.contains('id') ? row[0].toString() : null,
createdAt: fields.contains('created_at') ? (row[1] as DateTime?) : null,
updatedAt: fields.contains('updated_at') ? (row[2] as DateTime?) : null,
createdAt: fields.contains('created_at') ? mapToDateTime(row[1]) : null,
updatedAt: fields.contains('updated_at') ? mapToDateTime(row[2]) : null,
name: fields.contains('name') ? (row[3] as String?) : null);
if (row.length > 4) {
var modelOpt = UserQuery().parseRow(row.skip(4).take(6).toList());

View file

@ -1,5 +1,5 @@
name: angel3_orm_test
version: 6.0.0
version: 6.0.1
description: Common tests for Angel3 ORM. Reference implmentation of the generated ORM files.
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_test
@ -19,26 +19,26 @@ dev_dependencies:
angel3_framework: ^6.0.0
build_runner: ^2.0.1
lints: ^1.0.0
# dependency_overrides:
# angel3_container:
# path: ../../container/angel_container
# angel3_framework:
# path: ../../framework
# angel3_http_exception:
# path: ../../http_exception
# angel3_model:
# path: ../../model
# angel3_route:
# path: ../../route
# angel3_mock_request:
# path: ../../mock_request
# angel3_serialize:
# path: ../../serialize/angel_serialize
# angel3_serialize_generator:
# path: ../../serialize/angel_serialize_generator
# angel3_orm:
# path: ../angel_orm
# angel3_migration:
# path: ../angel_migration
# angel3_orm_generator:
# path: ../angel_orm_generator
dependency_overrides:
# angel3_container:
# path: ../../container/angel_container
# angel3_framework:
# path: ../../framework
# angel3_http_exception:
# path: ../../http_exception
# angel3_model:
# path: ../../model
# angel3_route:
# path: ../../route
# angel3_mock_request:
# path: ../../mock_request
# angel3_serialize:
# path: ../../serialize/angel_serialize
# angel3_serialize_generator:
# path: ../../serialize/angel_serialize_generator
angel3_orm:
path: ../angel_orm
# angel3_migration:
# path: ../angel_migration
angel3_orm_generator:
path: ../angel_orm_generator