Fixed temporal mapping
This commit is contained in:
parent
793a8ac115
commit
572a134c9c
41 changed files with 356 additions and 97 deletions
|
@ -63,8 +63,9 @@ For more details, checkout [Project Status](https://github.com/dukefirehawk/ange
|
||||||
1. Download and install [Dart](https://dart.dev/get-dart)
|
1. Download and install [Dart](https://dart.dev/get-dart)
|
||||||
|
|
||||||
2. Clone one of the following starter projects:
|
2. Clone one of the following starter projects:
|
||||||
* [Angel3 Basic Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-basic)
|
* [Basic Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-basic)
|
||||||
* [Angel3 ORM Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-orm)
|
* [ORM for PostgreSQL Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-orm)
|
||||||
|
* [ORM for MySQL Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-orm-mysql)
|
||||||
* [Angel3 Graphql Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-graphql)
|
* [Angel3 Graphql Template](https://github.com/dukefirehawk/boilerplates/tree/angel3-graphql)
|
||||||
|
|
||||||
3. Run the project in development mode (*hot-reloaded* is enabled on file changes).
|
3. Run the project in development mode (*hot-reloaded* is enabled on file changes).
|
||||||
|
@ -123,12 +124,12 @@ Check out [Migrating to Angel3](https://angel3-docs.dukefirehawk.com/migration/a
|
||||||
|
|
||||||
The performance benchmark can be found at
|
The performance benchmark can be found at
|
||||||
|
|
||||||
[TechEmpower Framework Benchmarks](https://tfb-status.techempower.com/)
|
[TechEmpower Framework Benchmarks Round 21](https://www.techempower.com/benchmarks/#section=data-r21&test=composite)
|
||||||
|
|
||||||
The test cases are build using standard `Angel3 ORM` template. This result will be used for fine-tuning Angel3 framework. The following test cases will be progressively added in the upcoming update to benchmark.
|
The test cases are build using standard `Angel3 ORM` template. This result will be used for fine-tuning Angel3 framework. The following test cases will be progressively added in the upcoming update to benchmark.
|
||||||
|
|
||||||
1. Angel3 with MongoDB
|
1. Angel3 with MongoDB
|
||||||
2. Angel3 with MySQL ORM
|
2. Angel3 with ORM MySQL
|
||||||
3. Cached queries
|
3. Cached queries
|
||||||
|
|
||||||
## Examples and Documentation
|
## Examples and Documentation
|
||||||
|
|
93
experiment/db/bin/mysql_sql_main.dart
Normal file
93
experiment/db/bin/mysql_sql_main.dart
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:mysql_client/mysql_client.dart';
|
||||||
|
import 'package:mysql1/mysql1.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
print("=== Start 'mysql1' driver test");
|
||||||
|
await testMySQL1Driver().catchError((error, stackTrace) {
|
||||||
|
print(error);
|
||||||
|
});
|
||||||
|
print("=== End test");
|
||||||
|
print(" ");
|
||||||
|
|
||||||
|
print("=== Start 'mysql_client' driver test");
|
||||||
|
await testMySQLClientDriver().catchError((error, stackTrace) {
|
||||||
|
print(error);
|
||||||
|
});
|
||||||
|
print("=== End test");
|
||||||
|
print(" ");
|
||||||
|
|
||||||
|
//sleep(Duration(seconds: 5));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> testMySQLClientDriver() async {
|
||||||
|
var connection = await MySQLConnection.createConnection(
|
||||||
|
host: "localhost",
|
||||||
|
port: 3306,
|
||||||
|
databaseName: "orm_test",
|
||||||
|
userName: "test",
|
||||||
|
password: "test123",
|
||||||
|
secure: false);
|
||||||
|
await connection.connect(timeoutMs: 30000);
|
||||||
|
|
||||||
|
print(">Test Select All");
|
||||||
|
var result = await connection.execute("SELECT * from users");
|
||||||
|
print("Total records: ${result.rows.length}");
|
||||||
|
|
||||||
|
print(">Test Insert");
|
||||||
|
var params = {
|
||||||
|
"username": "test",
|
||||||
|
"password": "test123",
|
||||||
|
"email": "test@demo.com",
|
||||||
|
"updatedAt": DateTime.parse("1970-01-01 00:00:00")
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await connection.execute(
|
||||||
|
"INSERT INTO users (username, password, email, updated_at) VALUES (:username, :password, :email, :updatedAt)",
|
||||||
|
params);
|
||||||
|
print("Last inserted ID: ${result.lastInsertID}");
|
||||||
|
|
||||||
|
print(">Test Select By ID");
|
||||||
|
result = await connection.execute(
|
||||||
|
"SELECT * from users where id=:id", {"id": result.lastInsertID.toInt()});
|
||||||
|
print("Read record: ${result.rows.first.assoc()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> testMySQL1Driver() async {
|
||||||
|
var settings = ConnectionSettings(
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3306,
|
||||||
|
db: 'orm_test',
|
||||||
|
user: 'test',
|
||||||
|
password: 'test123',
|
||||||
|
timeout: Duration(seconds: 60));
|
||||||
|
var connection = await MySqlConnection.connect(settings);
|
||||||
|
|
||||||
|
print(">Test Select All");
|
||||||
|
var result = await connection.query("SELECT * from users");
|
||||||
|
print("Total records: ${result.length}");
|
||||||
|
|
||||||
|
print(">Test Insert");
|
||||||
|
var params = [
|
||||||
|
"test",
|
||||||
|
"test123",
|
||||||
|
"test@demo.com",
|
||||||
|
DateTime.parse("1970-01-01 00:00:00").toUtc()
|
||||||
|
];
|
||||||
|
|
||||||
|
// DateTime.parse("1970-01-01 00:00:01").toUtc()
|
||||||
|
result = await connection.query(
|
||||||
|
"INSERT INTO users (username, password, email, updated_at) VALUES (?, ?, ?, ?)",
|
||||||
|
params);
|
||||||
|
print("Last inserted ID: ${result.insertId}");
|
||||||
|
|
||||||
|
print(">Test Select By ID");
|
||||||
|
result = await connection
|
||||||
|
.query("SELECT * from users where id=?", [result.insertId]);
|
||||||
|
print("Read record: ${result.first.values}");
|
||||||
|
|
||||||
|
var d = DateTime.parse("1970-01-01 00:00:00").toUtc();
|
||||||
|
print("Local time: ${d.toLocal()}");
|
||||||
|
}
|
12
experiment/db/pubspec.yaml
Normal file
12
experiment/db/pubspec.yaml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
name: performance_tool
|
||||||
|
version: 1.0.0
|
||||||
|
description: Angel3 performance testing tool
|
||||||
|
publish_to: none
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.16.0 <3.0.0'
|
||||||
|
published_to: none
|
||||||
|
dependencies:
|
||||||
|
mysql1: ^0.20.0
|
||||||
|
mysql_client: ^0.0.24
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^2.0.0
|
6
experiment/logging/AUTHORS.md
Normal file
6
experiment/logging/AUTHORS.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
The current main maintainer of the code base.
|
29
experiment/logging/LICENSE
Normal file
29
experiment/logging/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2021, dukefirehawk.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1
experiment/logging/analysis_options.yaml
Normal file
1
experiment/logging/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include: package:lints/recommended.yaml
|
22
experiment/logging/bin/main.dart
Normal file
22
experiment/logging/bin/main.dart
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import 'dart:isolate';
|
||||||
|
|
||||||
|
Future<void> runApp(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
// Do something
|
||||||
|
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
var concurrency = 6000;
|
||||||
|
|
||||||
|
for (var i = 0; i < concurrency; i++) {
|
||||||
|
Isolate.spawn(runApp, 'Instance_$i');
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(seconds: 10));
|
||||||
|
|
||||||
|
//print("Exit");
|
||||||
|
}
|
11
experiment/logging/pubspec.yaml
Normal file
11
experiment/logging/pubspec.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
name: performance_tool
|
||||||
|
version: 1.0.0
|
||||||
|
description: Angel3 performance testing tool
|
||||||
|
publish_to: none
|
||||||
|
environment:
|
||||||
|
sdk: '>=2.16.0 <3.0.0'
|
||||||
|
published_to: none
|
||||||
|
dependencies:
|
||||||
|
http: ^0.13.4
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^2.0.0
|
6
experiment/performance/AUTHORS.md
Normal file
6
experiment/performance/AUTHORS.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Primary Authors
|
||||||
|
===============
|
||||||
|
|
||||||
|
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
|
||||||
|
|
||||||
|
The current main maintainer of the code base.
|
29
experiment/performance/LICENSE
Normal file
29
experiment/performance/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2021, dukefirehawk.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
1
experiment/performance/analysis_options.yaml
Normal file
1
experiment/performance/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include: package:lints/recommended.yaml
|
|
@ -291,15 +291,23 @@ abstract class Driver<
|
||||||
Future sendResponse(Request request, Response response, RequestContext req,
|
Future sendResponse(Request request, Response response, RequestContext req,
|
||||||
ResponseContext res,
|
ResponseContext res,
|
||||||
{bool ignoreFinalizers = false}) {
|
{bool ignoreFinalizers = false}) {
|
||||||
|
//app.logger.fine("Calling SendResponse");
|
||||||
Future<void> _cleanup(_) {
|
Future<void> _cleanup(_) {
|
||||||
if (!app.environment.isProduction && req.container!.has<Stopwatch>()) {
|
if (!app.environment.isProduction && req.container!.has<Stopwatch>()) {
|
||||||
var sw = req.container!.make<Stopwatch>();
|
var sw = req.container!.make<Stopwatch>();
|
||||||
app.logger.info(
|
app.logger.fine(
|
||||||
"${res.statusCode} ${req.method} ${req.uri} (${sw.elapsedMilliseconds} ms)");
|
"${res.statusCode} ${req.method} ${req.uri} (${sw.elapsedMilliseconds} ms)");
|
||||||
}
|
}
|
||||||
return req.close();
|
return req.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Debugging header
|
||||||
|
/*
|
||||||
|
for (var key in res.headers.keys) {
|
||||||
|
app.logger.fine("Response header key: $key");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
if (!res.isBuffered) {
|
if (!res.isBuffered) {
|
||||||
//if (res.isOpen) {
|
//if (res.isOpen) {
|
||||||
return res.close().then(_cleanup);
|
return res.close().then(_cleanup);
|
||||||
|
@ -307,6 +315,8 @@ abstract class Driver<
|
||||||
//return Future.value();
|
//return Future.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//app.logger.fine("Calling finalizers");
|
||||||
|
|
||||||
var finalizers = ignoreFinalizers == true
|
var finalizers = ignoreFinalizers == true
|
||||||
? Future.value()
|
? Future.value()
|
||||||
: Future.forEach(app.responseFinalizers, (dynamic f) => f(req, res));
|
: Future.forEach(app.responseFinalizers, (dynamic f) => f(req, res));
|
||||||
|
@ -315,6 +325,7 @@ abstract class Driver<
|
||||||
//if (res.isOpen) res.close();
|
//if (res.isOpen) res.close();
|
||||||
|
|
||||||
for (var key in res.headers.keys) {
|
for (var key in res.headers.keys) {
|
||||||
|
app.logger.fine("Response header key: $key");
|
||||||
setHeader(response, key, res.headers[key] ?? '');
|
setHeader(response, key, res.headers[key] ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,5 +18,5 @@ Future<String> absoluteSourcePath(Type type) async {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return uri.toFilePath() + '#' + MirrorSystem.getName(mirror.simpleName);
|
return '${uri.toFilePath()}#${MirrorSystem.getName(mirror.simpleName)}';
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,9 +397,14 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
||||||
return executor
|
return executor
|
||||||
.query(tableName, sql, substitutionValues,
|
.query(tableName, sql, substitutionValues,
|
||||||
returningQuery: returningSql)
|
returningQuery: returningSql)
|
||||||
.then((it) {
|
.then((result) {
|
||||||
// Return SQL execution results
|
// Return SQL execution results
|
||||||
return it.isEmpty ? Optional.empty() : deserialize(it.first);
|
//if (result.isNotEmpty) {
|
||||||
|
// for (var element in result.first) {
|
||||||
|
// _log.fine("value: $element");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
return result.isEmpty ? Optional.empty() : deserialize(result.first);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,19 +5,48 @@
|
||||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_mysql/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_mysql/LICENSE)
|
||||||
|
|
||||||
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.
|
This package contains the SQL executor required by Angel3 ORM to work with MySQL and MariaDB respectively. In order to better support both MySQL and MariaDB, two different flavors of drives have been included; `mysql_client` and `mysql1`. They are implmented as `MySqlExecutor` and `MariaDbExecutor` respectively.
|
||||||
|
|
||||||
* MariaDbExecutor
|
## Supported databases
|
||||||
* MySqlExecutor
|
|
||||||
|
|
||||||
## Supported database version
|
* MariaDD 10.2.x or greater
|
||||||
|
* MySQL 8.x or greater
|
||||||
|
|
||||||
* MariaDb 10.2.x
|
**Note** MySQL below version 8.0 and MariaDB below version 10.2.0 are not supported as Angel3 ORM requires common table expressions (CTE) to work.
|
||||||
* MySQL 8.x
|
|
||||||
|
|
||||||
**Note** MySQL below version 8.0 and MariaDB below version 10.2 are not supported as Angel3 ORM requires common table expressions (CTE).
|
## MySqlExecutor
|
||||||
|
|
||||||
## Connecting to MariaDB database 10.2.x
|
This SQL executor is implemented using [`mysql_client`](https://pub.dev/packages?q=mysql_client) driver. It works with both `MySQL` 8.0+ and `MariaDB` 10.2+ database.
|
||||||
|
|
||||||
|
### Connecting to MySQL or MariaDB
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import 'package:mysql_client/mysql_client.dart';
|
||||||
|
|
||||||
|
var connection = await MySQLConnection.createConnection(
|
||||||
|
host: "localhost",
|
||||||
|
port: 3306,
|
||||||
|
databaseName: "orm_test",
|
||||||
|
userName: "test",
|
||||||
|
password: "test123",
|
||||||
|
secure: true);
|
||||||
|
|
||||||
|
var logger = Logger('orm_mysql');
|
||||||
|
await connection.connect(timeoutMs: 10000);
|
||||||
|
var executor = MySqlExecutor(connection, logger: logger);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Known Limitation for MySqlExecutor
|
||||||
|
|
||||||
|
* `Blob` data type mapping is not support.
|
||||||
|
* `timestamp` data type mapping is not supported. Use `datetime` instead.
|
||||||
|
* UTC datetime is not supported.
|
||||||
|
|
||||||
|
## MariaDBExecutor
|
||||||
|
|
||||||
|
This SQL executor is implemented using [`mysql1`](https://pub.dev/packages?q=mysql1) driver. It only works with `MariaDB` 10.2+ database. Do not use this for `MySQL` 8.0+ database.
|
||||||
|
|
||||||
|
### Connecting to MariaDB
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:mysql1/mysql1.dart';
|
import 'package:mysql1/mysql1.dart';
|
||||||
|
@ -34,31 +63,13 @@ This package contains the SQL Executor required by Angel3 ORM to work with MySQL
|
||||||
var executor = MariaDbExecutor(connection, logger: logger);
|
var executor = MariaDbExecutor(connection, logger: logger);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Connecting to MySQL database 8.x
|
### Known Limitation for MariaDBExecutor
|
||||||
|
|
||||||
```dart
|
* `Blob` type mapping is not supported.
|
||||||
import 'package:mysql_client/mysql_client.dart';
|
* `timestamp` mapping is not supported. Use `datetime` instead.
|
||||||
|
* Only UTC datetime is supported. None UTC datetime will be automatically converted into UTC datetime.
|
||||||
|
|
||||||
var connection = await MySQLConnection.createConnection(
|
## Creating a new database in MariaDB or MySQL
|
||||||
host: "localhost",
|
|
||||||
port: 3306,
|
|
||||||
databaseName: "orm_test",
|
|
||||||
userName: "test",
|
|
||||||
password: "test123",
|
|
||||||
secure: false);
|
|
||||||
|
|
||||||
var logger = Logger('orm_mysql');
|
|
||||||
await connection.connect(timeoutMs: 10000);
|
|
||||||
var executor = MySqlExecutor(connection, logger: logger);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issues
|
|
||||||
|
|
||||||
* Blob
|
|
||||||
* DateTime value not in UTC
|
|
||||||
* Transaction is broken
|
|
||||||
|
|
||||||
## Creating a new database in MariaDB/MySQL
|
|
||||||
|
|
||||||
1. Login to MariaDB/MySQL database console with the following command.
|
1. Login to MariaDB/MySQL database console with the following command.
|
||||||
|
|
||||||
|
@ -71,29 +82,27 @@ This package contains the SQL Executor required by Angel3 ORM to work with MySQL
|
||||||
```mysql
|
```mysql
|
||||||
create database orm_test;
|
create database orm_test;
|
||||||
|
|
||||||
|
-- Granting localhost access only
|
||||||
create user 'test'@'localhost' identified by 'test123';
|
create user 'test'@'localhost' identified by 'test123';
|
||||||
grant all privileges on orm_test.* to 'test'@'localhost';
|
grant all privileges on orm_test.* to 'test'@'localhost';
|
||||||
|
|
||||||
|
-- Granting localhost and remote access
|
||||||
create user 'test'@'%' identified by 'test123';
|
create user 'test'@'%' identified by 'test123';
|
||||||
grant all privileges on orm_test.* to 'test'@'%';
|
grant all privileges on orm_test.* to 'test'@'%';
|
||||||
```
|
```
|
||||||
|
|
||||||
## Known limitation
|
## Compatibility Matrix
|
||||||
|
|
||||||
### Using `mysql1` driver on MariabDb
|
### MariaDB 10.2+
|
||||||
|
|
||||||
* Blob
|
| | Create | Read | Update | Delete |
|
||||||
* DateTime value not in UTC
|
|-----------------|--------|--------|--------|--------|
|
||||||
* Transaction is broken
|
| MySqlExecutor | Y | Y | Y | Y |
|
||||||
|
| MariaDBExecutor | Y | Y | Y | Y |
|
||||||
|
|
||||||
### Using `mysql1` driver on MySQL
|
### MySQL 8.0+
|
||||||
|
|
||||||
* Blob is not supported
|
| | Create | Read | Update | Delete |
|
||||||
|
|-----------------|--------|--------|--------|--------|
|
||||||
### Using `mysql_client` driver on MariabDb
|
| MySqlExecutor | Y | Y | Y | Y |
|
||||||
|
| MariaDBExecutor | N | N | N | N |
|
||||||
* Blob is not supported
|
|
||||||
|
|
||||||
### Using `mysql_client` driver on MySQL
|
|
||||||
|
|
||||||
* Blob is not supported
|
|
||||||
|
|
|
@ -9,6 +9,8 @@ class MariaDbExecutor extends QueryExecutor {
|
||||||
|
|
||||||
final MySqlConnection _connection;
|
final MySqlConnection _connection;
|
||||||
|
|
||||||
|
TransactionContext? _transactionContext;
|
||||||
|
|
||||||
MariaDbExecutor(this._connection, {Logger? logger}) {
|
MariaDbExecutor(this._connection, {Logger? logger}) {
|
||||||
this.logger = logger ?? Logger('MariaDbExecutor');
|
this.logger = logger ?? Logger('MariaDbExecutor');
|
||||||
}
|
}
|
||||||
|
@ -33,6 +35,15 @@ class MariaDbExecutor extends QueryExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
var params = substitutionValues.values.toList();
|
var params = substitutionValues.values.toList();
|
||||||
|
for (var i = 0; i < params.length; i++) {
|
||||||
|
var v = params[i];
|
||||||
|
|
||||||
|
if (v is DateTime) {
|
||||||
|
if (!v.isUtc) {
|
||||||
|
params[i] = v.toUtc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.warning('Query: $query');
|
logger.warning('Query: $query');
|
||||||
logger.warning('Values: $params');
|
logger.warning('Values: $params');
|
||||||
|
@ -66,12 +77,12 @@ class MariaDbExecutor extends QueryExecutor {
|
||||||
@override
|
@override
|
||||||
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
|
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
|
||||||
T? returnValue = await _connection.transaction((ctx) async {
|
T? returnValue = await _connection.transaction((ctx) async {
|
||||||
// TODO: This is broken
|
// TODO: To be relooked at
|
||||||
var conn = ctx as MySqlConnection;
|
|
||||||
try {
|
try {
|
||||||
logger.fine('Entering transaction');
|
logger.fine('Entering transaction');
|
||||||
var tx = MariaDbExecutor(conn, logger: logger);
|
//var tx = MariaDbExecutor(conn, logger: logger);
|
||||||
return await f(tx);
|
_transactionContext = ctx;
|
||||||
|
return await f(this);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.severe('Failed to run transaction', e);
|
logger.severe('Failed to run transaction', e);
|
||||||
rethrow;
|
rethrow;
|
||||||
|
|
|
@ -131,7 +131,10 @@ class MySqlExecutor extends QueryExecutor {
|
||||||
|
|
||||||
// Handle select
|
// Handle select
|
||||||
return _connection.execute(query, substitutionValues).then((results) {
|
return _connection.execute(query, substitutionValues).then((results) {
|
||||||
logger.warning("SELECT");
|
var tmpData = results.rows;
|
||||||
|
for (var element in tmpData) {
|
||||||
|
logger.warning("[Result] : ${element.assoc()}");
|
||||||
|
}
|
||||||
|
|
||||||
return results.rows.map((r) => r.typedAssoc().values.toList()).toList();
|
return results.rows.map((r) => r.typedAssoc().values.toList()).toList();
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,25 +10,28 @@ List tmpTables = [];
|
||||||
|
|
||||||
FutureOr<QueryExecutor> Function() createTables(List<String> schemas) {
|
FutureOr<QueryExecutor> Function() createTables(List<String> schemas) {
|
||||||
// For MySQL
|
// For MySQL
|
||||||
//return () => _connectToMySql(schemas);
|
return () => _connectToMySql(schemas);
|
||||||
|
|
||||||
// For MariaDB
|
// For MariaDB
|
||||||
return () => _connectToMariaDb(schemas);
|
//return () => _connectToMariaDb(schemas);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For MySQL
|
// For MySQL
|
||||||
Future<void> dropTables2(QueryExecutor executor) async {
|
Future<void> dropTables(QueryExecutor executor) async {
|
||||||
var sqlExecutor = (executor as MySqlExecutor);
|
var sqlExecutor = (executor as MySqlExecutor);
|
||||||
for (var tableName in tmpTables.reversed) {
|
for (var tableName in tmpTables.reversed) {
|
||||||
await sqlExecutor.rawConnection.execute('drop table $tableName;');
|
print('DROP TABLE $tableName');
|
||||||
|
await sqlExecutor.rawConnection.execute('DROP TABLE $tableName;');
|
||||||
}
|
}
|
||||||
|
|
||||||
return sqlExecutor.close();
|
return sqlExecutor.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// For MariaDB
|
// For MariaDB
|
||||||
Future<void> dropTables(QueryExecutor executor) {
|
Future<void> dropTables2(QueryExecutor executor) {
|
||||||
var sqlExecutor = (executor as MariaDbExecutor);
|
var sqlExecutor = (executor as MariaDbExecutor);
|
||||||
for (var tableName in tmpTables.reversed) {
|
for (var tableName in tmpTables.reversed) {
|
||||||
|
print('DROP TABLE $tableName');
|
||||||
sqlExecutor.query(tableName, 'DROP TABLE $tableName', {});
|
sqlExecutor.query(tableName, 'DROP TABLE $tableName', {});
|
||||||
}
|
}
|
||||||
return sqlExecutor.close();
|
return sqlExecutor.close();
|
||||||
|
@ -64,7 +67,7 @@ Future<MariaDbExecutor> _connectToMariaDb(List<String> schemas) async {
|
||||||
var data = await File('test/migrations/$s.sql').readAsString();
|
var data = await File('test/migrations/$s.sql').readAsString();
|
||||||
var queries = data.split(";");
|
var queries = data.split(";");
|
||||||
for (var q in queries) {
|
for (var q in queries) {
|
||||||
//print("Table: [$q]");
|
print("Table: [$q]");
|
||||||
if (q.trim().isNotEmpty) {
|
if (q.trim().isNotEmpty) {
|
||||||
//await connection.execute(q);
|
//await connection.execute(q);
|
||||||
await connection.query(q);
|
await connection.query(q);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE IF NOT EXISTS authors (
|
CREATE TABLE IF NOT EXISTS authors (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
name varchar(255) UNIQUE NOT NULL,
|
name varchar(255) UNIQUE NOT NULL,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -3,6 +3,6 @@ CREATE TABLE IF NOT EXISTS books (
|
||||||
author_id int NOT NULL,
|
author_id int NOT NULL,
|
||||||
partner_author_id int,
|
partner_author_id int,
|
||||||
name varchar(255),
|
name varchar(255),
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -3,7 +3,7 @@ CREATE TABLE IF NOT EXISTS cars (
|
||||||
make varchar(255) NOT NULL,
|
make varchar(255) NOT NULL,
|
||||||
description TEXT NOT NULL,
|
description TEXT NOT NULL,
|
||||||
family_friendly BOOLEAN NOT NULL,
|
family_friendly BOOLEAN NOT NULL,
|
||||||
recalled_at timestamp,
|
recalled_at datetime,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -2,6 +2,6 @@ CREATE TABLE IF NOT EXISTS feet (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
leg_id int NOT NULL,
|
leg_id int NOT NULL,
|
||||||
n_toes int NOT NULL,
|
n_toes int NOT NULL,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS fruits (
|
||||||
id serial,
|
id serial,
|
||||||
tree_id int,
|
tree_id int,
|
||||||
common_name varchar(255),
|
common_name varchar(255),
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp,
|
updated_at datetime,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE IF NOT EXISTS has_cars (
|
CREATE TABLE IF NOT EXISTS has_cars (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
type int not null,
|
type int not null,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -2,6 +2,6 @@ CREATE TABLE IF NOT EXISTS has_maps (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
value jsonb not null,
|
value jsonb not null,
|
||||||
list jsonb not null,
|
list jsonb not null,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE IF NOT EXISTS legs (
|
CREATE TABLE IF NOT EXISTS legs (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
name varchar(255) NOT NULL,
|
name varchar(255) NOT NULL,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE TABLE IF NOT EXISTS numbas (
|
CREATE TABLE IF NOT EXISTS numbas (
|
||||||
i int NOT NULL UNIQUE,
|
i int NOT NULL UNIQUE,
|
||||||
parent int,
|
parent int,
|
||||||
created_at TIMESTAMP,
|
created_at datetime,
|
||||||
updated_at TIMESTAMP,
|
updated_at datetime,
|
||||||
PRIMARY KEY(i)
|
PRIMARY KEY(i)
|
||||||
);
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
CREATE TABLE IF NOT EXISTS roles (
|
CREATE TABLE IF NOT EXISTS roles (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
name varchar(255),
|
name varchar(255),
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -2,7 +2,7 @@ CREATE TABLE IF NOT EXISTS songs (
|
||||||
id serial,
|
id serial,
|
||||||
weird_join_id int,
|
weird_join_id int,
|
||||||
title varchar(255),
|
title varchar(255),
|
||||||
created_at TIMESTAMP,
|
created_at datetime,
|
||||||
updated_at TIMESTAMP,
|
updated_at datetime,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE TABLE IF NOT EXISTS trees (
|
CREATE TABLE IF NOT EXISTS trees (
|
||||||
id serial,
|
id serial,
|
||||||
rings smallint UNIQUE,
|
rings smallint UNIQUE,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp,
|
updated_at datetime,
|
||||||
PRIMARY KEY(id)
|
PRIMARY KEY(id)
|
||||||
);
|
);
|
|
@ -3,6 +3,6 @@ CREATE TABLE IF NOT EXISTS users (
|
||||||
username varchar(255),
|
username varchar(255),
|
||||||
password varchar(255),
|
password varchar(255),
|
||||||
email varchar(255),
|
email varchar(255),
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -2,6 +2,6 @@ CREATE TABLE IF NOT EXISTS role_users (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
user_id int NOT NULL,
|
user_id int NOT NULL,
|
||||||
role_id int NOT NULL,
|
role_id int NOT NULL,
|
||||||
created_at timestamp,
|
created_at datetime,
|
||||||
updated_at timestamp
|
updated_at datetime
|
||||||
);
|
);
|
|
@ -14,7 +14,7 @@ void main() async {
|
||||||
// if (rec.stackTrace != null) print(rec.stackTrace);
|
// if (rec.stackTrace != null) print(rec.stackTrace);
|
||||||
//});
|
//});
|
||||||
|
|
||||||
belongsToTests(createTables(['author', 'book']), close: dropTables);
|
//belongsToTests(createTables(['author', 'book']), close: dropTables);
|
||||||
|
|
||||||
//hasOneTests(my(['leg', 'foot']), close: closeMy);
|
//hasOneTests(my(['leg', 'foot']), close: closeMy);
|
||||||
//standaloneTests(my(['car']), close: closeMy);
|
//standaloneTests(my(['car']), close: closeMy);
|
||||||
|
|
|
@ -5,4 +5,10 @@
|
||||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_test/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_test/LICENSE)
|
||||||
|
|
||||||
Common tests for Angel3 ORM. Reference implmentation of generated ORM files.
|
Common test cases for Angel3 ORM. Reference implmentation of generated ORM files.
|
||||||
|
|
||||||
|
## Supported databases
|
||||||
|
|
||||||
|
* MariaDb 10.2.x or greater
|
||||||
|
* MySQL 8.x or greater
|
||||||
|
* PostreSQL 10.x or greater
|
||||||
|
|
|
@ -17,7 +17,7 @@ abstract class _Boat extends Model {
|
||||||
@Column(defaultValue: false)
|
@Column(defaultValue: false)
|
||||||
bool get familyFriendly;
|
bool get familyFriendly;
|
||||||
|
|
||||||
//@SerializableField(defaultValue: '1970-01-01 00:00:00')
|
//@SerializableField(defaultValue: '1970-01-01 00:00:01')
|
||||||
DateTime get recalledAt;
|
DateTime get recalledAt;
|
||||||
|
|
||||||
@Column(defaultValue: 0.0)
|
@Column(defaultValue: 0.0)
|
||||||
|
|
Loading…
Reference in a new issue