Merge pull request #34 from dukefirehawk/feature/update-orm
Update ORM for Postgresql
This commit is contained in:
commit
342bdb322e
48 changed files with 1313 additions and 392 deletions
|
@ -1,29 +0,0 @@
|
||||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
|
||||||
MIIE5DAcBgoqhkiG9w0BDAEBMA4ECL7L6rj6uEHGAgIIAASCBMLbucyfqAkgCbhP
|
|
||||||
xNSHYllPMAv/dsIjtnsBwepCXPGkCBCuOAw/2FaCHjN9hBqL5V7fkrKeaemhm2YE
|
|
||||||
ycPtlHJYPDf3kEkyMjdZ9rIY6kePGfQizs2uJPcXj4YPyQ4HsfVXpOicKfQrouf5
|
|
||||||
Mze9bGzeMN065q3iP4dYUMwHAyZYteXCsanQNHlqvsWli0W+H8St8fdsXefZhnv1
|
|
||||||
qVatKWdNdWQ9t5MuljgNU2Vv56sHKEYXI0yLxk2QUMk8KlJfnmt8foYUsnPUXHmc
|
|
||||||
gIjLKwwVkpdololnEHSNu0cEOUPowjgJru+uMpn7vdNl7TPEQ9jbEgdNg4JwoYzU
|
|
||||||
0nao8WzjaSp7kzvZz0VFwKnk5AjstGvvuAWckADdq23QElbn/mF7AG1m/TBpYxzF
|
|
||||||
gTt37UdndS/AcvVznWVVrRP5iTSIawdIwvqI4s7rqsoE0GCcak+RhchgAz2gWKkS
|
|
||||||
oODUo0JL6pPVbJ3l4ebbaO6c99nDVc8dViPtc1EkStJEJ2O4kI4xgLSCr4Y9ahKn
|
|
||||||
oAaoSkX7Xxq3aQm+BzqSpLjdGL8atsqR/YVOIHYIl3gThvP0NfZGx1xHyvO5mCdZ
|
|
||||||
kHxSA7tKWxauZ3eQ2clbnzeRsl4El0WMHy/5K1ovene4v7sunmoXVtghBC8hK6eh
|
|
||||||
zMO9orex2PNQ/VQC7HCvtytunOVx1lkSBoNo7hR70igg6rW9H7UyoAoBOwMpT1xa
|
|
||||||
J6V62nqruTKOqFNfur7aHJGpHGtDb5/ickHeYCyPTvmGp67u4wChzKReeg02oECe
|
|
||||||
d1E5FKAcIa8s9TVOB6Z+HvTRNQZu2PsI6TJnjQRowvY9DAHiWTlJZBBY/pko3hxX
|
|
||||||
TsIeybpvRdEHpDWv86/iqtw1hv9CUxS/8ZTWUgBo+osShHW79FeDASr9FC4/Zn76
|
|
||||||
ZDERTgV4YWlW/klVWcG2lFo7jix+OPXAB+ZQavLhlN1xdWBcIz1AUWjAM4hdPylW
|
|
||||||
HCX4PB9CQIPl2E7F+Y2p6nMcMWSJVBi5UIH7E9LfaBguXSzMmTk2Fw5p1aOQ6wfN
|
|
||||||
goVAMVwi8ppAVs741PfHdZ295xMmK/1LCxz5DeAdD/tsA/SYfT753GotioDuC7im
|
|
||||||
EyJ5JyvTr5I6RFFBuqt3NlUb3Hp16wP3B2x9DZiB6jxr0l341/NHgsyeBXkuIy9j
|
|
||||||
ON2mvpBPCJhS8kgWo3G0UyyKnx64tcgpGuSvZhGwPz843B6AbYyE6pMRfSWRMkMS
|
|
||||||
YZYa+VNKhR4ixdj07ocFZEWLVjCH7kxkE8JZXKt8jKYmkWd0lS1QVjgaKlO6lRa3
|
|
||||||
q6SPJkhW6pvqobvcqVNXwi1XuzpZeEbuh0B7OTekFTTxx5g9XeDl56M8SVQ1KEhT
|
|
||||||
Q1t7H2Nba18WCB7cf+6PN0F0K0Jz1Kq7ZWaqEI/grX1m4RQuvNF5807sB/QKMO/Z
|
|
||||||
Gz3NXvHg5xTJRd/567lxPGkor0cE7qD1EZfmJ2HrBYXQ91bhgA7LToBuMZo6ZRXH
|
|
||||||
QfsanjbP4FPLMiGdQigLjj3A35L/f4sQOOVac/sRaFnm7pzcxsMvyVU/YtvGcjYE
|
|
||||||
xaOOVnamg661Wo0wksXoDjeSz/JIyyKO3Gwp1FSm2wGLjjy/Ehmqcqy8rvHuf07w
|
|
||||||
AUukhVtTNn4=
|
|
||||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
|
@ -1,57 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDKTCCAhGgAwIBAgIJAOWmjTS+OnTEMA0GCSqGSIb3DQEBCwUAMBcxFTATBgNV
|
|
||||||
BAMMDGludGVybWVkaWF0ZTAeFw0xNTA1MTgwOTAwNDBaFw0yMzA4MDQwOTAwNDBa
|
|
||||||
MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
|
||||||
AQoCggEBALlcwQJuzd+xH8QFgfJSn5tRlvhkldSX98cE7NiA602NBbnAVyUrkRXq
|
|
||||||
Ni75lgt0kwjYfA9z674m8WSVbgpLPintPCla9CYky1TH0keIs8Rz6cGWHryWEHiu
|
|
||||||
EDuljQynu2b3sAFuHu9nfWurbJwZnFakBKpdQ9m4EyOZCHC/jHYY7HacKSXg1Cki
|
|
||||||
we2ca0BWDrcqy8kLy0dZ5oC6IZG8O8drAK8f3f44CRYw59D3sOKBrKXaabpvyEcb
|
|
||||||
N7Wk2HDBVwHpUJo1reVwtbM8dhqQayYSD8oXnGpP3RQNu/e2rzlXRyq/BfcDY1JI
|
|
||||||
7TbC4t/7/N4EcPSpGsTcSOC9A7FpzvECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg
|
|
||||||
hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O
|
|
||||||
BBYEFCnwiEMMFZh7NhCr+qA8K0w4Q+AOMB8GA1UdIwQYMBaAFB0h1Evsaw2vfrmS
|
|
||||||
YuoCTmC4EE6ZMA0GCSqGSIb3DQEBCwUAA4IBAQAcFmHMaXRxyoNaeOowQ6iQWoZd
|
|
||||||
AUbvG7SHr7I6Pi2aqdqofsKWts7Ytm5WsS0M2nN+sW504houu0iCPeJJX8RQw2q4
|
|
||||||
CCcNOs9IXk+2uMzlpocHpv+yYoUiD5DxgWh7eghQMLyMpf8FX3Gy4VazeuXznHOM
|
|
||||||
4gE4L417xkDzYOzqVTp0FTyAPUv6G2euhNCD6TMru9REcRhYul+K9kocjA5tt2KG
|
|
||||||
MH6y28LXbLyq4YJUxSUU9gY/xlnbbZS48KDqEcdYC9zjW9nQ0qS+XQuQuFIcwjJ5
|
|
||||||
V4kAUYxDu6FoTpyQjgsrmBbZlKNxH7Nj4NDlcdJhp/zeSKHqWa5hSWjjKIxp
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDAjCCAeqgAwIBAgIJAOWmjTS+OnTDMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV
|
|
||||||
BAMMDXJvb3RhdXRob3JpdHkwHhcNMTUwNTE4MDkwMDQwWhcNMjMwODA0MDkwMDQw
|
|
||||||
WjAXMRUwEwYDVQQDDAxpbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IB
|
|
||||||
DwAwggEKAoIBAQDSrAO1CoPvUllgLOzDm5nG0skDF7vh1DUgAIDVGz0ecD0JFbQx
|
|
||||||
EF79pju/6MbtpTW2FYvRp11t/G7rGtX923ybOHY/1MNFQrdIvPlO1VV7IGKjoMwP
|
|
||||||
DNeb0fIGjHoE9QxaDxR8NX8xQbItpsw+TUtRfc9SLkR+jaYJfVRoM21BOncZbSHE
|
|
||||||
YKiZlEbpecB/+EtwVpgvl+8mPD5U07Fi4fp/lza3WXInXQPyiTVllIEJCt4PKmlu
|
|
||||||
MocNaJOW38bysL7i0PzDpVZtOxLHOTaW68yF3FckIHNCaA7k1ABEEEegjFMmIao7
|
|
||||||
B9w7A0jvr4jZVvNmui5Djjn+oJxwEVVgyf8LAgMBAAGjUDBOMB0GA1UdDgQWBBQd
|
|
||||||
IdRL7GsNr365kmLqAk5guBBOmTAfBgNVHSMEGDAWgBRk81s9d0ZbiZhh44KckwPb
|
|
||||||
oTc0XzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBZQTK0plfdB5PC
|
|
||||||
cC5icut4EmrByJa1RbU7ayuEE70e7hla6KVmVjVdCBGltI4jBYwfhKbRItHiAJ/8
|
|
||||||
x+XZKBG8DLPFuDb7lAa1ObhAYF7YThUFPQYaBhfzKcWrdmWDBFpvNv6E0Mm364dZ
|
|
||||||
e7Yxmbe5S4agkYPoxEzgEYmcUk9jbjdR6eTbs8laG169ljrECXfEU9RiAcqz5iSX
|
|
||||||
NLSewqB47hn3B9qgKcQn+PsgO2j7M+rfklhNgeGJeWmy7j6clSOuCsIjWHU0RLQ4
|
|
||||||
0W3SB/rpEAJ7fgQbYUPTIUNALSOWi/o1tDX2mXPRjBoxqAv7I+vYk1lZPmSzkyRh
|
|
||||||
FKvRDxsW
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDAzCCAeugAwIBAgIJAJ0MomS4Ck+8MA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV
|
|
||||||
BAMMDXJvb3RhdXRob3JpdHkwHhcNMTUwNTE4MDkwMDQwWhcNMjMwODA0MDkwMDQw
|
|
||||||
WjAYMRYwFAYDVQQDDA1yb290YXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
|
|
||||||
AQ8AMIIBCgKCAQEAts1ijtBV92S2cOvpUMOSTp9c6A34nIGr0T5Nhz6XiqRVT+gv
|
|
||||||
dQgmkdKJQjbvR60y6jzltYFsI2MpGVXY8h/oAL81D/k7PDB2aREgyBfTPAhBHyGw
|
|
||||||
siR+2xYt5b/Zs99q5RdRqQNzNpLPJriIKvUsRyQWy1UiG2s7pRXQeA8qB0XtJdCj
|
|
||||||
kFIi+G2bDsaffspGeDOCqt7t+yqvRXfSES0c/l7DIHaiMbbp4//ZNML3RNgAjPz2
|
|
||||||
hCezZ+wOYajOIyoSPK8IgICrhYFYxvgWxwbLDBEfC5B3jOQsySe10GoRAKZz1gBV
|
|
||||||
DmgReu81tYJmdgkc9zknnQtIFdA0ex+GvZlfWQIDAQABo1AwTjAdBgNVHQ4EFgQU
|
|
||||||
ZPNbPXdGW4mYYeOCnJMD26E3NF8wHwYDVR0jBBgwFoAUZPNbPXdGW4mYYeOCnJMD
|
|
||||||
26E3NF8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEATzkZ97K777uZ
|
|
||||||
lQcduNX3ey4IbCiEzFA2zO5Blj+ilfIwNbZXNOgm/lqNvVGDYs6J1apJJe30vL3X
|
|
||||||
J+t2zsZWzzQzb9uIU37zYemt6m0fHrSrx/iy5lGNqt3HMfqEcOqSCOIK3PCTMz2/
|
|
||||||
uyGe1iw33PVeWsm1JUybQ9IrU/huJjbgOHU4wab+8SJCM49ipArp68Fr6j4lcEaE
|
|
||||||
4rfRg1ZsvxiOyUB3qPn6wyL/JB8kOJ+QCBe498376eaem8AEFk0kQRh6hDaWtq/k
|
|
||||||
t6IIXQLjx+EBDVP/veK0UnVhKRP8YTOoV8ZiG1NcdlJmX/Uk7iAfevP7CkBfSN8W
|
|
||||||
r6AL284qtw==
|
|
||||||
-----END CERTIFICATE-----
|
|
|
@ -1,21 +1,29 @@
|
||||||
MIT License
|
BSD 3-Clause License
|
||||||
|
|
||||||
Copyright (c) 2017 The Angel Framework
|
Copyright (c) 2021, dukefirehawk.com
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Redistribution and use in source and binary forms, with or without
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
modification, are permitted provided that the following conditions are met:
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
copies or substantial portions of the Software.
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
this list of conditions and the following disclaimer in the documentation
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
and/or other materials provided with the distribution.
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
contributors may be used to endorse or promote products derived from
|
||||||
SOFTWARE.
|
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,26 +0,0 @@
|
||||||
Copyright 2017 dart_language_server authors
|
|
||||||
|
|
||||||
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,10 +1,11 @@
|
||||||
# jael
|
# JAEL3
|
||||||
[![Pub](https://img.shields.io/pub/v/jael.svg)](https://pub.dartlang.org/packages/jael)
|
|
||||||
[![build status](https://travis-ci.org/angel-dart/jael.svg)](https://travis-ci.org/angel-dart/jael)
|
![Pub Version (including pre-releases)](https://img.shields.io/pub/v/jael3?include_prereleases)
|
||||||
|
|
||||||
A simple server-side HTML templating engine for Dart.
|
A simple server-side HTML templating engine for Dart.
|
||||||
|
|
||||||
Though its syntax is but a superset of HTML, it supports features such as:
|
Though its syntax is but a superset of HTML, it supports features such as:
|
||||||
|
|
||||||
* **Custom elements**
|
* **Custom elements**
|
||||||
* Loops
|
* Loops
|
||||||
* Conditionals
|
* Conditionals
|
||||||
|
@ -13,22 +14,21 @@ Though its syntax is but a superset of HTML, it supports features such as:
|
||||||
* `switch` syntax
|
* `switch` syntax
|
||||||
* Interpolation of any Dart expression
|
* Interpolation of any Dart expression
|
||||||
|
|
||||||
Jael is a good choice for applications of any scale, especially when the development team is small,
|
Jael is a good choice for applications of any scale, especially when the development team is small, or the time invested in building an SPA would be too much.
|
||||||
or the time invested in building an SPA would be too much.
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
Each of the [packages within this repository](#this-repository) contains
|
|
||||||
some sort of documentation.
|
Each of the [packages within this repository](#this-repository) contains some sort of documentation.
|
||||||
|
|
||||||
Documentation for Jael syntax and directives has been
|
Documentation for Jael syntax and directives has been
|
||||||
**moved** to the
|
**moved** to the
|
||||||
[Angel framework wiki](https://docs.angel-dart.dev/packages/front-end/jael).
|
[Angel3 framework wiki](https://angel3-docs.dukefirehawk.com/packages/front-end/jael).
|
||||||
|
|
||||||
## This Repository
|
## This Repository
|
||||||
|
|
||||||
Within this repository are three packages:
|
Within this repository are three packages:
|
||||||
|
|
||||||
* `package:jael` - Contains the Jael parser, AST, and HTML renderer.
|
* `package:jael3` - Contains the Jael parser, AST, and HTML renderer.
|
||||||
* `package:jael_preprocessor` - Handles template inheritance, and facilitates the use of "compile-time" constructs.
|
* `package:jael3_preprocessor` - Handles template inheritance, and facilitates the use of "compile-time" constructs.
|
||||||
* `package:build_jael` - Uses `package:build` to compile Jael templates, therefore allowing speedy incremental builds to HTML files.
|
* `package:angel3_jael` - [Angel3](https://angel3-framework.web.app/) support for Jael.
|
||||||
* `package:angel_jael` - [Angel](https://angel-dart.github.io) support for Jael. Angel contains other
|
|
||||||
facilities to speed up application development, so something like Jael is right at home.
|
facilities to speed up application development, so something like Jael is right at home.
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel3_framework/http.dart';
|
import 'package:angel3_framework/http.dart';
|
||||||
import 'package:angel3_jael/angel3_jael.dart';
|
import 'package:angel3_jael/angel3_jael.dart';
|
||||||
import 'package:file/local.dart';
|
import 'package:file/local.dart';
|
||||||
import 'package:jael3/jael3.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
main() async {
|
main() async {
|
||||||
|
|
|
@ -23,9 +23,9 @@ dependencies:
|
||||||
The core `jael3` package exports classes for parsing Jael templates, an AST library, and a `Renderer` class that generates HTML on-the-fly.
|
The core `jael3` package exports classes for parsing Jael templates, an AST library, and a `Renderer` class that generates HTML on-the-fly.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:belatuk_code_buffer/code_buffer.dart';
|
import 'package:belatuk_code_buffer/belatuk_code_buffer.dart';
|
||||||
import 'package:belatuk_symbol_table/symbol_table.dart';
|
import 'package:belatuk_symbol_table/belatuk_symbol_table.dart';
|
||||||
import 'package:jael3/jael.dart' as jael;
|
import 'package:jael3/jael3.dart' as jael;
|
||||||
|
|
||||||
void myFunction() {
|
void myFunction() {
|
||||||
const template = '''
|
const template = '''
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
name: jael3
|
name: jael3
|
||||||
version: 4.2.0
|
version: 4.2.1
|
||||||
description: A simple server-side HTML templating engine for Dart. Comparable to Blade or Liquid.
|
description: A simple server-side HTML templating engine for Dart. Comparable to Blade or Liquid.
|
||||||
homepage: https://github.com/dukefirehawk/angel/tree/master/packages/jael/jael
|
homepage: https://angel3-framework.web.app/
|
||||||
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/jael/jael
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 4.0.3
|
||||||
|
|
||||||
|
* Removed debugging messages
|
||||||
|
|
||||||
## 4.0.2
|
## 4.0.2
|
||||||
|
|
||||||
* Updated linter to `package:lints`
|
* Updated linter to `package:lints`
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:angel3_model/angel3_model.dart';
|
|
||||||
import 'package:angel3_orm/angel3_orm.dart';
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
import 'package:angel3_orm/src/query.dart';
|
|
||||||
import 'package:angel3_serialize/angel3_serialize.dart';
|
import 'package:angel3_serialize/angel3_serialize.dart';
|
||||||
import 'package:optional/optional.dart';
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
|
|
|
@ -342,6 +342,8 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
||||||
Future<List<T>> delete(QueryExecutor executor) {
|
Future<List<T>> delete(QueryExecutor executor) {
|
||||||
var sql = compile({}, preamble: 'DELETE', withFields: false);
|
var sql = compile({}, preamble: 'DELETE', withFields: false);
|
||||||
|
|
||||||
|
//_log.fine("Delete Query = $sql");
|
||||||
|
|
||||||
if (_joins.isEmpty) {
|
if (_joins.isEmpty) {
|
||||||
return executor
|
return executor
|
||||||
.query(tableName, sql, substitutionValues,
|
.query(tableName, sql, substitutionValues,
|
||||||
|
@ -375,6 +377,8 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
||||||
var sql = compile({});
|
var sql = compile({});
|
||||||
sql = 'WITH $tableName as ($insertion RETURNING $returning) ' + sql;
|
sql = 'WITH $tableName as ($insertion RETURNING $returning) ' + sql;
|
||||||
|
|
||||||
|
//_log.fine("Insert Query = $sql");
|
||||||
|
|
||||||
return executor.query(tableName, sql, substitutionValues).then((it) {
|
return executor.query(tableName, sql, substitutionValues).then((it) {
|
||||||
// Return SQL execution results
|
// Return SQL execution results
|
||||||
return it.isEmpty ? Optional.empty() : deserialize(it.first);
|
return it.isEmpty ? Optional.empty() : deserialize(it.first);
|
||||||
|
@ -400,6 +404,8 @@ abstract class Query<T, Where extends QueryWhere> extends QueryBase<T> {
|
||||||
var sql = compile({});
|
var sql = compile({});
|
||||||
sql = 'WITH $tableName as ($updateSql RETURNING $returning) ' + sql;
|
sql = 'WITH $tableName as ($updateSql RETURNING $returning) ' + sql;
|
||||||
|
|
||||||
|
//_log.fine("Update Query = $sql");
|
||||||
|
|
||||||
return executor
|
return executor
|
||||||
.query(tableName, sql, substitutionValues)
|
.query(tableName, sql, substitutionValues)
|
||||||
.then((it) => deserializeList(it));
|
.then((it) => deserializeList(it));
|
||||||
|
|
|
@ -60,8 +60,8 @@ abstract class QueryBase<T> {
|
||||||
Future<List<T>> get(QueryExecutor executor) async {
|
Future<List<T>> get(QueryExecutor executor) async {
|
||||||
var sql = compile({});
|
var sql = compile({});
|
||||||
|
|
||||||
_log.fine('sql = $sql');
|
//_log.fine('sql = $sql');
|
||||||
_log.fine('substitutionValues = $substitutionValues');
|
//_log.fine('substitutionValues = $substitutionValues');
|
||||||
|
|
||||||
return executor.query(tableName, sql, substitutionValues).then((it) {
|
return executor.query(tableName, sql, substitutionValues).then((it) {
|
||||||
return deserializeList(it);
|
return deserializeList(it);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel3_orm
|
name: angel3_orm
|
||||||
version: 4.0.2
|
version: 4.0.3
|
||||||
description: Runtime support for Angel3 ORM. Includes base classes for queries.
|
description: Runtime support for Angel3 ORM. Includes base classes for queries.
|
||||||
homepage: https://angel3-framework.web.app/
|
homepage: https://angel3-framework.web.app/
|
||||||
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm
|
||||||
|
|
|
@ -18,4 +18,9 @@ dev_dependencies:
|
||||||
test: ^1.17.0
|
test: ^1.17.0
|
||||||
angel3_orm_test: ^3.0.0
|
angel3_orm_test: ^3.0.0
|
||||||
lints: ^1.0.0
|
lints: ^1.0.0
|
||||||
|
dependency_overrides:
|
||||||
|
angel3_orm_test:
|
||||||
|
path: ../angel_orm_test
|
||||||
|
angel3_orm:
|
||||||
|
path: ../angel_orm
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 3.2.0
|
||||||
|
|
||||||
|
* Added `package:postgres_pool` for connection pooling
|
||||||
|
|
||||||
## 3.1.0
|
## 3.1.0
|
||||||
|
|
||||||
* Updated linter to `package:lints`
|
* Updated linter to `package:lints`
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
[![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_postgres/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_postgres/LICENSE)
|
||||||
|
|
||||||
Postgresql support for Angel3 ORM. Supported version: 9, 10, 11 and 12.
|
Postgresql support for Angel3 ORM. Supported version: 10, 11, 12, 13 and 14
|
||||||
|
|
||||||
For documentation about the ORM, see [Developer Guide](https://angel3-docs.dukefirehawk.com/guides/orm)
|
For documentation about the ORM, see [Developer Guide](https://angel3-docs.dukefirehawk.com/guides/orm)
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
|
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
|
||||||
import 'package:postgres/postgres.dart';
|
import 'package:postgres_pool/postgres_pool.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
var executor = PostgreSqlExecutorPool(Platform.numberOfProcessors, () {
|
var executor = PostgreSqlPoolExecutor(PgPool(
|
||||||
return PostgreSQLConnection('localhost', 5432, 'orm_test',
|
PgEndpoint(
|
||||||
username: 'test', password: 'test123');
|
host: 'localhost',
|
||||||
});
|
port: 5432,
|
||||||
|
database: 'orm_test',
|
||||||
|
username: Platform.environment['POSTGRES_USERNAME'] ?? 'test',
|
||||||
|
password: Platform.environment['POSTGRES_PASSWORD'] ?? 'test123',
|
||||||
|
),
|
||||||
|
settings: PgPoolSettings()
|
||||||
|
..maxConnectionAge = Duration(hours: 1)
|
||||||
|
..concurrency = 5,
|
||||||
|
));
|
||||||
|
|
||||||
var rows = await executor.query('users', 'SELECT * FROM users', {});
|
var rows = await executor.query('users', 'SELECT * FROM users', {});
|
||||||
print(rows);
|
print(rows);
|
||||||
|
|
|
@ -1,171 +1,2 @@
|
||||||
import 'dart:async';
|
export 'src/orm_postgres.dart';
|
||||||
import 'dart:convert';
|
export 'src/orm_postgres_pool.dart';
|
||||||
import 'package:angel3_orm/angel3_orm.dart';
|
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:pool/pool.dart';
|
|
||||||
import 'package:postgres/postgres.dart';
|
|
||||||
|
|
||||||
/// A [QueryExecutor] that queries a PostgreSQL database.
|
|
||||||
class PostgreSqlExecutor extends QueryExecutor {
|
|
||||||
final PostgreSQLExecutionContext _connection;
|
|
||||||
|
|
||||||
/// An optional [Logger] to print information to.
|
|
||||||
late Logger logger;
|
|
||||||
|
|
||||||
PostgreSqlExecutor(this._connection, {Logger? logger}) {
|
|
||||||
if (logger != null) {
|
|
||||||
this.logger = logger;
|
|
||||||
} else {
|
|
||||||
this.logger = Logger('PostgreSqlExecutor');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The underlying connection.
|
|
||||||
PostgreSQLExecutionContext get connection => _connection;
|
|
||||||
|
|
||||||
/// Closes the connection.
|
|
||||||
Future close() {
|
|
||||||
if (_connection is PostgreSQLConnection) {
|
|
||||||
return (_connection as PostgreSQLConnection).close();
|
|
||||||
} else {
|
|
||||||
return Future.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<List>> query(
|
|
||||||
String tableName, String query, Map<String, dynamic> substitutionValues,
|
|
||||||
[List<String>? returningFields]) {
|
|
||||||
if (returningFields != null) {
|
|
||||||
var fields = returningFields.join(', ');
|
|
||||||
var returning = 'RETURNING $fields';
|
|
||||||
query = '$query $returning';
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.fine('Query: $query');
|
|
||||||
logger.fine('Values: $substitutionValues');
|
|
||||||
|
|
||||||
// Convert List into String
|
|
||||||
var param = <String, dynamic>{};
|
|
||||||
substitutionValues.forEach((key, value) {
|
|
||||||
if (value is List) {
|
|
||||||
param[key] = jsonEncode(value);
|
|
||||||
} else {
|
|
||||||
param[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return _connection.query(query, substitutionValues: param);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
|
|
||||||
if (_connection is! PostgreSQLConnection) {
|
|
||||||
return await f(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
var conn = _connection as PostgreSQLConnection;
|
|
||||||
T? returnValue;
|
|
||||||
|
|
||||||
var txResult = await conn.transaction((ctx) async {
|
|
||||||
try {
|
|
||||||
logger.fine('Entering transaction');
|
|
||||||
var tx = PostgreSqlExecutor(ctx, logger: logger);
|
|
||||||
returnValue = await f(tx);
|
|
||||||
|
|
||||||
return returnValue;
|
|
||||||
} catch (e) {
|
|
||||||
ctx.cancelTransaction(reason: e.toString());
|
|
||||||
rethrow;
|
|
||||||
} finally {
|
|
||||||
logger.fine('Exiting transaction');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (txResult is PostgreSQLRollback) {
|
|
||||||
//if (txResult.reason == null) {
|
|
||||||
// throw StateError('The transaction was cancelled.');
|
|
||||||
//} else {
|
|
||||||
throw StateError(
|
|
||||||
'The transaction was cancelled with reason "${txResult.reason}".');
|
|
||||||
//}
|
|
||||||
} else {
|
|
||||||
return returnValue!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [QueryExecutor] that manages a pool of PostgreSQL connections.
|
|
||||||
class PostgreSqlExecutorPool extends QueryExecutor {
|
|
||||||
/// The maximum amount of concurrent connections.
|
|
||||||
final int size;
|
|
||||||
|
|
||||||
/// Creates a new [PostgreSQLConnection], on demand.
|
|
||||||
///
|
|
||||||
/// The created connection should **not** be open.
|
|
||||||
final PostgreSQLConnection Function() connectionFactory;
|
|
||||||
|
|
||||||
/// An optional [Logger] to print information to.
|
|
||||||
late Logger logger;
|
|
||||||
|
|
||||||
final List<PostgreSqlExecutor> _connections = [];
|
|
||||||
int _index = 0;
|
|
||||||
final Pool _pool, _connMutex = Pool(1);
|
|
||||||
|
|
||||||
PostgreSqlExecutorPool(this.size, this.connectionFactory, {Logger? logger})
|
|
||||||
: _pool = Pool(size) {
|
|
||||||
if (logger != null) {
|
|
||||||
this.logger = logger;
|
|
||||||
} else {
|
|
||||||
this.logger = Logger('PostgreSqlExecutorPool');
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(size > 0, 'Connection pool cannot be empty.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Closes all connections.
|
|
||||||
Future close() async {
|
|
||||||
await _pool.close();
|
|
||||||
await _connMutex.close();
|
|
||||||
return Future.wait(_connections.map((c) => c.close()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _open() async {
|
|
||||||
if (_connections.isEmpty) {
|
|
||||||
_connections.addAll(await Future.wait(List.generate(size, (_) {
|
|
||||||
logger.fine('Spawning connections...');
|
|
||||||
var conn = connectionFactory();
|
|
||||||
return conn
|
|
||||||
.open()
|
|
||||||
.then((_) => PostgreSqlExecutor(conn, logger: logger));
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<PostgreSqlExecutor> _next() {
|
|
||||||
return _connMutex.withResource(() async {
|
|
||||||
await _open();
|
|
||||||
if (_index >= size) _index = 0;
|
|
||||||
return _connections[_index++];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<List<List>> query(
|
|
||||||
String tableName, String query, Map<String, dynamic> substitutionValues,
|
|
||||||
[List<String>? returningFields]) {
|
|
||||||
return _pool.withResource(() async {
|
|
||||||
var executor = await _next();
|
|
||||||
return executor.query(
|
|
||||||
tableName, query, substitutionValues, returningFields);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) {
|
|
||||||
return _pool.withResource(() async {
|
|
||||||
var executor = await _next();
|
|
||||||
return executor.transaction(f);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
169
packages/orm/angel_orm_postgres/lib/src/orm_postgres.dart
Normal file
169
packages/orm/angel_orm_postgres/lib/src/orm_postgres.dart
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:pool/pool.dart';
|
||||||
|
import 'package:postgres/postgres.dart';
|
||||||
|
|
||||||
|
/// A [QueryExecutor] that queries a PostgreSQL database.
|
||||||
|
class PostgreSqlExecutor extends QueryExecutor {
|
||||||
|
final PostgreSQLExecutionContext _connection;
|
||||||
|
|
||||||
|
/// An optional [Logger] to print information to.
|
||||||
|
late Logger logger;
|
||||||
|
|
||||||
|
PostgreSqlExecutor(this._connection, {Logger? logger}) {
|
||||||
|
this.logger = logger ?? Logger('PostgreSqlExecutor');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The underlying connection.
|
||||||
|
PostgreSQLExecutionContext get connection => _connection;
|
||||||
|
|
||||||
|
/// Closes the connection.
|
||||||
|
Future close() {
|
||||||
|
if (_connection is PostgreSQLConnection) {
|
||||||
|
return (_connection as PostgreSQLConnection).close();
|
||||||
|
} else {
|
||||||
|
return Future.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PostgreSQLResult> query(
|
||||||
|
String tableName, String query, Map<String, dynamic> substitutionValues,
|
||||||
|
[List<String>? returningFields]) {
|
||||||
|
if (returningFields != null && returningFields.isNotEmpty) {
|
||||||
|
var fields = returningFields.join(', ');
|
||||||
|
var returning = 'RETURNING $fields';
|
||||||
|
query = '$query $returning';
|
||||||
|
}
|
||||||
|
|
||||||
|
//logger.fine('Query: $query');
|
||||||
|
//logger.fine('Values: $substitutionValues');
|
||||||
|
|
||||||
|
// Convert List into String
|
||||||
|
var param = <String, dynamic>{};
|
||||||
|
substitutionValues.forEach((key, value) {
|
||||||
|
if (value is List) {
|
||||||
|
param[key] = jsonEncode(value);
|
||||||
|
} else {
|
||||||
|
param[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return _connection.query(query, substitutionValues: param);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
|
||||||
|
if (_connection is! PostgreSQLConnection) {
|
||||||
|
return await f(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn = _connection as PostgreSQLConnection;
|
||||||
|
T? returnValue;
|
||||||
|
|
||||||
|
var txResult = await conn.transaction((ctx) async {
|
||||||
|
try {
|
||||||
|
logger.fine('Entering transaction');
|
||||||
|
var tx = PostgreSqlExecutor(ctx, logger: logger);
|
||||||
|
returnValue = await f(tx);
|
||||||
|
|
||||||
|
return returnValue;
|
||||||
|
} catch (e) {
|
||||||
|
ctx.cancelTransaction(reason: e.toString());
|
||||||
|
rethrow;
|
||||||
|
} finally {
|
||||||
|
logger.fine('Exiting transaction');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (txResult is PostgreSQLRollback) {
|
||||||
|
//if (txResult.reason == null) {
|
||||||
|
// throw StateError('The transaction was cancelled.');
|
||||||
|
//} else {
|
||||||
|
throw StateError(
|
||||||
|
'The transaction was cancelled with reason "${txResult.reason}".');
|
||||||
|
//}
|
||||||
|
} else {
|
||||||
|
return returnValue!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [QueryExecutor] that manages a pool of PostgreSQL connections.
|
||||||
|
class PostgreSqlExecutorPool extends QueryExecutor {
|
||||||
|
/// The maximum amount of concurrent connections.
|
||||||
|
final int size;
|
||||||
|
|
||||||
|
/// Creates a new [PostgreSQLConnection], on demand.
|
||||||
|
///
|
||||||
|
/// The created connection should **not** be open.
|
||||||
|
final PostgreSQLConnection Function() connectionFactory;
|
||||||
|
|
||||||
|
/// An optional [Logger] to print information to.
|
||||||
|
late Logger logger;
|
||||||
|
|
||||||
|
final List<PostgreSqlExecutor> _connections = [];
|
||||||
|
int _index = 0;
|
||||||
|
final Pool _pool, _connMutex = Pool(1);
|
||||||
|
|
||||||
|
PostgreSqlExecutorPool(this.size, this.connectionFactory, {Logger? logger})
|
||||||
|
: _pool = Pool(size) {
|
||||||
|
if (logger != null) {
|
||||||
|
this.logger = logger;
|
||||||
|
} else {
|
||||||
|
this.logger = Logger('PostgreSqlExecutorPool');
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(size > 0, 'Connection pool cannot be empty.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Closes all connections.
|
||||||
|
Future close() async {
|
||||||
|
await _pool.close();
|
||||||
|
await _connMutex.close();
|
||||||
|
return Future.wait(_connections.map((c) => c.close()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _open() async {
|
||||||
|
if (_connections.isEmpty) {
|
||||||
|
_connections.addAll(await Future.wait(List.generate(size, (_) async {
|
||||||
|
logger.fine('Spawning connections...');
|
||||||
|
var conn = connectionFactory();
|
||||||
|
await conn.open();
|
||||||
|
//return conn
|
||||||
|
// .open()
|
||||||
|
// .then((_) => PostgreSqlExecutor(conn, logger: logger));
|
||||||
|
return PostgreSqlExecutor(conn, logger: logger);
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PostgreSqlExecutor> _next() {
|
||||||
|
return _connMutex.withResource(() async {
|
||||||
|
await _open();
|
||||||
|
if (_index >= size) _index = 0;
|
||||||
|
return _connections[_index++];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<PostgreSQLResult> query(
|
||||||
|
String tableName, String query, Map<String, dynamic> substitutionValues,
|
||||||
|
[List<String>? returningFields]) {
|
||||||
|
return _pool.withResource(() async {
|
||||||
|
var executor = await _next();
|
||||||
|
return executor.query(
|
||||||
|
tableName, query, substitutionValues, returningFields);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) {
|
||||||
|
return _pool.withResource(() async {
|
||||||
|
var executor = await _next();
|
||||||
|
return executor.transaction(f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:postgres_pool/postgres_pool.dart';
|
||||||
|
|
||||||
|
import '../angel3_orm_postgres.dart';
|
||||||
|
|
||||||
|
/// A [QueryExecutor] that uses `package:postgres_pool` for connetions pooling.
|
||||||
|
class PostgreSqlPoolExecutor extends QueryExecutor {
|
||||||
|
final PgPool _pool;
|
||||||
|
|
||||||
|
/// An optional [Logger] to print information to.
|
||||||
|
late Logger logger;
|
||||||
|
|
||||||
|
PostgreSqlPoolExecutor(this._pool, {Logger? logger}) {
|
||||||
|
this.logger = logger ?? Logger('PostgreSqlPoolExecutor');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The underlying connection pooling.
|
||||||
|
PgPool get pool => _pool;
|
||||||
|
|
||||||
|
/// Closes all the connections in the pool.
|
||||||
|
Future<dynamic> close() {
|
||||||
|
return _pool.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run query.
|
||||||
|
@override
|
||||||
|
Future<PostgreSQLResult> query(
|
||||||
|
String tableName, String query, Map<String, dynamic> substitutionValues,
|
||||||
|
[List<String> returningFields = const []]) {
|
||||||
|
if (returningFields.isNotEmpty) {
|
||||||
|
var fields = returningFields.join(', ');
|
||||||
|
var returning = 'RETURNING $fields';
|
||||||
|
query = '$query $returning';
|
||||||
|
}
|
||||||
|
|
||||||
|
//logger.fine('Query: $query');
|
||||||
|
//logger.fine('Values: $substitutionValues');
|
||||||
|
|
||||||
|
// Convert List into String
|
||||||
|
var param = <String, dynamic>{};
|
||||||
|
substitutionValues.forEach((key, value) {
|
||||||
|
if (value is List) {
|
||||||
|
param[key] = jsonEncode(value);
|
||||||
|
} else {
|
||||||
|
param[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return _pool.run<PostgreSQLResult>((pgContext) async {
|
||||||
|
return await pgContext.query(query, substitutionValues: param);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run query in a transaction.
|
||||||
|
@override
|
||||||
|
Future<T> transaction<T>(FutureOr<T> Function(QueryExecutor) f) async {
|
||||||
|
return _pool.runTx((pgContext) async {
|
||||||
|
var exec = PostgreSqlExecutor(pgContext, logger: logger);
|
||||||
|
return await f(exec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel3_orm_postgres
|
name: angel3_orm_postgres
|
||||||
version: 3.1.0
|
version: 3.2.0
|
||||||
description: PostgreSQL support for Angel3 ORM. Includes functionality for querying and transactions.
|
description: PostgreSQL support for Angel3 ORM. Includes functionality for querying and transactions.
|
||||||
homepage: https://angel3-framework.web.app/
|
homepage: https://angel3-framework.web.app/
|
||||||
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_postgres
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_postgres
|
||||||
|
@ -10,8 +10,14 @@ dependencies:
|
||||||
logging: ^1.0.1
|
logging: ^1.0.1
|
||||||
pool: ^1.5.0
|
pool: ^1.5.0
|
||||||
postgres: ^2.4.1
|
postgres: ^2.4.1
|
||||||
|
postgres_pool: ^2.1.3
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
belatuk_pretty_logging: ^4.0.0
|
belatuk_pretty_logging: ^4.0.0
|
||||||
angel3_orm_test: ^3.0.0
|
angel3_orm_test: ^3.0.0
|
||||||
test: ^1.17.5
|
test: ^1.17.5
|
||||||
lints: ^1.0.0
|
lints: ^1.0.0
|
||||||
|
#dependency_overrides:
|
||||||
|
# angel3_orm_test:
|
||||||
|
# path: ../angel_orm_test
|
||||||
|
# angel3_orm:
|
||||||
|
# path: ../angel_orm
|
||||||
|
|
|
@ -9,6 +9,9 @@ void main() {
|
||||||
..level = Level.ALL
|
..level = Level.ALL
|
||||||
..onRecord.listen(prettyLog);
|
..onRecord.listen(prettyLog);
|
||||||
|
|
||||||
|
//group('performance',
|
||||||
|
// () => performanceTests(pg(['performance']), close: closePg));
|
||||||
|
|
||||||
group('postgresql', () {
|
group('postgresql', () {
|
||||||
group('belongsTo',
|
group('belongsTo',
|
||||||
() => belongsToTests(pg(['author', 'book']), close: closePg));
|
() => belongsToTests(pg(['author', 'book']), close: closePg));
|
||||||
|
|
|
@ -3,14 +3,28 @@ import 'dart:io';
|
||||||
import 'package:angel3_orm/angel3_orm.dart';
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
|
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:postgres/postgres.dart';
|
import 'package:postgres_pool/postgres_pool.dart';
|
||||||
|
|
||||||
FutureOr<QueryExecutor> Function() pg(Iterable<String> schemas) {
|
FutureOr<QueryExecutor> Function() pg(Iterable<String> schemas) {
|
||||||
|
// Use single connection
|
||||||
return () => connectToPostgres(schemas);
|
return () => connectToPostgres(schemas);
|
||||||
|
|
||||||
|
// Use connection pooling with 1 connection
|
||||||
|
//return () => connectToPostgresPool(schemas);
|
||||||
|
|
||||||
|
// Use PostgreSqlExecutorPool (Not working)
|
||||||
|
//return () => connectToPostgresPool1(schemas);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> closePg(QueryExecutor executor) =>
|
Future<void> closePg(QueryExecutor executor) async {
|
||||||
(executor as PostgreSqlExecutor).close();
|
if (executor is PostgreSqlExecutor) {
|
||||||
|
await executor.close();
|
||||||
|
//} else if (executor is PostgreSqlExecutorPool) {
|
||||||
|
// await executor.close();
|
||||||
|
} else if (executor is PostgreSqlPoolExecutor) {
|
||||||
|
await executor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<PostgreSqlExecutor> connectToPostgres(Iterable<String> schemas) async {
|
Future<PostgreSqlExecutor> connectToPostgres(Iterable<String> schemas) async {
|
||||||
var conn = PostgreSQLConnection('127.0.0.1', 5432, 'orm_test',
|
var conn = PostgreSQLConnection('127.0.0.1', 5432, 'orm_test',
|
||||||
|
@ -25,3 +39,47 @@ Future<PostgreSqlExecutor> connectToPostgres(Iterable<String> schemas) async {
|
||||||
|
|
||||||
return PostgreSqlExecutor(conn, logger: Logger.root);
|
return PostgreSqlExecutor(conn, logger: Logger.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<PostgreSqlExecutorPool> connectToPostgresPool1(
|
||||||
|
Iterable<String> schemas) async {
|
||||||
|
PostgreSQLConnection connectionFactory() {
|
||||||
|
return PostgreSQLConnection('127.0.0.1', 5432, 'orm_test',
|
||||||
|
username: Platform.environment['POSTGRES_USERNAME'] ?? 'test',
|
||||||
|
password: Platform.environment['POSTGRES_PASSWORD'] ?? 'test123');
|
||||||
|
}
|
||||||
|
|
||||||
|
PostgreSQLConnection conn = connectionFactory();
|
||||||
|
await conn.open();
|
||||||
|
|
||||||
|
// Run sql to create the tables
|
||||||
|
for (var s in schemas) {
|
||||||
|
await conn.execute(await File('test/migrations/$s.sql').readAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return PostgreSqlExecutorPool(5, connectionFactory, logger: Logger.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PostgreSqlPoolExecutor> connectToPostgresPool(
|
||||||
|
Iterable<String> schemas) async {
|
||||||
|
var _pool = PgPool(
|
||||||
|
PgEndpoint(
|
||||||
|
host: 'localhost',
|
||||||
|
port: 5432,
|
||||||
|
database: 'orm_test',
|
||||||
|
username: Platform.environment['POSTGRES_USERNAME'] ?? 'test',
|
||||||
|
password: Platform.environment['POSTGRES_PASSWORD'] ?? 'test123',
|
||||||
|
),
|
||||||
|
settings: PgPoolSettings()
|
||||||
|
..maxConnectionAge = Duration(hours: 1)
|
||||||
|
..concurrency = 200,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Run sql to create the tables in a transaction
|
||||||
|
//await _pool.runTx((conn) async {
|
||||||
|
// for (var s in schemas) {
|
||||||
|
// await conn.execute(await File('test/migrations/$s.sql').readAsString());
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
|
||||||
|
return PostgreSqlPoolExecutor(_pool, logger: Logger.root);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
CREATE TEMPORARY TABLE "world" (
|
||||||
|
id serial NOT NULL,
|
||||||
|
randomNumber integer NOT NULL default 0,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE "fortune" (
|
||||||
|
id serial NOT NULL,
|
||||||
|
message varchar(2048) NOT NULL,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
|
@ -1,5 +1,10 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## 3.0.3
|
||||||
|
|
||||||
|
* Added `performance_test` test cases
|
||||||
|
* Update `edge_case_test` test case to support connection pooling
|
||||||
|
|
||||||
## 3.0.2
|
## 3.0.2
|
||||||
|
|
||||||
* Updated linter to `package:lints`
|
* Updated linter to `package:lints`
|
||||||
|
|
|
@ -7,3 +7,4 @@ export 'src/has_map_test.dart';
|
||||||
export 'src/has_one_test.dart';
|
export 'src/has_one_test.dart';
|
||||||
export 'src/many_to_many_test.dart';
|
export 'src/many_to_many_test.dart';
|
||||||
export 'src/standalone_test.dart';
|
export 'src/standalone_test.dart';
|
||||||
|
export 'src/performance_test.dart';
|
||||||
|
|
|
@ -42,12 +42,12 @@ void belongsToTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
expect(books, hasLength(1));
|
expect(books, hasLength(1));
|
||||||
|
|
||||||
var book = books.first;
|
var book = books.first;
|
||||||
print(book.toJson());
|
//print(book.toJson());
|
||||||
expect(book.id, deathlyHallows!.id);
|
expect(book.id, deathlyHallows!.id);
|
||||||
expect(book.name, deathlyHallows!.name);
|
expect(book.name, deathlyHallows!.name);
|
||||||
|
|
||||||
var author = book.author!;
|
var author = book.author!;
|
||||||
print(AuthorSerializer.toMap(author));
|
//print(AuthorSerializer.toMap(author));
|
||||||
expect(author.id, jkRowling!.id);
|
expect(author.id, jkRowling!.id);
|
||||||
expect(author.name, jkRowling!.name);
|
expect(author.name, jkRowling!.name);
|
||||||
});
|
});
|
||||||
|
@ -55,17 +55,17 @@ void belongsToTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
test('select one', () async {
|
test('select one', () async {
|
||||||
var query = BookQuery();
|
var query = BookQuery();
|
||||||
query.where!.id.equals(int.parse(deathlyHallows!.id!));
|
query.where!.id.equals(int.parse(deathlyHallows!.id!));
|
||||||
print(query.compile({}));
|
//print(query.compile({}));
|
||||||
|
|
||||||
var bookOpt = await query.getOne(executor);
|
var bookOpt = await query.getOne(executor);
|
||||||
expect(bookOpt.isPresent, true);
|
expect(bookOpt.isPresent, true);
|
||||||
bookOpt.ifPresent((book) {
|
bookOpt.ifPresent((book) {
|
||||||
print(book.toJson());
|
//print(book.toJson());
|
||||||
expect(book.id, deathlyHallows!.id);
|
expect(book.id, deathlyHallows!.id);
|
||||||
expect(book.name, deathlyHallows!.name);
|
expect(book.name, deathlyHallows!.name);
|
||||||
|
|
||||||
var author = book.author!;
|
var author = book.author!;
|
||||||
print(AuthorSerializer.toMap(author));
|
//print(AuthorSerializer.toMap(author));
|
||||||
expect(author.id, jkRowling!.id);
|
expect(author.id, jkRowling!.id);
|
||||||
expect(author.name, jkRowling!.name);
|
expect(author.name, jkRowling!.name);
|
||||||
});
|
});
|
||||||
|
@ -75,18 +75,18 @@ void belongsToTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var query = BookQuery()
|
var query = BookQuery()
|
||||||
..where!.name.equals('Goblet of Fire')
|
..where!.name.equals('Goblet of Fire')
|
||||||
..orWhere((w) => w.authorId.equals(int.parse(jkRowling!.id!)));
|
..orWhere((w) => w.authorId.equals(int.parse(jkRowling!.id!)));
|
||||||
print(query.compile({}));
|
//print(query.compile({}));
|
||||||
|
|
||||||
var books = await query.get(executor);
|
var books = await query.get(executor);
|
||||||
expect(books, hasLength(1));
|
expect(books, hasLength(1));
|
||||||
|
|
||||||
var book = books.first;
|
var book = books.first;
|
||||||
print(book.toJson());
|
//print(book.toJson());
|
||||||
expect(book.id, deathlyHallows!.id);
|
expect(book.id, deathlyHallows!.id);
|
||||||
expect(book.name, deathlyHallows!.name);
|
expect(book.name, deathlyHallows!.name);
|
||||||
|
|
||||||
var author = book.author!;
|
var author = book.author!;
|
||||||
print(AuthorSerializer.toMap(author));
|
//print(AuthorSerializer.toMap(author));
|
||||||
expect(author.id, jkRowling!.id);
|
expect(author.id, jkRowling!.id);
|
||||||
expect(author.name, jkRowling!.name);
|
expect(author.name, jkRowling!.name);
|
||||||
});
|
});
|
||||||
|
@ -99,18 +99,18 @@ void belongsToTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
query1
|
query1
|
||||||
..union(query2)
|
..union(query2)
|
||||||
..unionAll(query3);
|
..unionAll(query3);
|
||||||
print(query1.compile({}));
|
//print(query1.compile({}));
|
||||||
|
|
||||||
var books = await query1.get(executor);
|
var books = await query1.get(executor);
|
||||||
expect(books, hasLength(1));
|
expect(books, hasLength(1));
|
||||||
|
|
||||||
var book = books.first;
|
var book = books.first;
|
||||||
print(book.toJson());
|
//print(book.toJson());
|
||||||
expect(book.id, deathlyHallows!.id);
|
expect(book.id, deathlyHallows!.id);
|
||||||
expect(book.name, deathlyHallows!.name);
|
expect(book.name, deathlyHallows!.name);
|
||||||
|
|
||||||
var author = book.author!;
|
var author = book.author!;
|
||||||
print(AuthorSerializer.toMap(author));
|
//print(AuthorSerializer.toMap(author));
|
||||||
expect(author.id, jkRowling!.id);
|
expect(author.id, jkRowling!.id);
|
||||||
expect(author.name, jkRowling!.name);
|
expect(author.name, jkRowling!.name);
|
||||||
});
|
});
|
||||||
|
@ -129,9 +129,9 @@ void belongsToTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
});
|
});
|
||||||
|
|
||||||
test('delete stream', () async {
|
test('delete stream', () async {
|
||||||
printSeparator('Delete stream test');
|
//printSeparator('Delete stream test');
|
||||||
var query = BookQuery()..where!.name.equals(deathlyHallows!.name!);
|
var query = BookQuery()..where!.name.equals(deathlyHallows!.name!);
|
||||||
print(query.compile({}, preamble: 'DELETE', withFields: false));
|
//print(query.compile({}, preamble: 'DELETE', withFields: false));
|
||||||
var books = await query.delete(executor);
|
var books = await query.delete(executor);
|
||||||
expect(books, hasLength(1));
|
expect(books, hasLength(1));
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ void belongsToTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var bookOpt = await (query.updateOne(executor));
|
var bookOpt = await (query.updateOne(executor));
|
||||||
expect(bookOpt.isPresent, true);
|
expect(bookOpt.isPresent, true);
|
||||||
bookOpt.ifPresent((book) {
|
bookOpt.ifPresent((book) {
|
||||||
print(book.toJson());
|
//print(book.toJson());
|
||||||
expect(book.name, cloned.name);
|
expect(book.name, cloned.name);
|
||||||
expect(book.author, isNotNull);
|
expect(book.author, isNotNull);
|
||||||
expect(book.author!.name, jkRowling!.name);
|
expect(book.author!.name, jkRowling!.name);
|
||||||
|
|
|
@ -15,11 +15,11 @@ void edgeCaseTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
tearDown(() => close!(executor));
|
tearDown(() => close!(executor));
|
||||||
|
|
||||||
test('can create object with no id', () async {
|
test('can create object with no id', () async {
|
||||||
var query = UnorthodoxQuery()..values.name = 'Hey';
|
var query = UnorthodoxQuery()..values.name = 'World';
|
||||||
var modelOpt = await query.insert(executor);
|
var modelOpt = await query.insert(executor);
|
||||||
expect(modelOpt.isPresent, true);
|
expect(modelOpt.isPresent, true);
|
||||||
modelOpt.ifPresent((model) {
|
modelOpt.ifPresent((model) {
|
||||||
expect(model, Unorthodox(name: 'Hey'));
|
expect(model, Unorthodox(name: 'World'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,12 +27,14 @@ void edgeCaseTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
Unorthodox? unorthodox;
|
Unorthodox? unorthodox;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
|
//if (unorthodox == null) {
|
||||||
var query = UnorthodoxQuery()..values.name = 'Hey';
|
var query = UnorthodoxQuery()..values.name = 'Hey';
|
||||||
|
|
||||||
var unorthodoxOpt = await query.insert(executor);
|
var unorthodoxOpt = await query.insert(executor);
|
||||||
unorthodoxOpt.ifPresent((value) {
|
unorthodoxOpt.ifPresent((value) {
|
||||||
unorthodox = value;
|
unorthodox = value;
|
||||||
});
|
});
|
||||||
|
//}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('belongs to', () async {
|
test('belongs to', () async {
|
||||||
|
@ -40,7 +42,7 @@ void edgeCaseTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var modelOpt = await query.insert(executor);
|
var modelOpt = await query.insert(executor);
|
||||||
expect(modelOpt.isPresent, true);
|
expect(modelOpt.isPresent, true);
|
||||||
modelOpt.ifPresent((model) {
|
modelOpt.ifPresent((model) {
|
||||||
print(model.toJson());
|
//print(model.toJson());
|
||||||
expect(model.id, isNotNull); // Postgres should set this.
|
expect(model.id, isNotNull); // Postgres should set this.
|
||||||
expect(model.unorthodox, unorthodox);
|
expect(model.unorthodox, unorthodox);
|
||||||
});
|
});
|
||||||
|
@ -73,7 +75,7 @@ void edgeCaseTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var wjOpt = await query.getOne(executor);
|
var wjOpt = await query.getOne(executor);
|
||||||
expect(wjOpt.isPresent, true);
|
expect(wjOpt.isPresent, true);
|
||||||
wjOpt.ifPresent((wj) {
|
wjOpt.ifPresent((wj) {
|
||||||
print(wj.toJson());
|
//print(wj.toJson());
|
||||||
expect(wj.song, girlBlue);
|
expect(wj.song, girlBlue);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -96,7 +98,7 @@ void edgeCaseTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var wjObj = await query.getOne(executor);
|
var wjObj = await query.getOne(executor);
|
||||||
expect(wjObj.isPresent, true);
|
expect(wjObj.isPresent, true);
|
||||||
wjObj.ifPresent((wj) {
|
wjObj.ifPresent((wj) {
|
||||||
print(wj.toJson());
|
//print(wj.toJson());
|
||||||
expect(wj.numbas, numbas);
|
expect(wj.numbas, numbas);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -114,8 +116,8 @@ void edgeCaseTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var fooOpt = await fooQuery.getOne(executor);
|
var fooOpt = await fooQuery.getOne(executor);
|
||||||
expect(fooOpt.isPresent, true);
|
expect(fooOpt.isPresent, true);
|
||||||
fooOpt.ifPresent((foo) {
|
fooOpt.ifPresent((foo) {
|
||||||
print(foo.toJson());
|
//print(foo.toJson());
|
||||||
print(weirdJoin!.toJson());
|
//print(weirdJoin!.toJson());
|
||||||
expect(foo.weirdJoins![0].id, weirdJoin!.id);
|
expect(foo.weirdJoins![0].id, weirdJoin!.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,7 +29,7 @@ void hasManyTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
Fruit? apple, banana;
|
Fruit? apple, banana;
|
||||||
|
|
||||||
void verify(Tree tree) {
|
void verify(Tree tree) {
|
||||||
print(tree.fruits!.map(FruitSerializer.toMap).toList());
|
//print(tree.fruits!.map(FruitSerializer.toMap).toList());
|
||||||
expect(tree.fruits, hasLength(2));
|
expect(tree.fruits, hasLength(2));
|
||||||
expect(tree.fruits![0].commonName, apple!.commonName);
|
expect(tree.fruits![0].commonName, apple!.commonName);
|
||||||
expect(tree.fruits![1].commonName, banana!.commonName);
|
expect(tree.fruits![1].commonName, banana!.commonName);
|
||||||
|
|
|
@ -22,10 +22,10 @@ void hasMapTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var modelOpt = await (query.insert(executor));
|
var modelOpt = await (query.insert(executor));
|
||||||
expect(modelOpt.isPresent, true);
|
expect(modelOpt.isPresent, true);
|
||||||
modelOpt.ifPresent((model) {
|
modelOpt.ifPresent((model) {
|
||||||
print(model.toString());
|
//print(model.toString());
|
||||||
|
|
||||||
var data = HasMap(value: {'foo': 'bar'}, list: ['1', 2, 3.0]);
|
var data = HasMap(value: {'foo': 'bar'}, list: ['1', 2, 3.0]);
|
||||||
print(data.toString());
|
//print(data.toString());
|
||||||
|
|
||||||
expect(model, data);
|
expect(model, data);
|
||||||
});
|
});
|
||||||
|
@ -40,7 +40,7 @@ void hasMapTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
expect(modelOpt.isPresent, true);
|
expect(modelOpt.isPresent, true);
|
||||||
if (modelOpt.isPresent) {
|
if (modelOpt.isPresent) {
|
||||||
var model = modelOpt.value;
|
var model = modelOpt.value;
|
||||||
print(model.toJson());
|
//print(model.toJson());
|
||||||
query = HasMapQuery()..values.copyFrom(model);
|
query = HasMapQuery()..values.copyFrom(model);
|
||||||
var result = await query.updateOne(executor);
|
var result = await query.updateOne(executor);
|
||||||
expect(result.isPresent, true);
|
expect(result.isPresent, true);
|
||||||
|
@ -83,7 +83,7 @@ void hasMapTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
|
|
||||||
query.where?.list.equals(['1', 2, 3.0]);
|
query.where?.list.equals(['1', 2, 3.0]);
|
||||||
|
|
||||||
print(query.substitutionValues);
|
//print(query.substitutionValues);
|
||||||
|
|
||||||
var result = await query.get(executor);
|
var result = await query.get(executor);
|
||||||
expect(result, [initialValue]);
|
expect(result, [initialValue]);
|
||||||
|
|
|
@ -18,12 +18,12 @@ void hasOneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
tearDown(() => close!(executor));
|
tearDown(() => close!(executor));
|
||||||
|
|
||||||
test('sets to null if no child', () async {
|
test('sets to null if no child', () async {
|
||||||
print(LegQuery().compile({}));
|
//print(LegQuery().compile({}));
|
||||||
var query = LegQuery()..where!.id.equals(int.parse(originalLeg!.id!));
|
var query = LegQuery()..where!.id.equals(int.parse(originalLeg!.id!));
|
||||||
var legOpt = await (query.getOne(executor));
|
var legOpt = await (query.getOne(executor));
|
||||||
expect(legOpt.isPresent, true);
|
expect(legOpt.isPresent, true);
|
||||||
legOpt.ifPresent((leg) {
|
legOpt.ifPresent((leg) {
|
||||||
print(leg.toJson());
|
//print(leg.toJson());
|
||||||
expect(leg.name, originalLeg?.name);
|
expect(leg.name, originalLeg?.name);
|
||||||
expect(leg.id, originalLeg?.id);
|
expect(leg.id, originalLeg?.id);
|
||||||
expect(leg.foot, isNull);
|
expect(leg.foot, isNull);
|
||||||
|
@ -82,7 +82,7 @@ void hasOneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
expect(footOpt.isPresent, true);
|
expect(footOpt.isPresent, true);
|
||||||
expect(legOpt.isPresent, true);
|
expect(legOpt.isPresent, true);
|
||||||
legOpt.ifPresent((leg) {
|
legOpt.ifPresent((leg) {
|
||||||
print(leg.toJson());
|
//print(leg.toJson());
|
||||||
expect(leg.name, 'Right');
|
expect(leg.name, 'Right');
|
||||||
expect(leg.foot, isNotNull);
|
expect(leg.foot, isNotNull);
|
||||||
footOpt.ifPresent((foot) {
|
footOpt.ifPresent((foot) {
|
||||||
|
@ -102,7 +102,7 @@ void hasOneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
expect(footOpt.isPresent, true);
|
expect(footOpt.isPresent, true);
|
||||||
expect(legOpt.isPresent, true);
|
expect(legOpt.isPresent, true);
|
||||||
legOpt.ifPresent((leg) {
|
legOpt.ifPresent((leg) {
|
||||||
print(leg.toJson());
|
//print(leg.toJson());
|
||||||
expect(leg.name, originalLeg?.name);
|
expect(leg.name, originalLeg?.name);
|
||||||
expect(leg.foot, isNotNull);
|
expect(leg.foot, isNotNull);
|
||||||
footOpt.ifPresent((foot) {
|
footOpt.ifPresent((foot) {
|
||||||
|
|
|
@ -21,7 +21,9 @@ void manyToManyTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
//var rows = await executor.query(null, query, {});
|
//var rows = await executor.query(null, query, {});
|
||||||
var rows = await executor.query('', query, {});
|
var rows = await executor.query('', query, {});
|
||||||
print('\n${rows.length} row(s):');
|
print('\n${rows.length} row(s):');
|
||||||
rows.forEach((r) => print(' * $r'));
|
for (var r in rows) {
|
||||||
|
print(' * $r');
|
||||||
|
}
|
||||||
print('==================================================\n\n');
|
print('==================================================\n\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
16
packages/orm/angel_orm_test/lib/src/models/fortune.dart
Normal file
16
packages/orm/angel_orm_test/lib/src/models/fortune.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import 'package:angel3_migration/angel3_migration.dart';
|
||||||
|
//import 'package:angel3_model/angel3_model.dart';
|
||||||
|
import 'package:angel3_serialize/angel3_serialize.dart';
|
||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
|
part 'fortune.g.dart';
|
||||||
|
|
||||||
|
@serializable
|
||||||
|
@Orm(tableName: 'fortune')
|
||||||
|
abstract class _Fortune {
|
||||||
|
int? id;
|
||||||
|
|
||||||
|
@Column(length: 2048)
|
||||||
|
String? message;
|
||||||
|
}
|
200
packages/orm/angel_orm_test/lib/src/models/fortune.g.dart
Normal file
200
packages/orm/angel_orm_test/lib/src/models/fortune.g.dart
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'fortune.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// MigrationGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class FortuneMigration extends Migration {
|
||||||
|
@override
|
||||||
|
void up(Schema schema) {
|
||||||
|
schema.create('fortune', (table) {
|
||||||
|
table.integer('id');
|
||||||
|
table.varChar('message', length: 2048);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void down(Schema schema) {
|
||||||
|
schema.drop('fortune');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// OrmGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class FortuneQuery extends Query<Fortune, FortuneQueryWhere> {
|
||||||
|
FortuneQuery({Query? parent, Set<String>? trampoline})
|
||||||
|
: super(parent: parent) {
|
||||||
|
trampoline ??= <String>{};
|
||||||
|
trampoline.add(tableName);
|
||||||
|
_where = FortuneQueryWhere(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final FortuneQueryValues values = FortuneQueryValues();
|
||||||
|
|
||||||
|
FortuneQueryWhere? _where;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, String> get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tableName {
|
||||||
|
return 'fortune';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> get fields {
|
||||||
|
return const ['id', 'message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FortuneQueryWhere? get where {
|
||||||
|
return _where;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
FortuneQueryWhere newWhereClause() {
|
||||||
|
return FortuneQueryWhere(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Fortune? parseRow(List row) {
|
||||||
|
if (row.every((x) => x == null)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var model = Fortune(id: (row[0] as int?), message: (row[1] as String?));
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Optional<Fortune> deserialize(List row) {
|
||||||
|
return Optional.ofNullable(parseRow(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FortuneQueryWhere extends QueryWhere {
|
||||||
|
FortuneQueryWhere(FortuneQuery query)
|
||||||
|
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
|
||||||
|
message = StringSqlExpressionBuilder(query, 'message');
|
||||||
|
|
||||||
|
final NumericSqlExpressionBuilder<int> id;
|
||||||
|
|
||||||
|
final StringSqlExpressionBuilder message;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<SqlExpressionBuilder> get expressionBuilders {
|
||||||
|
return [id, message];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FortuneQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
Map<String, String> get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int? get id {
|
||||||
|
return (values['id'] as int?);
|
||||||
|
}
|
||||||
|
|
||||||
|
set id(int? value) => values['id'] = value;
|
||||||
|
String? get message {
|
||||||
|
return (values['message'] as String?);
|
||||||
|
}
|
||||||
|
|
||||||
|
set message(String? value) => values['message'] = value;
|
||||||
|
void copyFrom(Fortune model) {
|
||||||
|
id = model.id;
|
||||||
|
message = model.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonModelGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
@generatedSerializable
|
||||||
|
class Fortune extends _Fortune {
|
||||||
|
Fortune({this.id, this.message});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? id;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? message;
|
||||||
|
|
||||||
|
Fortune copyWith({int? id, String? message}) {
|
||||||
|
return Fortune(id: id ?? this.id, message: message ?? this.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) {
|
||||||
|
return other is _Fortune && other.id == id && other.message == message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return hashObjects([id, message]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Fortune(id=$id, message=$message)';
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return FortuneSerializer.toMap(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// SerializerGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
const FortuneSerializer fortuneSerializer = FortuneSerializer();
|
||||||
|
|
||||||
|
class FortuneEncoder extends Converter<Fortune, Map> {
|
||||||
|
const FortuneEncoder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map convert(Fortune model) => FortuneSerializer.toMap(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FortuneDecoder extends Converter<Map, Fortune> {
|
||||||
|
const FortuneDecoder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Fortune convert(Map map) => FortuneSerializer.fromMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
class FortuneSerializer extends Codec<Fortune, Map> {
|
||||||
|
const FortuneSerializer();
|
||||||
|
|
||||||
|
@override
|
||||||
|
FortuneEncoder get encoder => const FortuneEncoder();
|
||||||
|
@override
|
||||||
|
FortuneDecoder get decoder => const FortuneDecoder();
|
||||||
|
static Fortune fromMap(Map map) {
|
||||||
|
return Fortune(id: map['id'] as int?, message: map['message'] as String?);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, dynamic> toMap(_Fortune? model) {
|
||||||
|
if (model == null) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {'id': model.id, 'message': model.message};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class FortuneFields {
|
||||||
|
static const List<String> allFields = <String>[id, message];
|
||||||
|
|
||||||
|
static const String id = 'id';
|
||||||
|
|
||||||
|
static const String message = 'message';
|
||||||
|
}
|
16
packages/orm/angel_orm_test/lib/src/models/world.dart
Normal file
16
packages/orm/angel_orm_test/lib/src/models/world.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import 'package:angel3_migration/angel3_migration.dart';
|
||||||
|
//import 'package:angel3_model/angel3_model.dart';
|
||||||
|
import 'package:angel3_serialize/angel3_serialize.dart';
|
||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
|
part 'world.g.dart';
|
||||||
|
|
||||||
|
@serializable
|
||||||
|
@Orm(tableName: 'world')
|
||||||
|
abstract class _World {
|
||||||
|
int? id;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
int? randomNumber;
|
||||||
|
}
|
203
packages/orm/angel_orm_test/lib/src/models/world.g.dart
Normal file
203
packages/orm/angel_orm_test/lib/src/models/world.g.dart
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'world.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// MigrationGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class WorldMigration extends Migration {
|
||||||
|
@override
|
||||||
|
void up(Schema schema) {
|
||||||
|
schema.create('world', (table) {
|
||||||
|
table.integer('id');
|
||||||
|
table.integer('randomNumber');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void down(Schema schema) {
|
||||||
|
schema.drop('world');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// OrmGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class WorldQuery extends Query<World, WorldQueryWhere> {
|
||||||
|
WorldQuery({Query? parent, Set<String>? trampoline}) : super(parent: parent) {
|
||||||
|
trampoline ??= <String>{};
|
||||||
|
trampoline.add(tableName);
|
||||||
|
_where = WorldQueryWhere(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final WorldQueryValues values = WorldQueryValues();
|
||||||
|
|
||||||
|
WorldQueryWhere? _where;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, String> get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get tableName {
|
||||||
|
return 'world';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<String> get fields {
|
||||||
|
return const ['id', 'randomNumber'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WorldQueryWhere? get where {
|
||||||
|
return _where;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
WorldQueryWhere newWhereClause() {
|
||||||
|
return WorldQueryWhere(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static World? parseRow(List row) {
|
||||||
|
if (row.every((x) => x == null)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var model = World(id: (row[0] as int?), randomNumber: (row[1] as int?));
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Optional<World> deserialize(List row) {
|
||||||
|
return Optional.ofNullable(parseRow(row));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorldQueryWhere extends QueryWhere {
|
||||||
|
WorldQueryWhere(WorldQuery query)
|
||||||
|
: id = NumericSqlExpressionBuilder<int>(query, 'id'),
|
||||||
|
randomNumber = NumericSqlExpressionBuilder<int>(query, 'randomNumber');
|
||||||
|
|
||||||
|
final NumericSqlExpressionBuilder<int> id;
|
||||||
|
|
||||||
|
final NumericSqlExpressionBuilder<int> randomNumber;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<SqlExpressionBuilder> get expressionBuilders {
|
||||||
|
return [id, randomNumber];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorldQueryValues extends MapQueryValues {
|
||||||
|
@override
|
||||||
|
Map<String, String> get casts {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
int? get id {
|
||||||
|
return (values['id'] as int?);
|
||||||
|
}
|
||||||
|
|
||||||
|
set id(int? value) => values['id'] = value;
|
||||||
|
int? get randomNumber {
|
||||||
|
return (values['randomNumber'] as int?);
|
||||||
|
}
|
||||||
|
|
||||||
|
set randomNumber(int? value) => values['randomNumber'] = value;
|
||||||
|
void copyFrom(World model) {
|
||||||
|
id = model.id;
|
||||||
|
randomNumber = model.randomNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonModelGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
@generatedSerializable
|
||||||
|
class World extends _World {
|
||||||
|
World({this.id, this.randomNumber});
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? id;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? randomNumber;
|
||||||
|
|
||||||
|
World copyWith({int? id, int? randomNumber}) {
|
||||||
|
return World(
|
||||||
|
id: id ?? this.id, randomNumber: randomNumber ?? this.randomNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) {
|
||||||
|
return other is _World &&
|
||||||
|
other.id == id &&
|
||||||
|
other.randomNumber == randomNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return hashObjects([id, randomNumber]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'World(id=$id, randomNumber=$randomNumber)';
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return WorldSerializer.toMap(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// SerializerGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
const WorldSerializer worldSerializer = WorldSerializer();
|
||||||
|
|
||||||
|
class WorldEncoder extends Converter<World, Map> {
|
||||||
|
const WorldEncoder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map convert(World model) => WorldSerializer.toMap(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorldDecoder extends Converter<Map, World> {
|
||||||
|
const WorldDecoder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
World convert(Map map) => WorldSerializer.fromMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorldSerializer extends Codec<World, Map> {
|
||||||
|
const WorldSerializer();
|
||||||
|
|
||||||
|
@override
|
||||||
|
WorldEncoder get encoder => const WorldEncoder();
|
||||||
|
@override
|
||||||
|
WorldDecoder get decoder => const WorldDecoder();
|
||||||
|
static World fromMap(Map map) {
|
||||||
|
return World(
|
||||||
|
id: map['id'] as int?, randomNumber: map['randomNumber'] as int?);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<String, dynamic> toMap(_World? model) {
|
||||||
|
if (model == null) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return {'id': model.id, 'randomNumber': model.randomNumber};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class WorldFields {
|
||||||
|
static const List<String> allFields = <String>[id, randomNumber];
|
||||||
|
|
||||||
|
static const String id = 'id';
|
||||||
|
|
||||||
|
static const String randomNumber = 'randomNumber';
|
||||||
|
}
|
91
packages/orm/angel_orm_test/lib/src/performance_test.dart
Normal file
91
packages/orm/angel_orm_test/lib/src/performance_test.dart
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'models/fortune.dart';
|
||||||
|
import 'models/world.dart';
|
||||||
|
|
||||||
|
void performanceTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
|
{FutureOr<void> Function(QueryExecutor)? close}) {
|
||||||
|
QueryExecutor? executor;
|
||||||
|
|
||||||
|
int _sampleSize = 1000;
|
||||||
|
|
||||||
|
int concurrency = 200;
|
||||||
|
|
||||||
|
// Generate a random number between 1 and 10000
|
||||||
|
int _genRandomId() {
|
||||||
|
var rand = Random();
|
||||||
|
return rand.nextInt(10000) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUp(() async {
|
||||||
|
print("Run setup");
|
||||||
|
executor = await createExecutor();
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (var i = 0; i < _sampleSize; i++) {
|
||||||
|
var query = WorldQuery();
|
||||||
|
query.values.randomNumber = _genRandomId();
|
||||||
|
var world = (await query.insert(executor!)).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < _sampleSize; i++) {
|
||||||
|
var query = FortuneQuery();
|
||||||
|
query.values.message = "message ${_genRandomId()}";
|
||||||
|
var fortune = (await query.insert(executor!)).value;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() => close!(executor!));
|
||||||
|
|
||||||
|
test('select all concurrency', () async {
|
||||||
|
var stopwatch = Stopwatch();
|
||||||
|
stopwatch.start();
|
||||||
|
|
||||||
|
// Fire and forget
|
||||||
|
for (var i = 0; i < concurrency; i++) {
|
||||||
|
FortuneQuery().get(executor!);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Loop time elapsed: ${stopwatch.elapsed.inMilliseconds}");
|
||||||
|
|
||||||
|
var result = await FortuneQuery().get(executor!);
|
||||||
|
|
||||||
|
print("Final Time elapsed: ${stopwatch.elapsed.inMilliseconds}");
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
expect(result, isNotNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('select one concurrency', () async {
|
||||||
|
var stopwatch = Stopwatch();
|
||||||
|
stopwatch.start();
|
||||||
|
|
||||||
|
var id = _genRandomId();
|
||||||
|
var query = WorldQuery()..where?.id.equals(id);
|
||||||
|
var result = await query.get(executor!);
|
||||||
|
|
||||||
|
print("Time elapsed: ${stopwatch.elapsed.inMilliseconds}");
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
expect(result, isNotNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('update concurrency', () async {
|
||||||
|
var stopwatch = Stopwatch();
|
||||||
|
stopwatch.start();
|
||||||
|
|
||||||
|
var id = _genRandomId();
|
||||||
|
var query = WorldQuery()..where?.id.equals(id);
|
||||||
|
var result = await query.get(executor!);
|
||||||
|
|
||||||
|
print("Time elapsed: ${stopwatch.elapsed.inMilliseconds}");
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
expect(result, isNotNull);
|
||||||
|
});
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
?..familyFriendly.isTrue
|
?..familyFriendly.isTrue
|
||||||
..recalledAt.lessThanOrEqualTo(y2k, includeTime: false);
|
..recalledAt.lessThanOrEqualTo(y2k, includeTime: false);
|
||||||
var whereClause = query.where?.compile(tableName: 'cars');
|
var whereClause = query.where?.compile(tableName: 'cars');
|
||||||
print('Where clause: $whereClause');
|
//print('Where clause: $whereClause');
|
||||||
expect(whereClause,
|
expect(whereClause,
|
||||||
'cars.family_friendly = TRUE AND cars.recalled_at <= \'2000-01-01\'');
|
'cars.family_friendly = TRUE AND cars.recalled_at <= \'2000-01-01\'');
|
||||||
});
|
});
|
||||||
|
@ -23,11 +23,11 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
// 'id', 'created_at', 'updated_at', 'make', 'description', 'family_friendly', 'recalled_at'
|
// 'id', 'created_at', 'updated_at', 'make', 'description', 'family_friendly', 'recalled_at'
|
||||||
// var row = [0, 'Mazda', 'CX9', true, y2k, y2k, y2k];
|
// var row = [0, 'Mazda', 'CX9', true, y2k, y2k, y2k];
|
||||||
var row = [0, y2k, y2k, 'Mazda', 'CX9', true, y2k];
|
var row = [0, y2k, y2k, 'Mazda', 'CX9', true, y2k];
|
||||||
print(row);
|
//print(row);
|
||||||
var carOpt = CarQuery().deserialize(row);
|
var carOpt = CarQuery().deserialize(row);
|
||||||
expect(carOpt.isPresent, true);
|
expect(carOpt.isPresent, true);
|
||||||
carOpt.ifPresent((car) {
|
carOpt.ifPresent((car) {
|
||||||
print(car.toJson());
|
//print(car.toJson());
|
||||||
expect(car.id, '0');
|
expect(car.id, '0');
|
||||||
expect(car.make, 'Mazda');
|
expect(car.make, 'Mazda');
|
||||||
expect(car.description, 'CX9');
|
expect(car.description, 'CX9');
|
||||||
|
@ -42,17 +42,17 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
});
|
});
|
||||||
|
|
||||||
group('queries', () {
|
group('queries', () {
|
||||||
late QueryExecutor executor;
|
QueryExecutor? executor;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
executor = await createExecutor();
|
executor = await createExecutor();
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() => close!(executor));
|
tearDown(() => close!(executor!));
|
||||||
|
|
||||||
group('selects', () {
|
group('selects', () {
|
||||||
test('select all', () async {
|
test('select all', () async {
|
||||||
var cars = await CarQuery().get(executor);
|
var cars = await CarQuery().get(executor!);
|
||||||
expect(cars, []);
|
expect(cars, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -63,19 +63,21 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var query = CarQuery();
|
var query = CarQuery();
|
||||||
query.values
|
query.values
|
||||||
..make = 'Ferrari東'
|
..make = 'Ferrari東'
|
||||||
|
..createdAt = y2k
|
||||||
|
..updatedAt = y2k
|
||||||
..description = 'Vroom vroom!'
|
..description = 'Vroom vroom!'
|
||||||
..familyFriendly = false;
|
..familyFriendly = false;
|
||||||
ferrari = (await query.insert(executor)).value;
|
ferrari = (await query.insert(executor!)).value;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('where clause is applied', () async {
|
test('where clause is applied', () async {
|
||||||
var query = CarQuery()..where!.familyFriendly.isTrue;
|
var query = CarQuery()..where!.familyFriendly.isTrue;
|
||||||
var cars = await query.get(executor);
|
var cars = await query.get(executor!);
|
||||||
expect(cars, isEmpty);
|
expect(cars, isEmpty);
|
||||||
|
|
||||||
var sportsCars = CarQuery()..where!.familyFriendly.isFalse;
|
var sportsCars = CarQuery()..where!.familyFriendly.isFalse;
|
||||||
cars = await sportsCars.get(executor);
|
cars = await sportsCars.get(executor!);
|
||||||
print(cars.map((c) => c.toJson()));
|
//print(cars.map((c) => c.toJson()));
|
||||||
|
|
||||||
var car = cars.first;
|
var car = cars.first;
|
||||||
expect(car.make, ferrari!.make);
|
expect(car.make, ferrari!.make);
|
||||||
|
@ -89,8 +91,8 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var query2 = CarQuery()..where?.familyFriendly.isTrue;
|
var query2 = CarQuery()..where?.familyFriendly.isTrue;
|
||||||
var query3 = CarQuery()..where?.description.equals('Submarine');
|
var query3 = CarQuery()..where?.description.equals('Submarine');
|
||||||
var union = query1.union(query2).unionAll(query3);
|
var union = query1.union(query2).unionAll(query3);
|
||||||
print(union.compile({}));
|
//print(union.compile({}));
|
||||||
var cars = await union.get(executor);
|
var cars = await union.get(executor!);
|
||||||
expect(cars, hasLength(1));
|
expect(cars, hasLength(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -100,22 +102,22 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
..orWhere((where) => where
|
..orWhere((where) => where
|
||||||
..familyFriendly.isTrue
|
..familyFriendly.isTrue
|
||||||
..make.equals('Honda'));
|
..make.equals('Honda'));
|
||||||
print(query.compile({}));
|
//print(query.compile({}));
|
||||||
var cars = await query.get(executor);
|
var cars = await query.get(executor!);
|
||||||
expect(cars, hasLength(1));
|
expect(cars, hasLength(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('limit obeyed', () async {
|
test('limit obeyed', () async {
|
||||||
var query = CarQuery()..limit(0);
|
var query = CarQuery()..limit(0);
|
||||||
print(query.compile({}));
|
//print(query.compile({}));
|
||||||
var cars = await query.get(executor);
|
var cars = await query.get(executor!);
|
||||||
expect(cars, isEmpty);
|
expect(cars, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('get one', () async {
|
test('get one', () async {
|
||||||
var id = int.parse(ferrari!.id!);
|
var id = int.parse(ferrari!.id!);
|
||||||
var query = CarQuery()..where!.id.equals(id);
|
var query = CarQuery()..where!.id.equals(id);
|
||||||
var carOpt = await query.getOne(executor);
|
var carOpt = await query.getOne(executor!);
|
||||||
expect(carOpt.isPresent, true);
|
expect(carOpt.isPresent, true);
|
||||||
carOpt.ifPresent((car) {
|
carOpt.ifPresent((car) {
|
||||||
expect(car, ferrari);
|
expect(car, ferrari);
|
||||||
|
@ -125,14 +127,14 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
test('delete one', () async {
|
test('delete one', () async {
|
||||||
var id = int.parse(ferrari!.id!);
|
var id = int.parse(ferrari!.id!);
|
||||||
var query = CarQuery()..where!.id.equals(id);
|
var query = CarQuery()..where!.id.equals(id);
|
||||||
var carOpt = await (query.deleteOne(executor));
|
var carOpt = await (query.deleteOne(executor!));
|
||||||
expect(carOpt.isPresent, true);
|
expect(carOpt.isPresent, true);
|
||||||
carOpt.ifPresent((car) {
|
carOpt.ifPresent((car) {
|
||||||
var car = carOpt.value;
|
var car = carOpt.value;
|
||||||
expect(car.toJson(), ferrari!.toJson());
|
expect(car.toJson(), ferrari!.toJson());
|
||||||
});
|
});
|
||||||
|
|
||||||
var cars = await CarQuery().get(executor);
|
var cars = await CarQuery().get(executor!);
|
||||||
expect(cars, isEmpty);
|
expect(cars, isEmpty);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -140,9 +142,9 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var query = CarQuery()
|
var query = CarQuery()
|
||||||
..where!.make.equals('Ferrari東')
|
..where!.make.equals('Ferrari東')
|
||||||
..orWhere((w) => w.familyFriendly.isTrue);
|
..orWhere((w) => w.familyFriendly.isTrue);
|
||||||
print(query.compile({}, preamble: 'DELETE FROM "cars"'));
|
//print(query.compile({}, preamble: 'DELETE FROM "cars"'));
|
||||||
|
|
||||||
var cars = await query.delete(executor);
|
var cars = await query.delete(executor!);
|
||||||
expect(cars, hasLength(1));
|
expect(cars, hasLength(1));
|
||||||
expect(cars.first.toJson(), ferrari!.toJson());
|
expect(cars.first.toJson(), ferrari!.toJson());
|
||||||
});
|
});
|
||||||
|
@ -151,7 +153,7 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
var query = CarQuery()
|
var query = CarQuery()
|
||||||
..where!.id.equals(int.parse(ferrari!.id!))
|
..where!.id.equals(int.parse(ferrari!.id!))
|
||||||
..values.make = 'Hyundai';
|
..values.make = 'Hyundai';
|
||||||
var cars = await query.update(executor);
|
var cars = await query.update(executor!);
|
||||||
expect(cars, hasLength(1));
|
expect(cars, hasLength(1));
|
||||||
expect(cars.first.make, 'Hyundai');
|
expect(cars.first.make, 'Hyundai');
|
||||||
});
|
});
|
||||||
|
@ -159,11 +161,11 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
test('update car', () async {
|
test('update car', () async {
|
||||||
var cloned = ferrari!.copyWith(make: 'Angel');
|
var cloned = ferrari!.copyWith(make: 'Angel');
|
||||||
var query = CarQuery()..values.copyFrom(cloned);
|
var query = CarQuery()..values.copyFrom(cloned);
|
||||||
var carOpt = await (query.updateOne(executor));
|
var carOpt = await (query.updateOne(executor!));
|
||||||
expect(carOpt.isPresent, true);
|
expect(carOpt.isPresent, true);
|
||||||
carOpt.ifPresent((car) {
|
carOpt.ifPresent((car) {
|
||||||
var car = carOpt.value;
|
var car = carOpt.value;
|
||||||
print(car.toJson());
|
//print(car.toJson());
|
||||||
expect(car.toJson(), cloned.toJson());
|
expect(car.toJson(), cloned.toJson());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -181,7 +183,7 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
..recalledAt = recalledAt
|
..recalledAt = recalledAt
|
||||||
..createdAt = now
|
..createdAt = now
|
||||||
..updatedAt = now;
|
..updatedAt = now;
|
||||||
var carOpt = await (query.insert(executor));
|
var carOpt = await (query.insert(executor!));
|
||||||
expect(carOpt.isPresent, true);
|
expect(carOpt.isPresent, true);
|
||||||
carOpt.ifPresent((car) {
|
carOpt.ifPresent((car) {
|
||||||
var car = carOpt.value;
|
var car = carOpt.value;
|
||||||
|
@ -203,10 +205,10 @@ void standaloneTests(FutureOr<QueryExecutor> Function() createExecutor,
|
||||||
familyFriendly: true,
|
familyFriendly: true,
|
||||||
recalledAt: recalledAt);
|
recalledAt: recalledAt);
|
||||||
var query = CarQuery()..values.copyFrom(beetle);
|
var query = CarQuery()..values.copyFrom(beetle);
|
||||||
var carOpt = await (query.insert(executor));
|
var carOpt = await (query.insert(executor!));
|
||||||
expect(carOpt.isPresent, true);
|
expect(carOpt.isPresent, true);
|
||||||
carOpt.ifPresent((car) {
|
carOpt.ifPresent((car) {
|
||||||
print(car.toJson());
|
//print(car.toJson());
|
||||||
expect(car.make, beetle.make);
|
expect(car.make, beetle.make);
|
||||||
expect(car.description, beetle.description);
|
expect(car.description, beetle.description);
|
||||||
expect(car.familyFriendly, beetle.familyFriendly);
|
expect(car.familyFriendly, beetle.familyFriendly);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel3_orm_test
|
name: angel3_orm_test
|
||||||
version: 3.0.2
|
version: 3.0.3
|
||||||
description: Common tests for Angel3 ORM. Reference implmentation of the generated ORM files.
|
description: Common tests for Angel3 ORM. Reference implmentation of the generated ORM files.
|
||||||
homepage: https://angel3-framework.web.app/
|
homepage: https://angel3-framework.web.app/
|
||||||
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_test
|
repository: https://github.com/dukefirehawk/angel/tree/master/packages/orm/angel_orm_test
|
||||||
|
|
149
packages/orm/angel_orm_test/scripts/create_tables.sql
Normal file
149
packages/orm/angel_orm_test/scripts/create_tables.sql
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
CREATE TABLE "authors" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
name varchar(255) UNIQUE NOT NULL,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "books" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
author_id int NOT NULL,
|
||||||
|
partner_author_id int,
|
||||||
|
name varchar(255),
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "cars" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
make varchar(255) NOT NULL,
|
||||||
|
description TEXT NOT NULL,
|
||||||
|
family_friendly BOOLEAN NOT NULL,
|
||||||
|
recalled_at timestamp,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "numbers" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "alphabets" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
value TEXT,
|
||||||
|
numbers_id int,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "feet" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
leg_id int NOT NULL,
|
||||||
|
n_toes int NOT NULL,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "fruits" (
|
||||||
|
"id" serial,
|
||||||
|
"tree_id" int,
|
||||||
|
"common_name" varchar,
|
||||||
|
"created_at" timestamp,
|
||||||
|
"updated_at" timestamp,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "has_cars" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
type int not null,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "has_maps" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
value jsonb not null,
|
||||||
|
list jsonb not null,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "legs" (
|
||||||
|
id serial PRIMARY KEY,
|
||||||
|
name varchar(255) NOT NULL,
|
||||||
|
created_at timestamp,
|
||||||
|
updated_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "roles" (
|
||||||
|
"id" serial PRIMARY KEY,
|
||||||
|
"name" varchar(255),
|
||||||
|
"created_at" timestamp,
|
||||||
|
"updated_at" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "trees" (
|
||||||
|
"id" serial,
|
||||||
|
"rings" smallint UNIQUE,
|
||||||
|
"created_at" timestamp,
|
||||||
|
"updated_at" timestamp,
|
||||||
|
UNIQUE(rings),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "unorthodoxes" (
|
||||||
|
"name" varchar(255),
|
||||||
|
PRIMARY KEY(name)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "users" (
|
||||||
|
"id" serial PRIMARY KEY,
|
||||||
|
"username" varchar(255),
|
||||||
|
"password" varchar(255),
|
||||||
|
"email" varchar(255),
|
||||||
|
"created_at" timestamp,
|
||||||
|
"updated_at" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "role_users" (
|
||||||
|
"id" serial PRIMARY KEY,
|
||||||
|
"user_id" int NOT NULL,
|
||||||
|
"role_id" int NOT NULL,
|
||||||
|
"created_at" timestamp,
|
||||||
|
"updated_at" timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "foos" (
|
||||||
|
"bar" varchar(255),
|
||||||
|
PRIMARY KEY(bar)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "weird_joins" (
|
||||||
|
"id" serial,
|
||||||
|
"join_name" varchar(255) references unorthodoxes(name),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "songs" (
|
||||||
|
"id" serial,
|
||||||
|
"weird_join_id" int references weird_joins(id),
|
||||||
|
"title" varchar(255),
|
||||||
|
created_at TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "numbas" (
|
||||||
|
"i" int,
|
||||||
|
"parent" int references weird_joins(id),
|
||||||
|
created_at TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP,
|
||||||
|
PRIMARY KEY(i)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "foo_pivots" (
|
||||||
|
"weird_join_id" int references weird_joins(id),
|
||||||
|
"foo_bar" varchar(255) references foos(bar)
|
||||||
|
);
|
0
tool/move_repos → tool/archived/move_repos
Executable file → Normal file
0
tool/move_repos → tool/archived/move_repos
Executable file → Normal file
0
tool/pull_subproject → tool/archived/pull_subproject
Executable file → Normal file
0
tool/pull_subproject → tool/archived/pull_subproject
Executable file → Normal file
6
tool/performance/AUTHORS.md
Normal file
6
tool/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
tool/performance/LICENSE
Normal file
29
tool/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
tool/performance/analysis_options.yaml
Normal file
1
tool/performance/analysis_options.yaml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include: package:lints/recommended.yaml
|
11
tool/performance/pubspec.yaml
Normal file
11
tool/performance/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.12.0 <3.0.0'
|
||||||
|
published_to: none
|
||||||
|
dependencies:
|
||||||
|
http: ^0.13.4
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^1.0.0
|
104
tool/performance/techempower/main.dart
Normal file
104
tool/performance/techempower/main.dart
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
Future<void> fortunes(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
var url = Uri.http('localhost:3000', '/fortunes');
|
||||||
|
var response = await http.get(url);
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print('Execution($message): success');
|
||||||
|
} else {
|
||||||
|
print('Execution($message): error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> plaintext(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
var url = Uri.http('localhost:3000', '/plaintext');
|
||||||
|
var response = await http.get(url);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print('Execution($message): success');
|
||||||
|
} else {
|
||||||
|
print('Execution($message): error');
|
||||||
|
}
|
||||||
|
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> json(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
var url = Uri.http('localhost:3000', '/json');
|
||||||
|
var response = await http.get(url);
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print('Execution($message): success');
|
||||||
|
} else {
|
||||||
|
print('Execution($message): error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> dbUpdate(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
var url = Uri.http('localhost:3000', '/updates', {'queries': "5"});
|
||||||
|
var response = await http.get(url);
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print('Execution($message): success');
|
||||||
|
} else {
|
||||||
|
print('Execution($message): error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> dbSingleQuery(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
var url = Uri.http('localhost:3000', '/db');
|
||||||
|
var response = await http.get(url);
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print('Execution($message): success');
|
||||||
|
} else {
|
||||||
|
print('Execution($message): error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> dbMultipleQuery(var message) async {
|
||||||
|
var stopwatch = Stopwatch()..start();
|
||||||
|
|
||||||
|
var url = Uri.http('localhost:3000', '/query', {'queries': "5"});
|
||||||
|
var response = await http.get(url);
|
||||||
|
print('Execution($message) Time: ${stopwatch.elapsed.inMilliseconds}ms');
|
||||||
|
stopwatch.stop();
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print('Execution($message): success');
|
||||||
|
} else {
|
||||||
|
print('Execution($message): error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
var concurrency = 100;
|
||||||
|
|
||||||
|
for (var i = 0; i < concurrency; i++) {
|
||||||
|
Isolate.spawn(dbUpdate, 'Instance_$i');
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(seconds: 10));
|
||||||
|
|
||||||
|
//print("Exit");
|
||||||
|
}
|
19
tool/performance/tests/techempower.http
Normal file
19
tool/performance/tests/techempower.http
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
### JSON Test
|
||||||
|
GET http://localhost:3000/json HTTP/1.1
|
||||||
|
|
||||||
|
### Plaintext Test
|
||||||
|
GET http://localhost:3000/plaintext HTTP/1.1
|
||||||
|
|
||||||
|
### Fortunes Test
|
||||||
|
GET http://localhost:3000/fortunes HTTP/1.1
|
||||||
|
|
||||||
|
### Db Test
|
||||||
|
GET http://localhost:3000/db HTTP/1.1
|
||||||
|
|
||||||
|
### Query test
|
||||||
|
GET http://localhost:3000/query?queries=20 HTTP/1.1
|
||||||
|
|
||||||
|
### Update Test
|
||||||
|
GET http://localhost:3000/updates?queries=20 HTTP/1.1
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue