Fixed temporal mapping

This commit is contained in:
thomashii@dukefirehawk.com 2022-07-24 12:00:10 +08:00
parent 793a8ac115
commit 572a134c9c
41 changed files with 356 additions and 97 deletions

View file

@ -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

View 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()}");
}

View 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

View file

@ -0,0 +1,6 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
The current main maintainer of the code base.

View 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.

View file

@ -0,0 +1 @@
include: package:lints/recommended.yaml

View 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");
}

View 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

View file

@ -0,0 +1,6 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
The current main maintainer of the code base.

View 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.

View file

@ -0,0 +1 @@
include: package:lints/recommended.yaml

View file

@ -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] ?? '');
} }

View file

@ -18,5 +18,5 @@ Future<String> absoluteSourcePath(Type type) async {
} }
} }
return uri.toFilePath() + '#' + MirrorSystem.getName(mirror.simpleName); return '${uri.toFilePath()}#${MirrorSystem.getName(mirror.simpleName)}';
} }

View file

@ -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);
}); });
} }
} }

View file

@ -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

View file

@ -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;

View file

@ -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();
}); });

View file

@ -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);

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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)
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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)
); );

View file

@ -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
); );

View file

@ -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)
); );

View file

@ -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)
); );

View file

@ -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
); );

View file

@ -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
); );

View file

@ -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);

View file

@ -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

View file

@ -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)