feat: SAP Hana support (#5246)

* basic impl

* finished basic table metadata queries;

* implemented data types;

* working on data types;

* added test for column length;

* working on indices

* working on query runner

* working on schema builder

* removed SAP HANA client from dependencies

* fixed SAP uuid

* working on falling tests;

* working on falling tests;

* added docker configuration for sap hana

* simplifying sample entity

* implemented pool;

* trying to add SAP Hana to Circle CI

* trying to add SAP Hana to Circle CI

* trying to add SAP Hana to Circle CI

* testing CircleCI config

* testing CircleCI config

* added sap tests for ci

* changed sap port

* ci experiments

* ci experiments

* removing ci, adding docs

* removing ci

* minor fixes;

* fixed falling test;

Co-authored-by: AlexMesser <dmzt08@gmail.com>
This commit is contained in:
Umed Khudoiberdiev 2019-12-23 19:35:54 +05:00 committed by GitHub
parent d19162c8bc
commit ec9034125d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
95 changed files with 4165 additions and 377 deletions

View File

@ -23,6 +23,30 @@ jobs:
POSTGRES_PASSWORD: "test"
POSTGRES_DB: "test"
- image: circleci/mongo:3.4.18
# - image: "store/saplabs/hanaexpress:2.00.040.00.20190729.1"
# auth:
# username: $DOCKER_USER
# password: $DOCKER_PASSWORD
## name: hanaexpress
## container_name: "typeorm-hanaexpress"
## hostname: hxe
# command: ['--passwords-url', 'https://raw.githubusercontent.com/typeorm/typeorm/b119f7c3b8748aea9c77c7bc42b8e1be209b43ec/docker/hana/hxe-config.json', '--agree-to-sap-license']
## ulimits:
## nofile: 1048576
## sysctls:
## - kernel.shmmax=1073741824
## - net.ipv4.ip_local_port_range=40000 60999
## - kernel.shmmni=524288
## - kernel.shmall=8388608
## volumes:
## - volume-hana-xe:/hana/mounts
## - ./docker/hana/hxe-config.json:/hana/hxe-config.json
## ports:
## - 39013:39013
## - 39017:39017
## - 39041-39045:39041-39045
## - 1128-1129:1128-1129
## - 59013-59014:59013-59014
# - image: mcr.microsoft.com/mssql/server:2017-GA-ubuntu
# environment:
# SA_PASSWORD: "Admin12345"

1
.npmrc Normal file
View File

@ -0,0 +1 @@
@sap:registry=https://npm.sap.com

View File

@ -57,7 +57,7 @@ TypeORM 的一些特性:
- 支持闭包表模式
- 在模型或者分离的配置文件中声明模式
- json / xml / yml / env 格式的连接配置
- 支持 MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / sql.js
- 支持 MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / SAP Hana / sql.js
- 支持 MongoDB NoSQL 数据库
- 可在 NodeJS / 浏览器 / Ionic / Cordova / React Native / Expo / Electron 平台上使用
- 支持 TypeScript 和 JavaScript
@ -198,9 +198,16 @@ await timber.remove();
查看 [支持的平台](/supported-platforms.md)
- **SAP Hana**
```
npm config set @sap:registry https://npm.sap.com
npm i @sap/hdbext
```
##### TypeScript 配置
此外,请确保你使用的 TypeScript 编译器版本是**2.3**或更高版本,并且已经在 `tsconfig.json` 中启用了以下设置:
此外,请确保你使用的 TypeScript 编译器版本是**3.3**或更高版本,并且已经在 `tsconfig.json` 中启用了以下设置:
```json
"emitDecoratorMetadata": true,

View File

@ -70,7 +70,7 @@ Some TypeORM features:
* supports closure table pattern
* schema declaration in models or separate configuration files
* connection configuration in json / xml / yml / env formats
* supports MySQL / MariaDB / Postgres / CockroachDB / SQLite / Microsoft SQL Server / Oracle / sql.js
* supports MySQL / MariaDB / Postgres / CockroachDB / SQLite / Microsoft SQL Server / Oracle / SAP Hana / sql.js
* supports MongoDB NoSQL database
* works in NodeJS / Browser / Ionic / Cordova / React Native / NativeScript / Expo / Electron platforms
* TypeScript and JavaScript support
@ -203,11 +203,16 @@ await timber.remove();
`npm install oracledb --save`
Install only *one* of them, depending on which database you use.
To make the Oracle driver work, you need to follow the installation instructions from
[their](https://github.com/oracle/node-oracledb) site.
* for **SAP Hana**
```
npm config set @sap:registry https://npm.sap.com
npm i @sap/hdbext
```
* for **MongoDB** (experimental)
`npm install mongodb --save`
@ -216,11 +221,12 @@ await timber.remove();
Check [documentation of supported platforms](./docs/supported-platforms.md)
Install only *one* of them, depending on which database you use.
##### TypeScript configuration
Also, make sure you are using TypeScript compiler version **3.3** or greater,
Also, make sure you are using TypeScript version **3.3** or higher,
and you have enabled the following settings in `tsconfig.json`:
```json

View File

@ -69,6 +69,29 @@ services:
ports:
- "26257:26257"
# sap hana (works only on linux)
# hanaexpress:
# image: "store/saplabs/hanaexpress:2.00.040.00.20190729.1"
# container_name: "typeorm-hanaexpress"
# hostname: hxe
# command: ['--passwords-url', 'file:////hana/hxe-config.json', '--agree-to-sap-license']
# ulimits:
# nofile: 1048576
# sysctls:
# - kernel.shmmax=1073741824
# - net.ipv4.ip_local_port_range=40000 60999
# - kernel.shmmni=524288
# - kernel.shmall=8388608
# volumes:
# - volume-hana-xe:/hana/mounts
# - ./docker/hana/hxe-config.json:/hana/hxe-config.json
# ports:
# - 39013:39013
# - 39017:39017
# - 39041-39045:39041-39045
# - 1128-1129:1128-1129
# - 59013-59014:59013-59014
# mongodb
mongodb:
image: "mongo:3.4.18"
@ -82,3 +105,6 @@ services:
# container_name: "typeorm-redis"
# ports:
# - "6379:6379"
#volumes:
# volume-hana-xe:

View File

@ -0,0 +1,3 @@
{
"master_password" : "HXEHana1"
}

View File

@ -69,6 +69,17 @@
"password": "",
"database": "defaultdb"
},
{
"skip": true,
"name": "sap",
"type": "sap",
"host": "localhost",
"port": 39015,
"username": "SYSTEM",
"password": "HXEHana1",
"database": "HXE",
"logging": false
},
{
"skip": false,
"disabledIfNotEnabledImplicitly": true,

View File

@ -70,6 +70,17 @@
"password": "",
"database": "defaultdb"
},
{
"skip": false,
"name": "sap",
"type": "sap",
"host": "192.168.56.102",
"port": 39015,
"username": "SYSTEM",
"password": "MySuperHanaPwd123!",
"database": "HXE",
"logging": false
},
{
"skip": false,
"disabledIfNotEnabledImplicitly": true,

570
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "typeorm",
"version": "0.2.21",
"version": "0.2.22-rc.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -120,6 +120,328 @@
"any-observable": "^0.3.0"
}
},
"@sap/hana-client": {
"version": "2.4.171",
"resolved": "https://npm.sap.com/@sap/hana-client/-/hana-client-2.4.171.tgz",
"integrity": "sha512-djtXNfPZl+QMSOYSZxbyEGvUaWxyC0or3U+8odm+5Oc1ScVDaXp54U1E5i4Iw/USFi+1FBIrY+kh5CQ+r62Wog==",
"dev": true,
"requires": {
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
},
"@sap/hdbext": {
"version": "6.1.1",
"resolved": "https://npm.sap.com/@sap/hdbext/-/hdbext-6.1.1.tgz",
"integrity": "sha512-M+VmMghNPVuGOvZnIJUfb8usYqj3HoEIjdcBaDzSHpSLXxUXGaWgWZ0pGgdDV4BTjWPHkbb7ZiBrp4k4heOoSg==",
"requires": {
"@sap/e2e-trace": "^2.0.0",
"@sap/hana-client": "2.4.167",
"accept-language": "2.0.16",
"async": "2.4.1",
"debug": "3.1.0",
"lodash": "4.17.13",
"verror": "1.10.0"
},
"dependencies": {
"@sap/e2e-trace": {
"version": "2.0.0",
"resolved": "https://npm.sap.com/@sap/e2e-trace/-/e2e-trace-2.0.0.tgz",
"integrity": "sha512-iAAd+U8W+c5Yk4f3PSCL68oAjpCG6NUtmh67MD+hifCjM+LIG8R9oDtVgefQ68jImAtsiInBwEFisRkYHBjztw==",
"requires": {
"request-stats": "3.0.0"
},
"dependencies": {
"http-headers": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/http-headers/-/http-headers-3.0.2.tgz",
"integrity": "sha512-87E1I+2Wg4dxxz4rcxElo3dxO/w1ZtgL1yA0Sb6vH3qU16vRKq1NjWQv9SCY3ly2OQROcoxHZOUpmelS+k6wOw==",
"requires": {
"next-line": "^1.1.0"
}
},
"next-line": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-line/-/next-line-1.1.0.tgz",
"integrity": "sha1-/K5XhTBStqm66CCOQN19PC0wRgM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"request-stats": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/request-stats/-/request-stats-3.0.0.tgz",
"integrity": "sha1-dpFV3Il0141KHLh7vxTqq5ha/iU=",
"requires": {
"http-headers": "^3.0.1",
"once": "^1.4.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
},
"@sap/hana-client": {
"version": "2.4.167",
"resolved": "https://npm.sap.com/@sap/hana-client/-/hana-client-2.4.167.tgz",
"integrity": "sha512-nUIOcuNa6xhUPr49RR497Pg+UYB/Lb/X2SM2woQGaCeY23mkaQy5w/+TVAgqmW0i0WQhRC1BJ8tXOR2TmLYzmg==",
"requires": {
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"accept-language": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/accept-language/-/accept-language-2.0.16.tgz",
"integrity": "sha1-uefScQd0rWCfJHbzz+GkkrVgYb4=",
"requires": {
"bcp47": "^1.1.2"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/async/-/async-2.4.1.tgz",
"integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=",
"requires": {
"lodash": "^4.14.0"
}
},
"bcp47": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz",
"integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"extsprintf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz",
"integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8="
},
"lodash": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.13.tgz",
"integrity": "sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
}
}
},
"@sap/hdbext": {
"version": "6.1.1",
"resolved": "https://npm.sap.com/@sap/hdbext/-/hdbext-6.1.1.tgz",
"integrity": "sha512-M+VmMghNPVuGOvZnIJUfb8usYqj3HoEIjdcBaDzSHpSLXxUXGaWgWZ0pGgdDV4BTjWPHkbb7ZiBrp4k4heOoSg==",
"requires": {
"@sap/e2e-trace": "^2.0.0",
"@sap/hana-client": "2.4.167",
"accept-language": "2.0.16",
"async": "2.4.1",
"debug": "3.1.0",
"lodash": "4.17.13",
"verror": "1.10.0"
},
"dependencies": {
"@sap/e2e-trace": {
"version": "2.0.0",
"resolved": "https://npm.sap.com/@sap/e2e-trace/-/e2e-trace-2.0.0.tgz",
"integrity": "sha512-iAAd+U8W+c5Yk4f3PSCL68oAjpCG6NUtmh67MD+hifCjM+LIG8R9oDtVgefQ68jImAtsiInBwEFisRkYHBjztw==",
"requires": {
"request-stats": "3.0.0"
},
"dependencies": {
"http-headers": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/http-headers/-/http-headers-3.0.2.tgz",
"integrity": "sha512-87E1I+2Wg4dxxz4rcxElo3dxO/w1ZtgL1yA0Sb6vH3qU16vRKq1NjWQv9SCY3ly2OQROcoxHZOUpmelS+k6wOw==",
"requires": {
"next-line": "^1.1.0"
}
},
"next-line": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-line/-/next-line-1.1.0.tgz",
"integrity": "sha1-/K5XhTBStqm66CCOQN19PC0wRgM="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"request-stats": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/request-stats/-/request-stats-3.0.0.tgz",
"integrity": "sha1-dpFV3Il0141KHLh7vxTqq5ha/iU=",
"requires": {
"http-headers": "^3.0.1",
"once": "^1.4.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
},
"@sap/hana-client": {
"version": "2.4.167",
"resolved": "https://npm.sap.com/@sap/hana-client/-/hana-client-2.4.167.tgz",
"integrity": "sha512-nUIOcuNa6xhUPr49RR497Pg+UYB/Lb/X2SM2woQGaCeY23mkaQy5w/+TVAgqmW0i0WQhRC1BJ8tXOR2TmLYzmg==",
"requires": {
"debug": "3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"accept-language": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/accept-language/-/accept-language-2.0.16.tgz",
"integrity": "sha1-uefScQd0rWCfJHbzz+GkkrVgYb4=",
"requires": {
"bcp47": "^1.1.2"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/async/-/async-2.4.1.tgz",
"integrity": "sha1-YqVrJ5yYoR0JhwlqAcw+6463u9c=",
"requires": {
"lodash": "^4.14.0"
}
},
"bcp47": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz",
"integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"extsprintf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz",
"integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8="
},
"lodash": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.13.tgz",
"integrity": "sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA=="
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
}
}
},
"@sinonjs/commons": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.1.tgz",
@ -1200,16 +1522,29 @@
"yargs": "^11.0.0"
},
"dependencies": {
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"requires": {
"invert-kv": "^2.0.0"
}
},
"yargs": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz",
"integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==",
"requires": {
"cliui": "^4.0.0",
"decamelize": "^1.1.1",
"find-up": "^2.1.0",
"get-caller-file": "^1.0.1",
"os-locale": "^2.0.0",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
@ -1217,6 +1552,26 @@
"which-module": "^2.0.0",
"y18n": "^3.2.1",
"yargs-parser": "^9.0.2"
},
"dependencies": {
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"yargs-parser": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
"integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
"requires": {
"camelcase": "^4.1.0"
}
}
}
}
}
@ -1754,11 +2109,13 @@
}
},
"cross-spawn": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"lru-cache": "^4.0.1",
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
@ -2277,17 +2634,36 @@
}
},
"execa": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
"integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"requires": {
"cross-spawn": "^5.0.1",
"get-stream": "^3.0.0",
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
},
"dependencies": {
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"requires": {
"pump": "^3.0.0"
}
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
}
}
},
"expand-brackets": {
@ -2691,8 +3067,7 @@
"version": "2.1.1",
"resolved": false,
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -2716,15 +3091,13 @@
"version": "1.0.0",
"resolved": false,
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": false,
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -2734,22 +3107,19 @@
"version": "1.1.0",
"resolved": false,
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": false,
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": false,
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -2870,8 +3240,7 @@
"version": "2.0.3",
"resolved": false,
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -2885,7 +3254,6 @@
"resolved": false,
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -2902,7 +3270,6 @@
"resolved": false,
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -2911,15 +3278,13 @@
"version": "0.0.8",
"resolved": false,
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": false,
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -3008,8 +3373,7 @@
"version": "1.0.1",
"resolved": false,
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -3023,7 +3387,6 @@
"resolved": false,
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -3119,8 +3482,7 @@
"version": "5.1.1",
"resolved": false,
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -3162,7 +3524,6 @@
"resolved": false,
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -3184,7 +3545,6 @@
"resolved": false,
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -3242,8 +3602,7 @@
"version": "1.0.2",
"resolved": false,
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
@ -3315,7 +3674,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
@ -3466,7 +3825,8 @@
"get-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
"dev": true
},
"get-value": {
"version": "2.0.6",
@ -3748,7 +4108,7 @@
},
"os-locale": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
"dev": true,
"requires": {
@ -4130,9 +4490,9 @@
}
},
"handlebars": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
@ -4474,7 +4834,8 @@
"invert-kv": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
"integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
"dev": true
},
"is-absolute": {
"version": "1.0.0",
@ -4488,7 +4849,7 @@
},
"is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
"dev": true,
"requires": {
@ -4553,7 +4914,7 @@
},
"is-data-descriptor": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
"dev": true,
"requires": {
@ -5027,6 +5388,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
"dev": true,
"requires": {
"invert-kv": "^1.0.0"
}
@ -5280,7 +5642,7 @@
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
@ -5293,7 +5655,7 @@
"dependencies": {
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
@ -5415,6 +5777,7 @@
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"dev": true,
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
@ -5501,11 +5864,20 @@
}
},
"mem": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz",
"integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"requires": {
"mimic-fn": "^1.0.0"
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
},
"dependencies": {
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
}
}
},
"memoizee": {
@ -6178,9 +6550,9 @@
}
},
"neo-async": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
"integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==",
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
"next-tick": {
@ -6547,16 +6919,6 @@
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true
},
"os-locale": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz",
"integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==",
"requires": {
"execa": "^0.7.0",
"lcid": "^1.0.0",
"mem": "^1.1.0"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@ -6753,7 +7115,7 @@
"dependencies": {
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
}
@ -7030,7 +7392,8 @@
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
"dev": true
},
"psl": {
"version": "1.1.32",
@ -7097,7 +7460,7 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
}
@ -7565,9 +7928,9 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@ -8423,16 +8786,23 @@
"dev": true
},
"uglify-js": {
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz",
"integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==",
"dev": true,
"optional": true,
"requires": {
"commander": "~2.17.1",
"commander": "~2.20.3",
"source-map": "~0.6.1"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true,
"optional": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@ -8472,38 +8842,15 @@
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"unique-stream": {
@ -8797,7 +9144,8 @@
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
"dev": true
},
"yargonaut": {
"version": "1.1.4",
@ -9032,14 +9380,6 @@
}
}
},
"yargs-parser": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
"integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
"requires": {
"camelcase": "^4.1.0"
}
},
"yargs-unparser": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz",

View File

@ -13,6 +13,7 @@
"browser": {
"./browser/driver/postgres/PostgresDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js",
"./browser/driver/oracle/OracleDriver.ts": "./browser/platform/BrowserDisabledDriversDummy.js",
"./browser/driver/sap/SapDriver.ts": "./browser/platform/BrowserDisabledDriversDummy.js",
"./browser/driver/mysql/MysqlDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js",
"./browser/driver/sqlserver/SqlServerDriver.ts": "./browser/platform/BrowserDisabledDriversDummy.js",
"./browser/driver/mongodb/MongoDriver.js": "./browser/platform/BrowserDisabledDriversDummy.js",
@ -46,6 +47,7 @@
"oracle-orm"
],
"devDependencies": {
"@sap/hdbext": "^6.1.1",
"@types/chai": "^4.1.2",
"@types/chai-as-promised": "7.1.0",
"@types/debug": "4.1.2",

View File

@ -3,63 +3,20 @@ import {ConnectionOptions, createConnection} from "../../src/index";
import {Post} from "./entity/Post";
const options: ConnectionOptions = {
// type: "oracle",
// host: "localhost",
// username: "system",
// password: "oracle",
// port: 1521,
// sid: "xe.oracle.docker",
"name": "mysql",
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "test",
"password": "test",
"database": "test",
// type: "postgres",
// host: "localhost",
// port: 5432,
// username: "test",
// password: "test",
// database: "test",
// "type": "mssql",
// "host": "192.168.1.6",
// "username": "sa",
// "password": "admin12345",
// "database": "test",
// port: 1521,
// type: "sqlite",
// database: "temp/sqlitedb.db",
// logger: "file",
// logging: ["query", "error"],
// logging: ["error", "schema", "query"],
// maxQueryExecutionTime: 90,
"name": "sap",
"type": "sap",
"host": "192.168.56.102",
"port": 39015,
"username": "SYSTEM",
"password": "MySuperHanaPwd123!",
"database": "HXE",
"logging": true,
synchronize: true,
entities: [Post]
};
createConnection(options).then(async connection => {
// const posts: Post[] = [];
// for (let i = 0; i < 100; i++) {
// let post = new Post();
// post.text = "Hello how are you?";
// post.title = "hello";
// post.likesCount = 100;
// posts.push(post);
// }
//
// await connection.manager.save(posts);
// try {
// await connection.query("CREATE DATABASE 'aaaa' AND DIE");
//
// } catch (err) {
// console.log("-------------------------------");
// console.log("ERRROR: ", err instanceof QueryFailedError);
// console.log(err);
// }
let post = new Post();
post.text = "Hello how are you?";
post.title = "hello";

View File

@ -1,14 +1,14 @@
import {QueryResultCache} from "./QueryResultCache";
import {QueryResultCacheOptions} from "./QueryResultCacheOptions";
import {Table} from "../schema-builder/table/Table";
import {QueryRunner} from "../query-runner/QueryRunner";
import {Connection} from "../connection/Connection";
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
import {MssqlParameter} from "../driver/sqlserver/MssqlParameter";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {Connection} from "../connection/Connection";
import {OracleDriver} from "../driver/oracle/OracleDriver";
import {PostgresConnectionOptions} from "../driver/postgres/PostgresConnectionOptions";
import {MssqlParameter} from "../driver/sqlserver/MssqlParameter";
import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions";
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
import {QueryRunner} from "../query-runner/QueryRunner";
import {Table} from "../schema-builder/table/Table";
import {QueryResultCache} from "./QueryResultCache";
import {QueryResultCacheOptions} from "./QueryResultCacheOptions";
/**
* Caches query result into current database, into separate table called "query-result-cache".
@ -28,7 +28,7 @@ export class DbQueryResultCache implements QueryResultCache {
constructor(protected connection: Connection) {
const options = <SqlServerConnectionOptions|PostgresConnectionOptions>this.connection.driver.options;
const cacheOptions = typeof this.connection.options.cache === "object" ? this.connection.options.cache : {};
const cacheOptions = typeof this.connection.options.cache === "object" ? this.connection.options.cache : {};
const cacheTableName = cacheOptions.tableName || "query-result-cache";
this.queryResultCacheTable = this.connection.driver.buildTableName(cacheTableName, options.schema, options.database);

View File

@ -257,7 +257,7 @@ export class Connection {
*/
// TODO rename
async dropDatabase(): Promise<void> {
const queryRunner = await this.createQueryRunner("master");
const queryRunner = this.createQueryRunner("master");
try {
if (this.driver instanceof SqlServerDriver || this.driver instanceof MysqlDriver || this.driver instanceof AuroraDataApiDriver) {
const databases: string[] = this.driver.database ? [this.driver.database] : [];

View File

@ -11,6 +11,7 @@ import {ReactNativeConnectionOptions} from "../driver/react-native/ReactNativeCo
import {NativescriptConnectionOptions} from "../driver/nativescript/NativescriptConnectionOptions";
import {ExpoConnectionOptions} from "../driver/expo/ExpoConnectionOptions";
import {AuroraDataApiConnectionOptions} from "../driver/aurora-data-api/AuroraDataApiConnectionOptions";
import {SapConnectionOptions} from "../driver/sap/SapConnectionOptions";
/**
@ -24,6 +25,7 @@ export type ConnectionOptions =
CockroachConnectionOptions|
SqliteConnectionOptions|
SqlServerConnectionOptions|
SapConnectionOptions|
OracleConnectionOptions|
CordovaConnectionOptions|
NativescriptConnectionOptions|

View File

@ -14,6 +14,7 @@ import {ExpoDriver} from "./expo/ExpoDriver";
import {AuroraDataApiDriver} from "./aurora-data-api/AuroraDataApiDriver";
import {Driver} from "./Driver";
import {Connection} from "../connection/Connection";
import {SapDriver} from "./sap/SapDriver";
/**
* Helps to create drivers.
@ -32,6 +33,8 @@ export class DriverFactory {
return new PostgresDriver(connection);
case "cockroachdb":
return new CockroachDriver(connection);
case "sap":
return new SapDriver(connection);
case "mariadb":
return new MysqlDriver(connection);
case "sqlite":

View File

@ -1533,7 +1533,7 @@ export class CockroachQueryRunner extends BaseQueryRunner implements QueryRunner
const foreignKeys = dbForeignKeys.filter(dbFk => dbFk["constraint_name"] === dbForeignKey["constraint_name"]);
// if referenced table located in currently used schema, we don't need to concat schema name to table name.
const schema = dbForeignKey["referenced_table_schema"] === currentSchema ? undefined : dbTable["referenced_table_schema"];
const schema = dbForeignKey["referenced_table_schema"] === currentSchema ? undefined : dbForeignKey["referenced_table_schema"];
const referencedTableName = this.driver.buildTableName(dbForeignKey["referenced_table_name"], schema);
return new TableForeignKey({

View File

@ -1612,7 +1612,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
const foreignKeys = dbForeignKeys.filter(dbFk => dbFk["constraint_name"] === dbForeignKey["constraint_name"]);
// if referenced table located in currently used schema, we don't need to concat schema name to table name.
const schema = dbForeignKey["referenced_table_schema"] === currentSchema ? undefined : dbTable["referenced_table_schema"];
const schema = dbForeignKey["referenced_table_schema"] === currentSchema ? undefined : dbForeignKey["referenced_table_schema"];
const referencedTableName = this.driver.buildTableName(dbForeignKey["referenced_table_name"], schema);
return new TableForeignKey({

View File

@ -0,0 +1,31 @@
/**
* SAP Hana specific connection credential options.
*/
export interface SapConnectionCredentialsOptions {
/**
* Database host.
*/
readonly host?: string;
/**
* Database host port.
*/
readonly port?: number;
/**
* Database username.
*/
readonly username?: string;
/**
* Database password.
*/
readonly password?: string;
/**
* Database name to connect to.
*/
readonly database?: string;
}

View File

@ -0,0 +1,19 @@
import {BaseConnectionOptions} from "../../connection/BaseConnectionOptions";
import {SapConnectionCredentialsOptions} from "./SapConnectionCredentialsOptions";
/**
* SAP Hana specific connection options.
*/
export interface SapConnectionOptions extends BaseConnectionOptions, SapConnectionCredentialsOptions {
/**
* Database type.
*/
readonly type: "sap";
/**
* Database schema.
*/
readonly schema?: string;
}

645
src/driver/sap/SapDriver.ts Normal file
View File

@ -0,0 +1,645 @@
import {ColumnType, Connection, EntityMetadata, ObjectLiteral, TableColumn} from "../..";
import {DriverPackageNotInstalledError} from "../../error/DriverPackageNotInstalledError";
import {ColumnMetadata} from "../../metadata/ColumnMetadata";
import {PlatformTools} from "../../platform/PlatformTools";
import {RdbmsSchemaBuilder} from "../../schema-builder/RdbmsSchemaBuilder";
import {ApplyValueTransformers} from "../../util/ApplyValueTransformers";
import {DateUtils} from "../../util/DateUtils";
import {OrmUtils} from "../../util/OrmUtils";
import {Driver} from "../Driver";
import {DataTypeDefaults} from "../types/DataTypeDefaults";
import {MappedColumnTypes} from "../types/MappedColumnTypes";
import {SapConnectionOptions} from "./SapConnectionOptions";
import {SapQueryRunner} from "./SapQueryRunner";
/**
* Organizes communication with SAP Hana DBMS.
*
* todo: looks like there is no built in support for connection pooling, we need to figure out something
*/
export class SapDriver implements Driver {
// -------------------------------------------------------------------------
// Public Properties
// -------------------------------------------------------------------------
/**
* Connection used by driver.
*/
connection: Connection;
/**
* Hana client instance.
*/
client: any;
/**
* Pool for master database.
*/
master: any;
/**
* Pool for slave databases.
* Used in replication.
*/
slaves: any[] = [];
// -------------------------------------------------------------------------
// Public Implemented Properties
// -------------------------------------------------------------------------
/**
* Connection options.
*/
options: SapConnectionOptions;
/**
* Master database used to perform all write queries.
*/
database?: string;
/**
* Indicates if replication is enabled.
*/
isReplicated: boolean = false;
/**
* Indicates if tree tables are supported by this driver.
*/
treeSupport = true;
/**
* Gets list of supported column data types by a driver.
*
* @see https://help.sap.com/viewer/4fe29514fd584807ac9f2a04f6754767/2.0.03/en-US/20a1569875191014b507cf392724b7eb.html
*/
supportedDataTypes: ColumnType[] = [
"tinyint",
"smallint",
"int",
"integer",
"bigint",
"smalldecimal",
"decimal",
"dec",
"real",
"double",
"float",
"date",
"time",
"seconddate",
"timestamp",
"boolean",
"char",
"nchar",
"varchar",
"nvarchar",
"text",
"alphanum",
"shorttext",
"array",
"varbinary",
"blob",
"clob",
"nclob",
"st_geometry",
"st_point",
];
/**
* Gets list of spatial column data types.
*/
spatialTypes: ColumnType[] = [
"st_geometry",
"st_point",
];
/**
* Gets list of column data types that support length by a driver.
*/
withLengthColumnTypes: ColumnType[] = [
"varchar",
"nvarchar",
"alphanum",
"shorttext",
"varbinary"
];
/**
* Gets list of column data types that support precision by a driver.
*/
withPrecisionColumnTypes: ColumnType[] = [
"decimal",
];
/**
* Gets list of column data types that support scale by a driver.
*/
withScaleColumnTypes: ColumnType[] = [
"decimal",
];
/**
* Orm has special columns and we need to know what database column types should be for those types.
* Column types are driver dependant.
*/
mappedDataTypes: MappedColumnTypes = {
createDate: "timestamp",
createDateDefault: "CURRENT_TIMESTAMP",
updateDate: "timestamp",
updateDateDefault: "CURRENT_TIMESTAMP",
version: "integer",
treeLevel: "integer",
migrationId: "integer",
migrationName: "nvarchar",
migrationTimestamp: "bigint",
cacheId: "integer",
cacheIdentifier: "nvarchar",
cacheTime: "bigint",
cacheDuration: "integer",
cacheQuery: "nvarchar(5000)" as any,
cacheResult: "text",
metadataType: "nvarchar",
metadataDatabase: "nvarchar",
metadataSchema: "nvarchar",
metadataTable: "nvarchar",
metadataName: "nvarchar",
metadataValue: "nvarchar(5000)" as any,
};
/**
* Default values of length, precision and scale depends on column data type.
* Used in the cases when length/precision/scale is not specified by user.
*/
dataTypeDefaults: DataTypeDefaults = {
"char": { length: 1 },
"nchar": { length: 1 },
"varchar": { length: 255 },
"nvarchar": { length: 255 },
"shorttext": { length: 255 },
"varbinary": { length: 255 },
"decimal": { precision: 18, scale: 0 },
};
/**
* Max length allowed by SAP HANA for aliases (identifiers).
* @see https://help.sap.com/viewer/4fe29514fd584807ac9f2a04f6754767/2.0.03/en-US/20a760537519101497e3cfe07b348f3c.html
*/
maxAliasLength = 128;
// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------
constructor(connection: Connection) {
this.connection = connection;
this.options = connection.options as SapConnectionOptions;
this.loadDependencies();
}
// -------------------------------------------------------------------------
// Public Implemented Methods
// -------------------------------------------------------------------------
/**
* Performs connection to the database.
* Based on pooling options, it can either create connection immediately,
* either create a pool and create connection when needed.
*/
async connect(): Promise<void> {
// this.master = await this.createConnection(this.options);
this.database = this.options.database;
}
/**
* Makes any action after connection (e.g. create extensions in Postgres driver).
*/
afterConnect(): Promise<void> {
return Promise.resolve();
}
/**
* Closes connection with the database.
*/
async disconnect(): Promise<void> {
await this.closeConnection();
this.master = undefined;
}
/**
* Closes connection pool.
*/
protected async closeConnection(): Promise<void> {
return new Promise<void>((ok, fail) => {
if (!this.master) return ok();
this.master.disconnect((err: any) => err ? fail(err) : ok());
});
}
/**
* Creates a schema builder used to build and sync a schema.
*/
createSchemaBuilder() {
return new RdbmsSchemaBuilder(this.connection);
}
/**
* Creates a query runner used to execute database queries.
*/
createQueryRunner(mode: "master"|"slave" = "master") {
return new SapQueryRunner(this, mode);
}
/**
* Replaces parameters in the given sql with special escaping character
* and an array of parameter names to be passed to a query.
*/
escapeQueryWithParameters(sql: string, parameters: ObjectLiteral, nativeParameters: ObjectLiteral): [string, any[]] {
const builtParameters: any[] = Object.keys(nativeParameters).map(key => {
return nativeParameters[key];
});
if (!parameters || !Object.keys(parameters).length)
return [sql, builtParameters];
const keys = Object.keys(parameters).map(parameter => "(:(\\.\\.\\.)?" + parameter + "\\b)").join("|");
sql = sql.replace(new RegExp(keys, "g"), (key: string): string => {
let value: any;
let isArray = false;
if (key.substr(0, 4) === ":...") {
isArray = true;
value = parameters[key.substr(4)];
} else {
value = parameters[key.substr(1)];
}
if (isArray) {
return value.map((v: any) => {
builtParameters.push(v);
return "?";
// return "$" + builtParameters.length;
}).join(", ");
} else if (value instanceof Function) {
return value();
} else {
builtParameters.push(value);
return "?";
// return "$" + builtParameters.length;
}
}); // todo: make replace only in value statements, otherwise problems
return [sql, builtParameters];
}
/**
* Escapes a column name.
*/
escape(columnName: string): string {
return `"${columnName}"`;
}
/**
* Build full table name with schema name and table name.
* E.g. "mySchema"."myTable"
*/
buildTableName(tableName: string, schema?: string): string {
return schema ? `${schema}.${tableName}` : tableName;
}
/**
* Prepares given value to a value to be persisted, based on its column type and metadata.
*/
preparePersistentValue(value: any, columnMetadata: ColumnMetadata): any {
if (columnMetadata.transformer)
value = ApplyValueTransformers.transformTo(columnMetadata.transformer, value);
if (value === null || value === undefined)
return value;
if (columnMetadata.type === Boolean) {
return value === true ? 1 : 0;
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value);
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value);
} else if (columnMetadata.type === "timestamp"
|| columnMetadata.type === Date) {
return DateUtils.mixedDateToDatetimeString(value, true);
} else if (columnMetadata.type === "seconddate") {
return DateUtils.mixedDateToDatetimeString(value, false);
} else if (columnMetadata.type === "simple-array") {
return DateUtils.simpleArrayToString(value);
} else if (columnMetadata.type === "simple-json") {
return DateUtils.simpleJsonToString(value);
} else if (columnMetadata.type === "simple-enum") {
return DateUtils.simpleEnumToString(value);
} else if (columnMetadata.isArray) {
return () => `ARRAY(${value.map((it: any) => `'${it}'`)})`;
}
return value;
}
/**
* Prepares given value to a value to be persisted, based on its column type or metadata.
*/
prepareHydratedValue(value: any, columnMetadata: ColumnMetadata): any {
if (value === null || value === undefined)
return columnMetadata.transformer ? ApplyValueTransformers.transformFrom(columnMetadata.transformer, value) : value;
if (columnMetadata.type === Boolean) {
value = value ? true : false;
} else if (columnMetadata.type === "timestamp"
|| columnMetadata.type === "seconddate"
|| columnMetadata.type === Date) {
value = DateUtils.normalizeHydratedDate(value);
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value);
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value);
} else if (columnMetadata.type === "simple-array") {
value = DateUtils.stringToSimpleArray(value);
} else if (columnMetadata.type === "simple-json") {
value = DateUtils.stringToSimpleJson(value);
} else if (columnMetadata.type === "simple-enum") {
value = DateUtils.stringToSimpleEnum(value, columnMetadata);
}
if (columnMetadata.transformer)
value = ApplyValueTransformers.transformFrom(columnMetadata.transformer, value);
return value;
}
/**
* Creates a database type from a given column metadata.
*/
normalizeType(column: { type?: ColumnType, length?: number | string, precision?: number|null, scale?: number }): string {
if (column.type === Number || column.type === "integer") {
return "integer";
} else if (column.type === String) {
return "nvarchar";
} else if (column.type === Date) {
return "timestamp";
} else if (column.type === Boolean) {
return "boolean";
} else if ((column.type as any) === Buffer) {
return "blob";
} else if (column.type === "uuid") {
return "nvarchar";
} else if (column.type === "simple-array" || column.type === "simple-json") {
return "text";
} else if (column.type === "simple-enum") {
return "nvarchar";
} else {
return column.type as string || "";
}
}
/**
* Normalizes "default" value of the column.
*/
normalizeDefault(columnMetadata: ColumnMetadata): string {
const defaultValue = columnMetadata.default;
if (typeof defaultValue === "number") {
return "" + defaultValue;
} else if (typeof defaultValue === "function") {
return defaultValue();
} else if (typeof defaultValue === "string") {
return `'${defaultValue}'`;
} else {
return defaultValue;
}
}
/**
* Normalizes "isUnique" value of the column.
*/
normalizeIsUnique(column: ColumnMetadata): boolean {
return column.entityMetadata.indices.some(idx => idx.isUnique && idx.columns.length === 1 && idx.columns[0] === column);
}
/**
* Returns default column lengths, which is required on column creation.
*/
getColumnLength(column: ColumnMetadata|TableColumn): string {
if (column.length)
return column.length.toString();
if (column.generationStrategy === "uuid")
return "36";
switch (column.type) {
case "varchar":
case "nvarchar":
case "shorttext":
case String:
return "255";
case "alphanum":
return "127";
case "varbinary":
return "255";
}
return "";
}
/**
* Creates column type definition including length, precision and scale
*/
createFullType(column: TableColumn): string {
let type = column.type;
// used 'getColumnLength()' method, because SqlServer sets `varchar` and `nvarchar` length to 1 by default.
if (this.getColumnLength(column)) {
type += `(${this.getColumnLength(column)})`;
} else if (column.precision !== null && column.precision !== undefined && column.scale !== null && column.scale !== undefined) {
type += `(${column.precision},${column.scale})`;
} else if (column.precision !== null && column.precision !== undefined) {
type += `(${column.precision})`;
}
if (column.isArray)
type += " array";
return type;
}
/**
* Obtains a new database connection to a master server.
* Used for replication.
* If replication is not setup then returns default connection's database connection.
*/
obtainMasterConnection(): Promise<any> {
return this.createConnection();
}
/**
* Obtains a new database connection to a slave server.
* Used for replication.
* If replication is not setup then returns master (default) connection's database connection.
*/
obtainSlaveConnection(): Promise<any> {
// return Promise.resolve(this.master);
return this.createConnection();
}
/**
* Creates generated map of values generated or returned by database after INSERT query.
*/
createGeneratedMap(metadata: EntityMetadata, insertResult: ObjectLiteral) {
const generatedMap = metadata.generatedColumns.reduce((map, generatedColumn) => {
let value: any;
if (generatedColumn.generationStrategy === "increment" && insertResult) {
value = insertResult;
// } else if (generatedColumn.generationStrategy === "uuid") {
// console.log("getting db value:", generatedColumn.databaseName);
// value = generatedColumn.getEntityValue(uuidMap);
}
return OrmUtils.mergeDeep(map, generatedColumn.createValueMap(value));
}, {} as ObjectLiteral);
return Object.keys(generatedMap).length > 0 ? generatedMap : undefined;
}
/**
* Differentiate columns of this table and columns from the given column metadatas columns
* and returns only changed.
*/
findChangedColumns(tableColumns: TableColumn[], columnMetadatas: ColumnMetadata[]): ColumnMetadata[] {
return columnMetadatas.filter(columnMetadata => {
const tableColumn = tableColumns.find(c => c.name === columnMetadata.databaseName);
if (!tableColumn)
return false; // we don't need new columns, we only need exist and changed
// console.log("table:", columnMetadata.entityMetadata.tableName);
// console.log("name:", tableColumn.name, columnMetadata.databaseName);
// console.log("type:", tableColumn.type, this.normalizeType(columnMetadata));
// console.log("length:", tableColumn.length, columnMetadata.length);
// console.log("width:", tableColumn.width, columnMetadata.width);
// console.log("precision:", tableColumn.precision, columnMetadata.precision);
// console.log("scale:", tableColumn.scale, columnMetadata.scale);
// console.log("default:", tableColumn.default, columnMetadata.default);
// console.log("isPrimary:", tableColumn.isPrimary, columnMetadata.isPrimary);
// console.log("isNullable:", tableColumn.isNullable, columnMetadata.isNullable);
// console.log("isUnique:", tableColumn.isUnique, this.normalizeIsUnique(columnMetadata));
// console.log("isGenerated:", tableColumn.isGenerated, columnMetadata.isGenerated);
// console.log((columnMetadata.generationStrategy !== "uuid" && tableColumn.isGenerated !== columnMetadata.isGenerated));
// console.log("==========================================");
return tableColumn.name !== columnMetadata.databaseName
|| tableColumn.type !== this.normalizeType(columnMetadata)
|| tableColumn.length !== columnMetadata.length
|| tableColumn.precision !== columnMetadata.precision
|| tableColumn.scale !== columnMetadata.scale
// || tableColumn.comment !== columnMetadata.comment || // todo
|| (!tableColumn.isGenerated && this.normalizeDefault(columnMetadata) !== tableColumn.default) // we included check for generated here, because generated columns already can have default values
|| tableColumn.isPrimary !== columnMetadata.isPrimary
|| tableColumn.isNullable !== columnMetadata.isNullable
|| tableColumn.isUnique !== this.normalizeIsUnique(columnMetadata)
|| tableColumn.isGenerated !== columnMetadata.isGenerated;
});
}
/**
* Returns true if driver supports RETURNING / OUTPUT statement.
*/
isReturningSqlSupported(): boolean {
return false;
}
/**
* Returns true if driver supports uuid values generation on its own.
*/
isUUIDGenerationSupported(): boolean {
return false;
}
/**
* Creates an escaped parameter.
*/
createParameter(parameterName: string, index: number): string {
return "?";
}
// -------------------------------------------------------------------------
// Protected Methods
// -------------------------------------------------------------------------
/**
* If driver dependency is not given explicitly, then try to load it via "require".
*/
protected loadDependencies(): void {
try {
this.client = PlatformTools.load("@sap/hdbext");
} catch (e) { // todo: better error for browser env
throw new DriverPackageNotInstalledError("SAP Hana", "hdb");
}
}
/**
* Creates a new connection pool for a given database credentials.
*/
protected createConnection(): Promise<any> {
// pooling is enabled either when its set explicitly to true,
// either when its not defined at all (e.g. enabled by default)
return new Promise<any>((ok, fail) => {
try {
// const master = ();
this.client.createConnection({
host: this.options.host,
port: this.options.port,
uid: this.options.username,
pwd: this.options.password,
databaseName: this.options.database,
pooling: true,
...this.options.extra
}, (err: any, master: any) => {
if (err) {
fail(err);
return;
}
ok(master);
});
} catch (err) {
fail(err);
}
});
}
}

File diff suppressed because it is too large Load Diff

View File

@ -613,7 +613,7 @@ export class SqlServerDriver implements Driver {
});
}
private lowerDefaultValueIfNessesary(value: string | undefined) {
// SqlServer saves function calls in default value as lowercase #2733
// SqlServer saves function calls in default value as lowercase https://github.com/typeorm/typeorm/issues/2733
if (!value) {
return value;
}

View File

@ -1,17 +1,18 @@
/**
* Column types used for @PrimaryGeneratedColumn() decorator.
*/
export type PrimaryGeneratedColumnType = "int" // mysql, mssql, oracle, sqlite
export type PrimaryGeneratedColumnType = "int" // mysql, mssql, oracle, sqlite, sap
|"int2" // postgres, sqlite, cockroachdb
|"int4" // postgres, cockroachdb
|"int8" // postgres, sqlite, cockroachdb
|"integer" // postgres, oracle, sqlite, mysql, cockroachdb
|"tinyint" // mysql, mssql, sqlite
|"smallint" // mysql, postgres, mssql, oracle, sqlite, cockroachdb
|"integer" // postgres, oracle, sqlite, mysql, cockroachdb, sap
|"tinyint" // mysql, mssql, sqlite, sap
|"smallint" // mysql, postgres, mssql, oracle, sqlite, cockroachdb, sap
|"mediumint" // mysql, sqlite
|"bigint" // mysql, postgres, mssql, sqlite, cockroachdb
|"dec" // oracle, mssql
|"decimal" // mysql, postgres, mssql, sqlite
|"bigint" // mysql, postgres, mssql, sqlite, cockroachdb, sap
|"dec" // oracle, mssql, sap
|"decimal" // mysql, postgres, mssql, sqlite, sap
|"smalldecimal" // sap
|"fixed" // mysql
|"numeric" // postgres, mssql, sqlite
|"number" // oracle
@ -21,7 +22,9 @@ export type PrimaryGeneratedColumnType = "int" // mysql, mssql, oracle, sqlite
* Column types where spatial properties are used.
*/
export type SpatialColumnType = "geometry" // postgres
|"geography"; // postgres
|"geography" // postgres
|"st_geometry" // sap
|"st_point"; // sap
/**
* Column types where precision and scale properties are used.
@ -30,9 +33,10 @@ export type WithPrecisionColumnType = "float" // mysql, mssql, oracle, sqlite
|"double" // mysql, sqlite
|"dec" // oracle, mssql, mysql
|"decimal" // mysql, postgres, mssql, sqlite
|"smalldecimal" // sap
|"fixed" // mysql
|"numeric" // postgres, mssql, sqlite, mysql
|"real" // mysql, postgres, mssql, oracle, sqlite, cockroachdb
|"real" // mysql, postgres, mssql, oracle, sqlite, cockroachdb, sap
|"double precision" // postgres, oracle, sqlite, mysql, cockroachdb
|"number" // oracle
|"datetime" // mssql, mysql, sqlite
@ -57,14 +61,16 @@ export type WithLengthColumnType = "character varying" // postgres, cockroachdb
|"character" // mysql, postgres, sqlite, cockroachdb
|"native character" // sqlite
|"varchar" // mysql, postgres, mssql, sqlite, cockroachdb
|"char" // mysql, postgres, mssql, oracle, cockroachdb
|"nchar" // mssql, oracle, sqlite, mysql
|"char" // mysql, postgres, mssql, oracle, cockroachdb, sap
|"nchar" // mssql, oracle, sqlite, mysql, sap
|"national char" // mysql
|"varchar2" // oracle
|"nvarchar2" // oracle, sqlite
|"alphanum" // sap
|"shorttext" // sap
|"raw" // oracle
|"binary" // mssql
|"varbinary" // mssql
|"varbinary" // mssql, sap
|"string"; // cockroachdb
export type WithWidthColumnType = "tinyint" // mysql
@ -86,13 +92,13 @@ export type SimpleColumnType =
|"simple-enum" // typeorm-specific, automatically mapped to string
// numeric types
|"bit" // mssql
|"int2" // postgres, sqlite, cockroachdb
|"integer" // postgres, oracle, sqlite, cockroachdb
|"int4" // postgres, cockroachdb
|"int8" // postgres, sqlite, cockroachdb
|"int64" // cockroachdb
|"unsigned big int" // sqlite
|"float" // mysql, mssql, oracle, sqlite, sap
|"float4" // postgres, cockroachdb
|"float8" // postgres, cockroachdb
|"smallmoney" // mssql
@ -107,21 +113,23 @@ export type SimpleColumnType =
|"tinytext" // mysql
|"mediumblob" // mysql
|"mediumtext" // mysql
|"blob" // mysql, oracle, sqlite, cockroachdb
|"text" // mysql, postgres, mssql, sqlite, cockroachdb
|"blob" // mysql, oracle, sqlite, cockroachdb, sap
|"text" // mysql, postgres, mssql, sqlite, cockroachdb, sap
|"ntext" // mssql
|"citext" // postgres
|"hstore" // postgres
|"longblob" // mysql
|"longtext" // mysql
|"alphanum" // sap
|"shorttext" // sap
|"bytes" // cockroachdb
|"bytea" // postgres, cockroachdb
|"long" // oracle
|"raw" // oracle
|"long raw" // oracle
|"bfile" // oracle
|"clob" // oracle, sqlite
|"nclob" // oracle
|"clob" // oracle, sqlite, sap
|"nclob" // oracle, sap
|"image" // mssql
// date types
@ -134,6 +142,7 @@ export type SimpleColumnType =
|"interval day to second" // oracle
|"interval" // postgres, cockroachdb
|"year" // mysql
|"seconddate" // sap
// geometric types
|"point" // postgres, mysql
@ -150,6 +159,8 @@ export type SimpleColumnType =
|"multilinestring" // mysql
|"multipolygon" // mysql
|"geometrycollection" // mysql
|"st_geometry" // sap
|"st_point" // sap
// range types
|"int4range" // postgres
@ -165,7 +176,7 @@ export type SimpleColumnType =
|"cidr" // postgres
|"inet" // postgres, cockroachdb
|"macaddr"// postgres
|"bit" // postgres
|"bit" // postgres, mssql
|"bit varying" // postgres
|"varbit"// postgres
|"tsvector" // postgres
@ -174,14 +185,14 @@ export type SimpleColumnType =
|"xml" // mssql, postgres
|"json" // mysql, postgres, cockroachdb
|"jsonb" // postgres, cockroachdb
|"varbinary" // mssql
|"varbinary" // mssql, sap
|"hierarchyid" // mssql
|"sql_variant" // mssql
|"rowid" // oracle
|"urowid" // oracle
|"uniqueidentifier" // mssql
|"rowversion" // mssql
|"array" // cockroachdb
|"array" // cockroachdb, sap
|"cube"; // postgres
/**

View File

@ -5,6 +5,7 @@ export type DatabaseType =
"mysql"|
"postgres"|
"cockroachdb"|
"sap"|
"mariadb"|
"sqlite"|
"cordova"|

View File

@ -4,10 +4,10 @@
export class OffsetWithoutLimitNotSupportedError extends Error {
name = "OffsetWithoutLimitNotSupportedError";
constructor(driverName: string) {
constructor() {
super();
Object.setPrototypeOf(this, OffsetWithoutLimitNotSupportedError.prototype);
this.message = `${driverName} does not support OFFSET without LIMIT in SELECT statements. You must use limit in conjunction with offset function (or take in conjunction with skip function if you are using pagination).`;
this.message = `RDBMS does not support OFFSET without LIMIT in SELECT statements. You must use limit in conjunction with offset function (or take in conjunction with skip function if you are using pagination).`;
}
}
}

View File

@ -1,4 +1,5 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../driver/sap/SapDriver";
import {EntityMetadata} from "../metadata/EntityMetadata";
import {ColumnMetadata} from "../metadata/ColumnMetadata";
import {IndexMetadata} from "../metadata/IndexMetadata";
@ -129,7 +130,8 @@ export class EntityMetadataBuilder {
entityMetadata.foreignKeys.push(foreignKey);
}
if (uniqueConstraint) {
if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver || this.connection.driver instanceof SqlServerDriver) {
if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver
|| this.connection.driver instanceof SqlServerDriver || this.connection.driver instanceof SapDriver) {
const index = new IndexMetadata({
entityMetadata: uniqueConstraint.entityMetadata,
columns: uniqueConstraint.columns,
@ -520,8 +522,8 @@ export class EntityMetadataBuilder {
});
}
// Mysql stores unique constraints as unique indices.
if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) {
// Mysql and SAP HANA stores unique constraints as unique indices.
if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver || this.connection.driver instanceof SapDriver) {
const indices = this.metadataArgsStorage.filterUniques(entityMetadata.inheritanceTree).map(args => {
return new IndexMetadata({
entityMetadata: entityMetadata,

View File

@ -3,6 +3,7 @@ import {ObjectLiteral} from "../common/ObjectLiteral";
import {Connection} from "../connection/Connection";
import {PostgresConnectionOptions} from "../driver/postgres/PostgresConnectionOptions";
import {PostgresDriver} from "../driver/postgres/PostgresDriver";
import {SapDriver} from "../driver/sap/SapDriver";
import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions";
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
import {CannotCreateEntityIdMapError} from "../error/CannotCreateEntityIdMapError";
@ -104,7 +105,7 @@ export class EntityMetadata {
/**
* Enables Sqlite "WITHOUT ROWID" modifier for the "CREATE TABLE" statement
*/
withoutRowid?: boolean = false;
withoutRowid?: boolean = false;
/**
* Original user-given table name (taken from schema or @Entity(tableName) decorator).
@ -846,7 +847,7 @@ export class EntityMetadata {
*/
protected buildTablePath(): string {
let tablePath = this.tableName;
if (this.schema && ((this.connection.driver instanceof PostgresDriver) || (this.connection.driver instanceof SqlServerDriver))) {
if (this.schema && ((this.connection.driver instanceof PostgresDriver) || (this.connection.driver instanceof SqlServerDriver) || (this.connection.driver instanceof SapDriver))) {
tablePath = this.schema + "." + tablePath;
}

View File

@ -1,3 +1,4 @@
import {SapDriver} from "../driver/sap/SapDriver";
import {QueryRunner} from "../query-runner/QueryRunner";
import {Subject} from "./Subject";
import {PromiseUtils} from "../util/PromiseUtils";
@ -249,7 +250,8 @@ export class SubjectExecutor {
// - when oracle is used, since oracle's bulk insertion is very bad
if (subject.changeMaps.length === 0 ||
subject.metadata.treeType ||
this.queryRunner.connection.driver instanceof OracleDriver) {
this.queryRunner.connection.driver instanceof OracleDriver ||
this.queryRunner.connection.driver instanceof SapDriver) {
singleInsertSubjects.push(subject);
} else {

View File

@ -43,6 +43,12 @@ export class PostgresDriver {}
*/
export class SqlServerDriver {}
/**
* DO NOT IMPORT THIS CLASS -
* This is a dummy class for replacement via `package.json` in browser builds
*/
export class SapDriver {}
/**
* DO NOT IMPORT THIS CLASS -
* This is a dummy class for replacement via `package.json` in browser builds

View File

@ -46,6 +46,12 @@ export class PlatformTools {
case "mongodb":
return require("mongodb");
/**
* hana
*/
case "@sap/hdbext":
return require("@sap/hdbext");
/**
* mysql
*/

View File

@ -1,4 +1,5 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../driver/sap/SapDriver";
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {ObjectType} from "../common/ObjectType";
@ -444,7 +445,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
// if value for this column was not provided then insert default value
} else if (value === undefined) {
if (this.connection.driver instanceof AbstractSqliteDriver) { // unfortunately sqlite does not support DEFAULT expression in INSERT queries
if (this.connection.driver instanceof AbstractSqliteDriver || this.connection.driver instanceof SapDriver) { // unfortunately sqlite does not support DEFAULT expression in INSERT queries
if (column.default !== undefined) { // try to use default defined in the column
expression += this.connection.driver.normalizeDefault(column);
} else {
@ -524,7 +525,7 @@ export class InsertQueryBuilder<Entity> extends QueryBuilder<Entity> {
// if value for this column was not provided then insert default value
} else if (value === undefined) {
if (this.connection.driver instanceof AbstractSqliteDriver) {
if (this.connection.driver instanceof AbstractSqliteDriver || this.connection.driver instanceof SapDriver) {
expression += "NULL";
} else {

View File

@ -1,3 +1,4 @@
import {SapDriver} from "../driver/sap/SapDriver";
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {QueryExpressionMap} from "./QueryExpressionMap";
@ -117,7 +118,7 @@ export class RelationUpdater {
if (!bulkInserted.length) return;
if (this.queryBuilder.connection.driver instanceof OracleDriver) {
if (this.queryBuilder.connection.driver instanceof OracleDriver || this.queryBuilder.connection.driver instanceof SapDriver) {
await Promise.all(bulkInserted.map(value => {
return this.queryBuilder
.createQueryBuilder()
@ -137,4 +138,4 @@ export class RelationUpdater {
}
}
}
}

View File

@ -1,3 +1,4 @@
import {SapDriver} from "../driver/sap/SapDriver";
import {RawSqlResultsToEntityTransformer} from "./transformer/RawSqlResultsToEntityTransformer";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {SqlServerDriver} from "../driver/sqlserver/SqlServerDriver";
@ -1592,14 +1593,14 @@ export class SelectQueryBuilder<Entity> extends QueryBuilder<Entity> implements
if (offset)
return prefix + " OFFSET " + offset + " ROWS";
} else if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver) {
} else if (this.connection.driver instanceof MysqlDriver || this.connection.driver instanceof AuroraDataApiDriver || this.connection.driver instanceof SapDriver) {
if (limit && offset)
return " LIMIT " + limit + " OFFSET " + offset;
if (limit)
return " LIMIT " + limit;
if (offset)
throw new OffsetWithoutLimitNotSupportedError("MySQL");
throw new OffsetWithoutLimitNotSupportedError();
} else if (this.connection.driver instanceof AbstractSqliteDriver) {

View File

@ -1,4 +1,5 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../driver/sap/SapDriver";
import {QueryBuilder} from "./QueryBuilder";
import {ObjectLiteral} from "../common/ObjectLiteral";
import {Connection} from "../connection/Connection";
@ -373,7 +374,8 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
let parametersCount = this.connection.driver instanceof MysqlDriver ||
this.connection.driver instanceof AuroraDataApiDriver ||
this.connection.driver instanceof OracleDriver ||
this.connection.driver instanceof AbstractSqliteDriver
this.connection.driver instanceof AbstractSqliteDriver ||
this.connection.driver instanceof SapDriver
? 0 : Object.keys(this.expressionMap.nativeParameters).length;
if (metadata) {
EntityMetadata.createPropertyPath(metadata, valuesSet).forEach(propertyPath => {
@ -401,6 +403,8 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
// todo: duplication zone
if (value instanceof Function) { // support for SQL expressions in update query
updateColumnAndValues.push(this.escape(column.databaseName) + " = " + value());
} else if (this.connection.driver instanceof SapDriver && value === null) {
updateColumnAndValues.push(this.escape(column.databaseName) + " = NULL");
} else {
if (this.connection.driver instanceof SqlServerDriver) {
value = this.connection.driver.parametrizeValue(column, value);
@ -412,7 +416,8 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
if (this.connection.driver instanceof MysqlDriver ||
this.connection.driver instanceof AuroraDataApiDriver ||
this.connection.driver instanceof OracleDriver ||
this.connection.driver instanceof AbstractSqliteDriver) {
this.connection.driver instanceof AbstractSqliteDriver ||
this.connection.driver instanceof SapDriver) {
newParameters[paramName] = value;
} else {
this.expressionMap.nativeParameters[paramName] = value;
@ -454,6 +459,8 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
// todo: duplication zone
if (value instanceof Function) { // support for SQL expressions in update query
updateColumnAndValues.push(this.escape(key) + " = " + value());
} else if (this.connection.driver instanceof SapDriver && value === null) {
updateColumnAndValues.push(this.escape(key) + " = NULL");
} else {
// we need to store array values in a special class to make sure parameter replacement will work correctly
@ -463,7 +470,8 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
if (this.connection.driver instanceof MysqlDriver ||
this.connection.driver instanceof AuroraDataApiDriver ||
this.connection.driver instanceof OracleDriver ||
this.connection.driver instanceof AbstractSqliteDriver) {
this.connection.driver instanceof AbstractSqliteDriver ||
this.connection.driver instanceof SapDriver) {
newParameters[key] = value;
} else {
this.expressionMap.nativeParameters[key] = value;
@ -484,7 +492,8 @@ export class UpdateQueryBuilder<Entity> extends QueryBuilder<Entity> implements
if (this.connection.driver instanceof MysqlDriver ||
this.connection.driver instanceof AuroraDataApiDriver ||
this.connection.driver instanceof OracleDriver ||
this.connection.driver instanceof AbstractSqliteDriver) {
this.connection.driver instanceof AbstractSqliteDriver ||
this.connection.driver instanceof SapDriver) {
this.expressionMap.nativeParameters = Object.assign(newParameters, this.expressionMap.nativeParameters);
}

View File

@ -11,5 +11,5 @@ export class DeleteResult {
* Number of affected rows/documents
* Not all drivers support this
*/
affected?: number;
}
affected?: number|null;
}

View File

@ -1,5 +1,6 @@
import {CockroachDriver} from "../driver/cockroachdb/CockroachDriver";
import {PostgresConnectionOptions} from "../driver/postgres/PostgresConnectionOptions";
import {SapDriver} from "../driver/sap/SapDriver";
import {SqlServerConnectionOptions} from "../driver/sqlserver/SqlServerConnectionOptions";
import {Table} from "./table/Table";
import {TableColumn} from "./table/TableColumn";
@ -367,7 +368,7 @@ export class RdbmsSchemaBuilder implements SchemaBuilder {
// check if table does not exist yet
const existTable = this.queryRunner.loadedTables.find(table => {
const database = metadata.database && metadata.database !== this.connection.driver.database ? metadata.database : undefined;
const schema = metadata.schema || (<SqlServerDriver|PostgresDriver>this.connection.driver).options.schema;
const schema = metadata.schema || (<SqlServerDriver|PostgresDriver|SapDriver>this.connection.driver).options.schema;
const fullTableName = this.connection.driver.buildTableName(metadata.tableName, schema, database);
return table.name === fullTableName;

View File

@ -43,7 +43,7 @@ export class TableForeignKey {
onUpdate?: string;
/**
* Set this foreign key constraint as "DEFERRABLE" e.g. check constraints at start
* Set this foreign key constraint as "DEFERRABLE" e.g. check constraints at start
* or at the end of a transaction
*/
deferrable?: string;

View File

@ -100,20 +100,25 @@ export class DateUtils {
/**
* Converts given value into datetime string in a "YYYY-MM-DD HH-mm-ss" format.
*/
static mixedDateToDatetimeString(value: Date|any): string|any {
static mixedDateToDatetimeString(value: Date|any, useMilliseconds?: boolean): string|any {
if (typeof value === "string") {
value = new Date(value);
}
if (value instanceof Date) {
return this.formatZerolessValue(value.getFullYear()) + "-" +
let finalValue = this.formatZerolessValue(value.getFullYear()) + "-" +
this.formatZerolessValue(value.getMonth() + 1) + "-" +
this.formatZerolessValue(value.getDate()) + " " +
this.formatZerolessValue(value.getHours()) + ":" +
this.formatZerolessValue(value.getMinutes()) + ":" +
this.formatZerolessValue(value.getSeconds()) + "." +
this.formatMilliseconds(value.getMilliseconds());
this.formatZerolessValue(value.getSeconds());
if (useMilliseconds)
finalValue += `.${this.formatMilliseconds(value.getMilliseconds())}`;
value = finalValue;
}
return value;
}
@ -171,7 +176,7 @@ export class DateUtils {
static stringToSimpleJson(value: any) {
try {
const simpleJSON = JSON.parse(value);
const simpleJSON = JSON.parse(value);
return (typeof simpleJSON === "object") ? simpleJSON : {};
} catch (err) {
return {};

View File

@ -1,7 +1,7 @@
import "reflect-metadata";
import {expect} from "chai";
import "reflect-metadata";
import {Connection} from "../../../../src";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {Post} from "./entity/Post";
describe("columns > readonly functionality", () => {

View File

@ -0,0 +1,56 @@
import "reflect-metadata";
import {expect} from "chai";
import {Post} from "./entity/Post";
import {Connection} from "../../../../../src";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
describe("database schema > column length > sap", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [Post],
enabledDrivers: ["sap"],
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("all types should create with correct size", () => Promise.all(connections.map(async connection => {
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("post");
await queryRunner.release();
expect(table!.findColumnByName("varchar")!.length).to.be.equal("50");
expect(table!.findColumnByName("nvarchar")!.length).to.be.equal("50");
expect(table!.findColumnByName("alphanum")!.length).to.be.equal("50");
expect(table!.findColumnByName("shorttext")!.length).to.be.equal("50");
expect(table!.findColumnByName("varbinary")!.length).to.be.equal("50");
})));
it("all types should update their size", () => Promise.all(connections.map(async connection => {
let metadata = connection.getMetadata(Post);
metadata.findColumnWithPropertyName("varchar")!.length = "100";
metadata.findColumnWithPropertyName("nvarchar")!.length = "100";
metadata.findColumnWithPropertyName("alphanum")!.length = "100";
metadata.findColumnWithPropertyName("shorttext")!.length = "100";
metadata.findColumnWithPropertyName("varbinary")!.length = "100";
await connection.synchronize();
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("post");
await queryRunner.release();
expect(table!.findColumnByName("varchar")!.length).to.be.equal("100");
expect(table!.findColumnByName("nvarchar")!.length).to.be.equal("100");
expect(table!.findColumnByName("alphanum")!.length).to.be.equal("100");
expect(table!.findColumnByName("shorttext")!.length).to.be.equal("100");
expect(table!.findColumnByName("varbinary")!.length).to.be.equal("100");
})));
});

View File

@ -0,0 +1,36 @@
import {Entity} from "../../../../../../src";
import {PrimaryColumn} from "../../../../../../src";
import {Column} from "../../../../../../src";
@Entity()
export class Post {
@PrimaryColumn()
id: number;
@Column("varchar", {
length: 50
})
varchar: string;
@Column("nvarchar", {
length: 50
})
nvarchar: string;
@Column("alphanum", {
length: 50
})
alphanum: string;
@Column("shorttext", {
length: 50
})
shorttext: string;
@Column("varbinary", {
length: 50
})
varbinary: Buffer;
}

View File

@ -0,0 +1,209 @@
import "reflect-metadata";
import {Post} from "./entity/Post";
import {Connection} from "../../../../../src";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
import {PostWithOptions} from "./entity/PostWithOptions";
import {PostWithoutTypes} from "./entity/PostWithoutTypes";
import {DateUtils} from "../../../../../src/util/DateUtils";
describe("database schema > column types > sap", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["sap"],
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("all types should work correctly - persist and hydrate", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(Post);
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("post");
await queryRunner.release();
const post = new Post();
post.id = 1;
post.name = "Post";
post.int = 2147483647;
post.integer = 2147483647;
post.tinyint = 250;
post.smallint = 32767;
post.bigint = "8223372036854775807";
post.decimal = "8223372036854775807";
post.dec = "8223372036854775807";
post.smalldecimal = "8223372036854775";
post.real = 10.5;
post.double = 10.53;
post.float = 10.53;
post.char = "A";
post.nchar = "A";
post.varchar = "This is varchar";
post.nvarchar = "This is nvarchar";
post.alphanum = "This is alphanum";
post.text = "This is text";
post.shorttext = "This is shorttext";
post.dateObj = new Date();
post.date = "2017-06-21";
post.timeObj = new Date();
post.time = "13:27:05";
post.timestamp = new Date();
post.timestamp.setMilliseconds(0);
post.seconddate = new Date();
post.seconddate.setMilliseconds(0);
post.blob = new Buffer("This is blob");
post.clob = "This is clob";
post.nclob = "This is nclob";
post.boolean = true;
// post.array = ["A", "B", "C"]; // TODO
post.varbinary = new Buffer("This is varbinary");
post.simpleArray = ["A", "B", "C"];
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
loadedPost.id.should.be.equal(post.id);
loadedPost.name.should.be.equal(post.name);
loadedPost.int.should.be.equal(post.int);
loadedPost.integer.should.be.equal(post.integer);
loadedPost.tinyint.should.be.equal(post.tinyint);
loadedPost.smallint.should.be.equal(post.smallint);
loadedPost.bigint.should.be.equal(post.bigint);
loadedPost.decimal.should.be.equal(post.decimal);
loadedPost.dec.should.be.equal(post.dec);
loadedPost.smalldecimal.should.be.equal(post.smalldecimal);
loadedPost.real.should.be.equal(post.real);
loadedPost.double.should.be.equal(post.double);
loadedPost.float.should.be.equal(post.float);
loadedPost.char.should.be.equal(post.char);
loadedPost.nchar.should.be.equal(post.nchar);
loadedPost.varchar.should.be.equal(post.varchar);
loadedPost.nvarchar.should.be.equal(post.nvarchar);
loadedPost.alphanum.should.be.equal(post.alphanum);
loadedPost.text.should.be.equal(post.text);
loadedPost.shorttext.should.be.equal(post.shorttext);
loadedPost.dateObj.should.be.equal(DateUtils.mixedDateToDateString(post.dateObj));
loadedPost.date.should.be.equal(post.date);
loadedPost.timeObj.valueOf().should.be.equal(DateUtils.mixedTimeToString(post.timeObj));
loadedPost.time.should.be.equal(post.time);
loadedPost.timestamp.valueOf().should.be.equal(post.timestamp.valueOf());
loadedPost.seconddate.valueOf().should.be.equal(post.seconddate.valueOf());
loadedPost.blob.toString().should.be.equal(post.blob.toString());
loadedPost.clob.toString().should.be.equal(post.clob.toString());
loadedPost.nclob.toString().should.be.equal(post.nclob.toString());
loadedPost.boolean.should.be.equal(post.boolean);
loadedPost.varbinary.toString().should.be.equal(post.varbinary.toString());
loadedPost.simpleArray[0].should.be.equal(post.simpleArray[0]);
loadedPost.simpleArray[1].should.be.equal(post.simpleArray[1]);
loadedPost.simpleArray[2].should.be.equal(post.simpleArray[2]);
table!.findColumnByName("id")!.type.should.be.equal("integer");
table!.findColumnByName("name")!.type.should.be.equal("nvarchar");
table!.findColumnByName("int")!.type.should.be.equal("integer");
table!.findColumnByName("integer")!.type.should.be.equal("integer");
table!.findColumnByName("tinyint")!.type.should.be.equal("tinyint");
table!.findColumnByName("smallint")!.type.should.be.equal("smallint");
table!.findColumnByName("bigint")!.type.should.be.equal("bigint");
table!.findColumnByName("decimal")!.type.should.be.equal("decimal");
table!.findColumnByName("dec")!.type.should.be.equal("decimal");
table!.findColumnByName("real")!.type.should.be.equal("real");
table!.findColumnByName("double")!.type.should.be.equal("double");
table!.findColumnByName("float")!.type.should.be.equal("double");
table!.findColumnByName("char")!.type.should.be.equal("char");
table!.findColumnByName("nchar")!.type.should.be.equal("nchar");
table!.findColumnByName("varchar")!.type.should.be.equal("varchar");
table!.findColumnByName("nvarchar")!.type.should.be.equal("nvarchar");
table!.findColumnByName("alphanum")!.type.should.be.equal("alphanum");
table!.findColumnByName("text")!.type.should.be.equal("text");
table!.findColumnByName("shorttext")!.type.should.be.equal("shorttext");
table!.findColumnByName("dateObj")!.type.should.be.equal("date");
table!.findColumnByName("date")!.type.should.be.equal("date");
table!.findColumnByName("timeObj")!.type.should.be.equal("time");
table!.findColumnByName("time")!.type.should.be.equal("time");
table!.findColumnByName("timestamp")!.type.should.be.equal("timestamp");
table!.findColumnByName("seconddate")!.type.should.be.equal("seconddate");
table!.findColumnByName("blob")!.type.should.be.equal("blob");
table!.findColumnByName("clob")!.type.should.be.equal("clob");
table!.findColumnByName("nclob")!.type.should.be.equal("nclob");
table!.findColumnByName("boolean")!.type.should.be.equal("boolean");
table!.findColumnByName("varbinary")!.type.should.be.equal("varbinary");
table!.findColumnByName("simpleArray")!.type.should.be.equal("text");
})));
it("all types should work correctly - persist and hydrate when options are specified on columns", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(PostWithOptions);
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("post_with_options");
await queryRunner.release();
const post = new PostWithOptions();
post.id = 1;
post.dec = "60.00";
post.decimal = "70.000";
post.varchar = "This is varchar";
post.nvarchar = "This is nvarchar";
post.alphanum = "This is alphanum";
post.shorttext = "This is shorttext";
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
loadedPost.id.should.be.equal(post.id);
loadedPost.dec.should.be.equal(post.dec);
loadedPost.decimal.should.be.equal(post.decimal);
loadedPost.varchar.should.be.equal(post.varchar);
loadedPost.nvarchar.should.be.equal(post.nvarchar);
loadedPost.alphanum.should.be.equal(post.alphanum);
loadedPost.shorttext.should.be.equal(post.shorttext);
table!.findColumnByName("id")!.type.should.be.equal("integer");
table!.findColumnByName("dec")!.type.should.be.equal("decimal");
table!.findColumnByName("dec")!.precision!.should.be.equal(10);
table!.findColumnByName("dec")!.scale!.should.be.equal(2);
table!.findColumnByName("decimal")!.type.should.be.equal("decimal");
table!.findColumnByName("decimal")!.precision!.should.be.equal(10);
table!.findColumnByName("decimal")!.scale!.should.be.equal(3);
table!.findColumnByName("varchar")!.type.should.be.equal("varchar");
table!.findColumnByName("varchar")!.length!.should.be.equal("50");
table!.findColumnByName("nvarchar")!.type.should.be.equal("nvarchar");
table!.findColumnByName("nvarchar")!.length!.should.be.equal("50");
table!.findColumnByName("alphanum")!.type.should.be.equal("alphanum");
table!.findColumnByName("alphanum")!.length!.should.be.equal("50");
table!.findColumnByName("shorttext")!.type.should.be.equal("shorttext");
table!.findColumnByName("shorttext")!.length!.should.be.equal("50");
})));
it("all types should work correctly - persist and hydrate when types are not specified on columns", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(PostWithoutTypes);
const queryRunner = connection.createQueryRunner();
const table = await queryRunner.getTable("post_without_types");
await queryRunner.release();
const post = new PostWithoutTypes();
post.id = 1;
post.name = "Post";
post.boolean = true;
post.blob = new Buffer("This is blob");
post.timestamp = new Date();
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
loadedPost.id.should.be.equal(post.id);
loadedPost.name.should.be.equal(post.name);
loadedPost.boolean.should.be.equal(post.boolean);
loadedPost.blob.toString().should.be.equal(post.blob.toString());
loadedPost.timestamp.valueOf().should.be.equal(post.timestamp.valueOf());
table!.findColumnByName("id")!.type.should.be.equal("integer");
table!.findColumnByName("name")!.type.should.be.equal("nvarchar");
table!.findColumnByName("boolean")!.type.should.be.equal("boolean");
table!.findColumnByName("blob")!.type.should.be.equal("blob");
table!.findColumnByName("timestamp")!.type.should.be.equal("timestamp");
})));
});

View File

@ -0,0 +1,131 @@
import {Entity} from "../../../../../../src";
import {PrimaryColumn} from "../../../../../../src";
import {Column} from "../../../../../../src";
@Entity()
export class Post {
@PrimaryColumn()
id: number;
@Column()
name: string;
// -------------------------------------------------------------------------
// Numeric Types
// -------------------------------------------------------------------------
@Column("int")
int: number;
@Column("integer")
integer: number;
@Column("tinyint")
tinyint: number;
@Column("smallint")
smallint: number;
@Column("bigint")
bigint: string;
@Column("decimal")
decimal: string;
@Column("dec")
dec: string;
@Column("smalldecimal")
smalldecimal: string;
@Column("real")
real: number;
@Column("double")
double: number;
@Column("float")
float: number;
// -------------------------------------------------------------------------
// Character Types
// -------------------------------------------------------------------------
@Column("char")
char: string;
@Column("nchar")
nchar: string;
@Column("varchar")
varchar: string;
@Column("nvarchar")
nvarchar: string;
@Column("alphanum")
alphanum: string;
@Column("text")
text: string;
@Column("shorttext")
shorttext: string;
// -------------------------------------------------------------------------
// Date Types
// -------------------------------------------------------------------------
@Column("date")
dateObj: Date;
@Column("date")
date: string;
@Column("time")
timeObj: Date;
@Column("time")
time: string;
@Column("timestamp")
timestamp: Date;
@Column("seconddate")
seconddate: Date;
// -------------------------------------------------------------------------
// LOB Type
// -------------------------------------------------------------------------
@Column("blob")
blob: Buffer;
@Column("clob")
clob: string;
@Column("nclob")
nclob: string;
// -------------------------------------------------------------------------
// Other Type
// -------------------------------------------------------------------------
@Column("boolean")
boolean: boolean;
// @Column("varchar", { array: true })
// array: string[];
@Column("varbinary")
varbinary: Buffer;
// -------------------------------------------------------------------------
// TypeOrm Specific Type
// -------------------------------------------------------------------------
@Column("simple-array")
simpleArray: string[];
}

View File

@ -0,0 +1,37 @@
import {Entity} from "../../../../../../src";
import {PrimaryColumn} from "../../../../../../src";
import {Column} from "../../../../../../src";
@Entity()
export class PostWithOptions {
@PrimaryColumn()
id: number;
// -------------------------------------------------------------------------
// Numeric Types
// -------------------------------------------------------------------------
@Column("dec", { precision: 10, scale: 2 })
dec: string;
@Column("decimal", { precision: 10, scale: 3 })
decimal: string;
// -------------------------------------------------------------------------
// Character Types
// -------------------------------------------------------------------------
@Column("varchar", { length: 50 })
varchar: string;
@Column("nvarchar", { length: 50 })
nvarchar: string;
@Column("alphanum", { length: 50 })
alphanum: string;
@Column("shorttext", { length: 50 })
shorttext: string;
}

View File

@ -0,0 +1,23 @@
import {Entity} from "../../../../../../src";
import {PrimaryColumn} from "../../../../../../src";
import {Column} from "../../../../../../src";
@Entity()
export class PostWithoutTypes {
@PrimaryColumn()
id: number;
@Column()
name: string;
@Column()
boolean: boolean;
@Column()
blob: Buffer;
@Column()
timestamp: Date;
}

View File

@ -1,8 +1,8 @@
import "reflect-metadata";
import {expect} from "chai";
import {Post} from "./entity/Post";
import {Connection} from "../../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
describe("database schema > column width", () => {
@ -31,7 +31,7 @@ describe("database schema > column width", () => {
})));
it("should update data type display width", () => Promise.all(connections.map(async connection => {
let metadata = connection.getMetadata(Post);
metadata.findColumnWithPropertyName("int")!.width = 5;
metadata.findColumnWithPropertyName("tinyint")!.width = 3;
@ -50,7 +50,7 @@ describe("database schema > column width", () => {
expect(table!.findColumnByName("smallint")!.width).to.be.equal(4);
expect(table!.findColumnByName("mediumint")!.width).to.be.equal(10);
expect(table!.findColumnByName("bigint")!.width).to.be.equal(11);
})));
});

View File

@ -1,6 +1,6 @@
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../../src/decorator/columns/Column";
@Entity()
export class Post {
@ -23,4 +23,4 @@ export class Post {
@Column("bigint", { width: 10 })
bigint: number;
}
}

View File

@ -1,10 +1,9 @@
import "reflect-metadata";
import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {expect} from "chai";
import {EntityMetadata} from "../../../../src/metadata/EntityMetadata";
import "reflect-metadata";
import {Connection, EntityMetadata} from "../../../../src";
import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver";
import {IndexMetadata} from "../../../../src/metadata/IndexMetadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Person} from "./entity/Person";
@ -59,7 +58,7 @@ describe("database schema > indices > reading index from entity and updating dat
})));
it("should update the index swaping the 2 columns", () => Promise.all(connections.map(async connection => {
it("should update the index swapping the 2 columns", () => Promise.all(connections.map(async connection => {
const entityMetadata = connection.entityMetadatas.find(x => x.name === "Person");
entityMetadata!.indices = [new IndexMetadata({

View File

@ -7,7 +7,7 @@ import {Post} from "./entity/Post";
import {Image} from "./entity/Image";
describe("query builder > relation-count-decorator-many-to-many > many-to-many", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],

View File

@ -7,7 +7,7 @@ import {Post} from "./entity/Post";
import {Image} from "./entity/Image";
describe("decorators > relation-count-decorator > one-to-many", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],

View File

@ -1,4 +1,5 @@
import "reflect-metadata";
import {SapDriver} from "../../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {expect} from "chai";
@ -21,7 +22,7 @@ describe("entity-schema > uniques", () => {
const table = await queryRunner.getTable("person");
await queryRunner.release();
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
expect(table!.indices.length).to.be.equal(1);
expect(table!.indices[0].name).to.be.equal("UNIQUE_TEST");
expect(table!.indices[0].isUnique).to.be.true;

View File

@ -22,6 +22,7 @@ describe("persistence > cascades > example 1", () => {
profile.photo = photo;
const user = new User();
user.name = "Umed";
user.profile = profile;
await connection.manager.save(user);
@ -35,13 +36,16 @@ describe("persistence > cascades > example 1", () => {
loadedUser!.should.be.eql({
id: 1,
name: "Umed",
profile: {
id: 1,
photo: {
id: 1
id: 1,
name: "My photo"
},
user: {
id: 1
id: 1,
name: "Umed"
}
}
});

View File

@ -1,3 +1,4 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@ -7,4 +8,7 @@ export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column({ default: "My photo" })
name: string;
}

View File

@ -1,3 +1,4 @@
import {Column} from "../../../../../../src/decorator/columns/Column";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Profile} from "./Profile";
@ -9,6 +10,9 @@ export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToOne(type => Profile, profile => profile.user, { cascade: ["insert"] })
profile: Profile;

View File

@ -44,26 +44,31 @@ describe("persistence > cascades > example 2", () => {
loadedQuestion!.should.be.eql({
id: 1,
name: "My question",
answers: [{
id: 1,
photo: {
id: 1
id: 1,
name: "My photo"
},
user: {
id: 1,
question: {
id: 1
id: 1,
name: "My question"
}
}
}, {
id: 2,
photo: {
id: 1
id: 1,
name: "My photo"
},
user: {
id: 1,
question: {
id: 1
id: 1,
name: "My question"
}
}
}]

View File

@ -1,3 +1,4 @@
import {Column} from "../../../../../../src";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
@ -7,4 +8,8 @@ export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column({ default: "My photo" })
name: string;
}

View File

@ -1,3 +1,4 @@
import {Column} from "../../../../../../src";
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Answer} from "./Answer";
@ -9,6 +10,9 @@ export class Question {
@PrimaryGeneratedColumn()
id: number;
@Column({ default: "My question" })
name: string;
@OneToMany(type => Answer, answer => answer.question, { cascade: ["insert"] })
answers: Answer[];

View File

@ -10,7 +10,7 @@ import {Connection} from "../../../../src/connection/Connection";
import {User} from "./entity/User";
describe("query builder > cache", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],

View File

@ -95,7 +95,7 @@ describe("query builder > delete", () => {
it("should return correct delete result", () => Promise.all(connections.map(async connection => {
// don't run test for sqlite and sqljs as they don't return affected rows
if (connection.name === "sqlite" || connection.name === "sqljs")
if (connection.name === "sqlite" || connection.name === "sqljs" || connection.name === "sap")
return;
// save some users

View File

@ -1,5 +1,6 @@
import "reflect-metadata";
import {expect} from "chai";
import {SapDriver} from "../../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {User} from "./entity/User";
@ -9,7 +10,7 @@ import {AbstractSqliteDriver} from "../../../../src/driver/sqlite-abstract/Abstr
import {OracleDriver} from "../../../../src/driver/oracle/OracleDriver";
describe("query builder > insert", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
@ -53,8 +54,8 @@ describe("query builder > insert", () => {
})));
it("should perform bulk insertion correctly", () => Promise.all(connections.map(async connection => {
// it is skipped for Oracle because it does not support bulk insertion
if (connection.driver instanceof OracleDriver)
// it is skipped for Oracle and SAP because it does not support bulk insertion
if (connection.driver instanceof OracleDriver || connection.driver instanceof SapDriver)
return;
await connection.createQueryBuilder()
@ -94,8 +95,8 @@ describe("query builder > insert", () => {
it("should be able to insert entities with different properties set even inside embeds", () => Promise.all(connections.map(async connection => {
// this test is skipped for sqlite based drivers because it does not support DEFAULT values in insertions,
// also it is skipped for Oracle because it does not support bulk insertion
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof OracleDriver)
// also it is skipped for Oracle and SAP because it does not support bulk insertion
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof OracleDriver || connection.driver instanceof SapDriver)
return;
await connection
@ -140,4 +141,4 @@ describe("query builder > insert", () => {
})));
});
});

View File

@ -1,5 +1,6 @@
import "reflect-metadata";
import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {PostWithVersion} from "./entity/PostWithVersion";
@ -28,7 +29,7 @@ describe("query builder > locking", () => {
after(() => closeTestingConnections(connections));
it("should not attach pessimistic read lock statement on query if locking is not used", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof SapDriver)
return;
const sql = connection.createQueryBuilder(PostWithVersion, "post")
@ -41,7 +42,7 @@ describe("query builder > locking", () => {
})));
it("should throw error if pessimistic lock used without transaction", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof SapDriver)
return;
return Promise.all([
@ -58,7 +59,7 @@ describe("query builder > locking", () => {
})));
it("should not throw error if pessimistic lock used with transaction", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
return connection.manager.transaction(entityManager => {
@ -77,7 +78,7 @@ describe("query builder > locking", () => {
})));
it("should attach pessimistic read lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
const sql = connection.createQueryBuilder(PostWithVersion, "post")
@ -106,12 +107,12 @@ describe("query builder > locking", () => {
.setLock("dirty_read")
.where("post.id = :id", { id: 1 })
.getSql();
expect(sql.indexOf("WITH (NOLOCK)") !== -1).to.be.true;
})));
it("should not attach pessimistic write lock statement on query if locking is not used", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof SapDriver)
return;
const sql = connection.createQueryBuilder(PostWithVersion, "post")
@ -123,7 +124,7 @@ describe("query builder > locking", () => {
})));
it("should attach pessimistic write lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
const sql = connection.createQueryBuilder(PostWithVersion, "post")
@ -272,7 +273,7 @@ describe("query builder > locking", () => {
})));
it("should throw error if pessimistic locking not supported by given driver", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return connection.manager.transaction(entityManager => {
return Promise.all([
entityManager.createQueryBuilder(PostWithVersion, "post")

View File

@ -12,7 +12,7 @@ import {Category} from "./entity/Category";
import {Image} from "./entity/Image";
describe("query builder > relation-id > many-to-many > basic-functionality", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],

View File

@ -1,11 +1,11 @@
import "reflect-metadata";
import {expect} from "chai";
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
import {TableColumn} from "../../../src/schema-builder/table/TableColumn";
import {AbstractSqliteDriver} from "../../../src/driver/sqlite-abstract/AbstractSqliteDriver";
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";
import {AbstractSqliteDriver} from "../../../src/driver/sqlite-abstract/AbstractSqliteDriver";
import {TableColumn} from "../../../src/schema-builder/table/TableColumn";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
describe("query runner > add column", () => {

View File

@ -1,5 +1,5 @@
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {Connection} from "../../../src";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
describe("query runner > create and drop schema", () => {
@ -8,7 +8,7 @@ describe("query runner > create and drop schema", () => {
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mssql", "postgres"],
enabledDrivers: ["mssql", "postgres", "sap"],
dropSchema: true,
});
});
@ -35,4 +35,4 @@ describe("query runner > create and drop schema", () => {
await queryRunner.release();
})));
});
});

View File

@ -2,6 +2,7 @@ import "reflect-metadata";
import {expect} from "chai";
import {Connection} from "../../../src/connection/Connection";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
import {Table} from "../../../src/schema-builder/table/Table";
import {TableOptions} from "../../../src/schema-builder/options/TableOptions";
@ -58,7 +59,7 @@ describe("query runner > create table", () => {
nameColumn!.should.be.exist;
nameColumn!.isUnique.should.be.true;
table!.should.exist;
if (!(connection.driver instanceof MysqlDriver))
if (!(connection.driver instanceof MysqlDriver) && !(connection.driver instanceof SapDriver))
table!.uniques.length.should.be.equal(1);
await queryRunner.executeMemoryDownSql();
@ -80,7 +81,7 @@ describe("query runner > create table", () => {
const versionColumn = table!.findColumnByName("version");
const nameColumn = table!.findColumnByName("name");
table!.should.exist;
if (!(connection.driver instanceof MysqlDriver)) {
if (!(connection.driver instanceof MysqlDriver) && !(connection.driver instanceof SapDriver)) {
table!.uniques.length.should.be.equal(2);
table!.checks.length.should.be.equal(1);
}
@ -154,7 +155,7 @@ describe("query runner > create table", () => {
]
};
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
questionTableOptions.indices!.push({ columnNames: ["name", "text"] });
} else {
questionTableOptions.uniques = [{ columnNames: ["name", "text"] }];
@ -199,14 +200,14 @@ describe("query runner > create table", () => {
]
};
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
categoryTableOptions.indices = [{ columnNames: ["name", "alternativeName"]}];
} else {
categoryTableOptions.uniques = [{ columnNames: ["name", "alternativeName"]}];
}
// When we mark column as unique, MySql create index for that column and we don't need to create index separately.
if (!(connection.driver instanceof MysqlDriver) && !(connection.driver instanceof OracleDriver))
if (!(connection.driver instanceof MysqlDriver) && !(connection.driver instanceof OracleDriver) && !(connection.driver instanceof SapDriver))
categoryTableOptions.indices = [{ columnNames: ["questionId"] }];
await queryRunner.createTable(new Table(categoryTableOptions), true);
@ -225,8 +226,8 @@ describe("query runner > create table", () => {
questionIdColumn!.generationStrategy!.should.be.equal("increment");
questionTable!.should.exist;
if (connection.driver instanceof MysqlDriver) {
// MySql driver does not have unique and check constraints.
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
// MySql and SAP HANA does not have unique constraints.
// all unique constraints is unique indexes.
questionTable!.uniques.length.should.be.equal(0);
questionTable!.indices.length.should.be.equal(2);
@ -259,8 +260,8 @@ describe("query runner > create table", () => {
categoryTable!.should.exist;
categoryTable!.foreignKeys.length.should.be.equal(1);
if (connection.driver instanceof MysqlDriver) {
// MySql driver does not have unique constraints. All unique constraints is unique indexes.
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
// MySql and SAP HANA does not have unique constraints. All unique constraints is unique indexes.
categoryTable!.indices.length.should.be.equal(3);
} else if (connection.driver instanceof OracleDriver) {
@ -301,7 +302,7 @@ describe("query runner > create table", () => {
nameColumn!.isUnique.should.be.true;
descriptionColumn!.isUnique.should.be.true;
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
table!.uniques.length.should.be.equal(0);
table!.indices.length.should.be.equal(4);
tagColumn!.isUnique.should.be.true;
@ -341,31 +342,31 @@ describe("query runner > create table", () => {
const aBook = new Book();
aBook.ean = "asdf";
await connection.manager.save(aBook);
const desc = await connection.manager.query("SELECT rowid FROM book WHERE ean = 'asdf'");
expect(desc[0].rowid).equals(1);
await queryRunner.dropTable("book");
const bookTableIsGone = await queryRunner.getTable("book");
expect(bookTableIsGone).to.be.undefined;
// the table 'book2' must NOT contain a 'rowid' column
const metadataBook2 = connection.getMetadata(Book2);
const newTableBook2 = Table.create(metadataBook2, connection.driver);
await queryRunner.createTable(newTableBook2);
try {
await connection.manager.query("SELECT rowid FROM book2");
} catch (e) {
expect(e.message).equal("SQLITE_ERROR: no such column: rowid");
}
await queryRunner.dropTable("book2");
await queryRunner.dropTable("book2");
const book2TableIsGone = await queryRunner.getTable("book2");
expect(book2TableIsGone).to.be.undefined;
expect(book2TableIsGone).to.be.undefined;
await queryRunner.release();
}
})));
})));
});

View File

@ -10,7 +10,7 @@ describe("query runner > create unique constraint", () => {
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mssql", "postgres", "sqlite", "oracle", "cockroachdb"], // mysql does not supports unique constraints
enabledDrivers: ["mssql", "postgres", "sqlite", "oracle", "cockroachdb"], // mysql and sap does not supports unique constraints
schemaCreate: true,
dropSchema: true,
});

View File

@ -8,7 +8,7 @@ describe("query runner > drop unique constraint", () => {
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mssql", "postgres", "sqlite", "oracle", "cockroachdb"], // mysql does not supports unique constraints
enabledDrivers: ["mssql", "postgres", "sqlite", "oracle", "cockroachdb"], // mysql and sap does not supports unique constraints
schemaCreate: true,
dropSchema: true,
});

View File

@ -2,6 +2,7 @@ import "reflect-metadata";
import {expect} from "chai";
import {Connection} from "../../../src";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
import {Table} from "../../../src";
import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver";
@ -76,8 +77,8 @@ describe("query runner > rename column", () => {
expect(table!.findColumnByName("id")).to.be.undefined;
table!.findColumnByName("id2")!.should.be.exist;
// MySql does not support unique constraints
if (!(connection.driver instanceof MysqlDriver)) {
// MySql and SAP does not support unique constraints
if (!(connection.driver instanceof MysqlDriver) && !(connection.driver instanceof SapDriver)) {
const oldUniqueConstraintName = connection.namingStrategy.uniqueConstraintName(table!, ["text", "tag"]);
let tableUnique = table!.uniques.find(unique => {
return !!unique.columnNames.find(columnName => columnName === "tag");

View File

@ -1,6 +1,7 @@
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver";
import {Table} from "../../../src/schema-builder/table/Table";
@ -65,7 +66,7 @@ describe("query runner > rename table", () => {
await queryRunner.dropPrimaryKey(table!);
// MySql does not support unique constraints
if (!(connection.driver instanceof MysqlDriver)) {
if (!(connection.driver instanceof MysqlDriver) && !(connection.driver instanceof SapDriver)) {
const newUniqueConstraintName = connection.namingStrategy.uniqueConstraintName(table!, ["text", "tag"]);
let tableUnique = table!.uniques.find(unique => {
return !!unique.columnNames.find(columnName => columnName === "tag");
@ -104,7 +105,7 @@ describe("query runner > rename table", () => {
await queryRunner.createDatabase("testDB", true);
await queryRunner.createSchema("testDB.testSchema", true);
} else if (connection.driver instanceof PostgresDriver) {
} else if (connection.driver instanceof PostgresDriver || connection.driver instanceof SapDriver) {
questionTableName = "testSchema.question";
renamedQuestionTableName = "testSchema.renamedQuestion";
categoryTableName = "testSchema.category";

View File

@ -1,5 +1,6 @@
import "reflect-metadata";
import {CockroachDriver} from "../../../../src/driver/cockroachdb/CockroachDriver";
import {SapDriver} from "../../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src";
import {PostWithVersion} from "./entity/PostWithVersion";
@ -28,7 +29,7 @@ describe("repository > find options > locking", () => {
after(() => closeTestingConnections(connections));
it("should throw error if pessimistic lock used without transaction", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
return Promise.all([
@ -45,7 +46,7 @@ describe("repository > find options > locking", () => {
})));
it("should not throw error if pessimistic lock used with transaction", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
return connection.manager.transaction(entityManager => {
@ -64,7 +65,7 @@ describe("repository > find options > locking", () => {
})));
it("should attach pessimistic read lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
const executedSql: string[] = [];
@ -97,7 +98,7 @@ describe("repository > find options > locking", () => {
})));
it("should attach pessimistic write lock statement on query if locking enabled", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return;
const executedSql: string[] = [];
@ -249,7 +250,7 @@ describe("repository > find options > locking", () => {
})));
it("should throw error if pessimistic locking not supported by given driver", () => Promise.all(connections.map(async connection => {
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver)
if (connection.driver instanceof AbstractSqliteDriver || connection.driver instanceof CockroachDriver || connection.driver instanceof SapDriver)
return connection.manager.transaction(entityManager => {
return Promise.all([
entityManager

View File

@ -146,7 +146,7 @@ describe("repository > increment method", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [PostBigInt],
enabledDrivers: ["mysql", "mariadb", "postgres"],
enabledDrivers: ["mysql", "mariadb", "postgres", "sap"],
// logging: true
}));
beforeEach(() => reloadTestingDatabases(connections));

View File

@ -1,9 +1,9 @@
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {Connection} from "../../../src";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
import {ColumnMetadata} from "../../../src/metadata/ColumnMetadata";
import {ColumnMetadataArgs} from "../../../src/metadata-args/ColumnMetadataArgs";
import {ColumnMetadata} from "../../../src/metadata/ColumnMetadata";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
import {Post} from "./entity/Post";
describe("schema builder > add column", () => {

View File

@ -1,17 +1,17 @@
import "reflect-metadata";
import {Connection} from "../../../src";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {expect} from "chai";
import {PromiseUtils} from "../../../src";
import {AbstractSqliteDriver} from "../../../src/driver/sqlite-abstract/AbstractSqliteDriver";
import {PostgresDriver} from "../../../src/driver/postgres/PostgresDriver";
import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver";
import {Post} from "./entity/Post";
import {PostVersion} from "./entity/PostVersion";
import "reflect-metadata";
import {Connection, PromiseUtils} from "../../../src";
import {AuroraDataApiDriver} from "../../../src/driver/aurora-data-api/AuroraDataApiDriver";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";
import {OracleDriver} from "../../../src/driver/oracle/OracleDriver";
import {AuroraDataApiDriver} from "../../../src/driver/aurora-data-api/AuroraDataApiDriver";
import {PostgresDriver} from "../../../src/driver/postgres/PostgresDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {AbstractSqliteDriver} from "../../../src/driver/sqlite-abstract/AbstractSqliteDriver";
import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Post} from "./entity/Post";
import {PostVersion} from "./entity/PostVersion";
describe("schema builder > change column", () => {
@ -62,7 +62,7 @@ describe("schema builder > change column", () => {
postTable!.findColumnByName("name")!.length.should.be.equal("500");
postTable!.findColumnByName("text")!.length.should.be.equal("300");
if (connection.driver instanceof MysqlDriver || connection.driver instanceof AuroraDataApiDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof AuroraDataApiDriver || connection.driver instanceof SapDriver) {
postTable!.indices.length.should.be.equal(2);
} else {
postTable!.uniques.length.should.be.equal(2);

View File

@ -5,7 +5,6 @@ import {PromiseUtils} from "../../../src";
import {Teacher} from "./entity/Teacher";
import {Post} from "./entity/Post";
import {ExclusionMetadata} from "../../../src/metadata/ExclusionMetadata";
import {PostgresDriver} from "../../../src/driver/postgres/PostgresDriver";
describe("schema builder > change exclusion constraint", () => {
@ -13,6 +12,7 @@ describe("schema builder > change exclusion constraint", () => {
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["postgres"], // Only PostgreSQL supports exclusion constraints.
schemaCreate: true,
dropSchema: true,
});
@ -21,9 +21,6 @@ describe("schema builder > change exclusion constraint", () => {
after(() => closeTestingConnections(connections));
it("should correctly add new exclusion constraint", () => PromiseUtils.runInSequence(connections, async connection => {
// Only PostgreSQL supports exclusion constraints.
if (!(connection.driver instanceof PostgresDriver))
return;
const teacherMetadata = connection.getMetadata(Teacher);
const exclusionMetadata = new ExclusionMetadata({
@ -46,9 +43,6 @@ describe("schema builder > change exclusion constraint", () => {
}));
it("should correctly change exclusion", () => PromiseUtils.runInSequence(connections, async connection => {
// Only PostgreSQL supports exclusion constraints.
if (!(connection.driver instanceof PostgresDriver))
return;
const postMetadata = connection.getMetadata(Post);
postMetadata.exclusions[0].expression = `USING gist ("tag" WITH =)`;
@ -64,9 +58,6 @@ describe("schema builder > change exclusion constraint", () => {
}));
it("should correctly drop removed exclusion", () => PromiseUtils.runInSequence(connections, async connection => {
// Only PostgreSQL supports exclusion constraints.
if (!(connection.driver instanceof PostgresDriver))
return;
const postMetadata = connection.getMetadata(Post);
postMetadata.exclusions = [];

View File

@ -1,13 +1,14 @@
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {PromiseUtils} from "../../../src";
import {Teacher} from "./entity/Teacher";
import {UniqueMetadata} from "../../../src/metadata/UniqueMetadata";
import {Connection} from "../../../src";
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";
import {Post} from "./entity/Post";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {AbstractSqliteDriver} from "../../../src/driver/sqlite-abstract/AbstractSqliteDriver";
import {IndexMetadata} from "../../../src/metadata/IndexMetadata";
import {UniqueMetadata} from "../../../src/metadata/UniqueMetadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Post} from "./entity/Post";
import {Teacher} from "./entity/Teacher";
describe("schema builder > change unique constraint", () => {
@ -28,8 +29,8 @@ describe("schema builder > change unique constraint", () => {
let uniqueIndexMetadata: IndexMetadata|undefined = undefined;
let uniqueMetadata: UniqueMetadata|undefined = undefined;
// Mysql stores unique constraints as unique indices.
if (connection.driver instanceof MysqlDriver) {
// Mysql and SAP stores unique constraints as unique indices.
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
uniqueIndexMetadata = new IndexMetadata({
entityMetadata: teacherMetadata,
columns: [nameColumn],
@ -60,7 +61,7 @@ describe("schema builder > change unique constraint", () => {
const table = await queryRunner.getTable("teacher");
await queryRunner.release();
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
table!.indices.length.should.be.equal(1);
table!.indices[0].isUnique!.should.be.true;
@ -82,8 +83,8 @@ describe("schema builder > change unique constraint", () => {
const postMetadata = connection.getMetadata(Post);
// Mysql stores unique constraints as unique indices.
if (connection.driver instanceof MysqlDriver) {
// Mysql and SAP stores unique constraints as unique indices.
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
const uniqueIndexMetadata = postMetadata.indices.find(i => i.columns.length === 2 && i.isUnique === true);
uniqueIndexMetadata!.name = "changed_unique";
@ -98,7 +99,7 @@ describe("schema builder > change unique constraint", () => {
const table = await queryRunner.getTable("post");
await queryRunner.release();
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
const tableIndex = table!.indices.find(index => index.columnNames.length === 2 && index.isUnique === true);
tableIndex!.name!.should.be.equal("changed_unique");
@ -120,8 +121,8 @@ describe("schema builder > change unique constraint", () => {
it("should correctly drop removed unique constraint", () => PromiseUtils.runInSequence(connections, async connection => {
const postMetadata = connection.getMetadata(Post);
// Mysql stores unique constraints as unique indices.
if (connection.driver instanceof MysqlDriver) {
// Mysql and SAP stores unique constraints as unique indices.
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
const index = postMetadata!.indices.find(i => i.columns.length === 2 && i.isUnique === true);
postMetadata!.indices.splice(postMetadata!.indices.indexOf(index!), 1);
@ -136,7 +137,7 @@ describe("schema builder > change unique constraint", () => {
const table = await queryRunner.getTable("post");
await queryRunner.release();
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
table!.indices.length.should.be.equal(1);
} else {

View File

@ -1,9 +1,10 @@
import "reflect-metadata";
import {expect} from "chai";
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {CockroachDriver} from "../../../src/driver/cockroachdb/CockroachDriver";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections} from "../../utils/test-utils";
describe("schema builder > create table", () => {
@ -36,7 +37,7 @@ describe("schema builder > create table", () => {
const nameColumn = postTable!.findColumnByName("name");
postTable!.should.exist;
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
postTable!.indices.length.should.be.equal(2);
} else {
postTable!.uniques.length.should.be.equal(2);

View File

@ -1,10 +1,11 @@
import "reflect-metadata";
import {Connection} from "../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {PostgresDriver} from "../../../src/driver/postgres/PostgresDriver";
import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver";
import {Connection} from "../../../src";
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";
import {PostgresDriver} from "../../../src/driver/postgres/PostgresDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {SqlServerDriver} from "../../../src/driver/sqlserver/SqlServerDriver";
import {ForeignKeyMetadata} from "../../../src/metadata/ForeignKeyMetadata";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
describe("schema builder > custom-db-and-schema-sync", () => {
@ -12,7 +13,7 @@ describe("schema builder > custom-db-and-schema-sync", () => {
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mysql", "mssql", "postgres"],
enabledDrivers: ["mysql", "mssql", "postgres", "sap"],
dropSchema: true,
});
});
@ -43,7 +44,7 @@ describe("schema builder > custom-db-and-schema-sync", () => {
await queryRunner.createSchema(photoMetadata.schemaPath, true);
await queryRunner.createSchema(albumMetadata.schemaPath, true);
} else if (connection.driver instanceof PostgresDriver) {
} else if (connection.driver instanceof PostgresDriver || connection.driver instanceof SapDriver) {
photoMetadata.schema = "photo-schema";
photoMetadata.tablePath = "photo-schema.photo";
photoMetadata.schemaPath = "photo-schema";

View File

@ -1,4 +1,5 @@
import "reflect-metadata";
import {SapDriver} from "../../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Connection} from "../../../../src/connection/Connection";
import {Post} from "./entity/Post";
@ -10,12 +11,15 @@ describe("transaction > transaction with full isolation support", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mysql", "mssql", "postgres"] // todo: for some reasons mariadb tests are not passing here
enabledDrivers: ["mysql", "mssql", "postgres", "sap"] // todo: for some reasons mariadb tests are not passing here
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should execute all operations in a single transaction with READ UNCOMMITTED isolation level", () => Promise.all(connections.map(async connection => {
// SAP does not support READ UNCOMMITTED isolation level
if (connection.driver instanceof SapDriver)
return;
let postId: number|undefined = undefined, categoryId: number|undefined = undefined;

View File

@ -0,0 +1,16 @@
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {Column} from "../../../../../src/decorator/columns/Column";
import {Generated} from "../../../../../src/decorator/Generated";
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
@Generated("uuid")
uuid: string;
}

View File

@ -0,0 +1,26 @@
import {Entity} from "../../../../../src/decorator/entity/Entity";
import {PrimaryGeneratedColumn} from "../../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {Column} from "../../../../../src/decorator/columns/Column";
import {Generated} from "../../../../../src/decorator/Generated";
@Entity()
export class Question {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column()
@Generated("uuid")
uuid: string;
@Column()
uuid2: string;
@Column("nvarchar", { nullable: true })
uuid3: string|null;
@Column("nvarchar", { nullable: true })
@Generated("uuid")
uuid4: string|null;
}

View File

@ -0,0 +1,79 @@
import {expect} from "chai";
import "reflect-metadata";
import {Connection} from "../../../../src";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../utils/test-utils";
import {Post} from "./entity/Post";
import {Question} from "./entity/Question";
describe("uuid-mysql", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["sap"],
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should persist uuid correctly when it is generated non primary column", () => Promise.all(connections.map(async connection => {
const postRepository = connection.getRepository(Post);
const questionRepository = connection.getRepository(Question);
const queryRunner = connection.createQueryRunner();
const postTable = await queryRunner.getTable("post");
const questionTable = await queryRunner.getTable("question");
await queryRunner.release();
const post = new Post();
await postRepository.save(post);
const loadedPost = await postRepository.findOne(1);
expect(loadedPost!.uuid).to.be.exist;
postTable!.findColumnByName("uuid")!.type.should.be.equal("nvarchar");
const post2 = new Post();
post2.uuid = "fd357b8f-8838-42f6-b7a2-ae027444e895";
await postRepository.save(post2);
const loadedPost2 = await postRepository.findOne(2);
expect(loadedPost2!.uuid).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
const question = new Question();
question.uuid2 = "fd357b8f-8838-42f6-b7a2-ae027444e895";
const savedQuestion = await questionRepository.save(question);
const loadedQuestion = await questionRepository.findOne(savedQuestion.id);
expect(loadedQuestion!.id).to.be.exist;
expect(loadedQuestion!.uuid).to.be.exist;
expect(loadedQuestion!.uuid2).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
expect(loadedQuestion!.uuid3).to.be.null;
expect(loadedQuestion!.uuid4).to.be.exist;
questionTable!.findColumnByName("id")!.type.should.be.equal("nvarchar");
questionTable!.findColumnByName("uuid")!.type.should.be.equal("nvarchar");
questionTable!.findColumnByName("uuid2")!.type.should.be.equal("nvarchar");
questionTable!.findColumnByName("uuid3")!.type.should.be.equal("nvarchar");
const question2 = new Question();
question2.id = "1ecad7f6-23ee-453e-bb44-16eca26d5189";
question2.uuid = "35b44650-b2cd-44ec-aa54-137fbdf1c373";
question2.uuid2 = "fd357b8f-8838-42f6-b7a2-ae027444e895";
question2.uuid3 = null;
question2.uuid4 = null;
await questionRepository.save(question2);
const loadedQuestion2 = await questionRepository.findOne("1ecad7f6-23ee-453e-bb44-16eca26d5189");
expect(loadedQuestion2!.id).to.equal("1ecad7f6-23ee-453e-bb44-16eca26d5189");
expect(loadedQuestion2!.uuid).to.equal("35b44650-b2cd-44ec-aa54-137fbdf1c373");
expect(loadedQuestion2!.uuid2).to.equal("fd357b8f-8838-42f6-b7a2-ae027444e895");
expect(loadedQuestion2!.uuid3).to.be.null;
expect(loadedQuestion2!.uuid4).to.be.null;
})));
it("should set generated uuid in the model after save", () => Promise.all(connections.map(async connection => {
const question = new Question();
question.uuid2 = "fd357b8f-8838-42f6-b7a2-ae027444e895";
await connection.manager.save(question);
expect(question!.id).to.exist;
expect(question!.uuid).to.exist;
expect(question!.uuid2).to.exist;
})));
});

View File

@ -1,4 +1,6 @@
import "reflect-metadata";
import {AuroraDataApiDriver} from "../../../src/driver/aurora-data-api/AuroraDataApiDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {Animal} from "./entity/Animal";
@ -26,7 +28,7 @@ describe("github issues > #1099 BUG - QueryBuilder MySQL skip sql is wrong", ()
.orderBy("a.id")
.skip(1);
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof AuroraDataApiDriver || connection.driver instanceof SapDriver ) {
await qb.getManyAndCount().should.be.rejectedWith(OffsetWithoutLimitNotSupportedError);
} else {
await qb.getManyAndCount().should.eventually.be.eql([[{ id: 2, name: "dog", categories: [] }, { id: 3, name: "bear", categories: [] }, { id: 4, name: "snake", categories: [] }, ], 4]);

View File

@ -31,7 +31,7 @@ describe("github issues > #2103 query builder regression", () => {
const entities = await repository.createQueryBuilder("s")
.whereInIds(ids)
.andWhere("x = 1")
.andWhere("s.x = 1")
.getMany();
entities.map(entity => entity.id).should.be.eql(
@ -60,7 +60,7 @@ describe("github issues > #2103 query builder regression", () => {
.whereInIds(ids.map(id => {
return { id, code: 1 };
}))
.andWhere("x = 1")
.andWhere("s.x = 1")
.getMany();
entities.map(entity => entity.id).should.be.eql(

View File

@ -1,4 +1,4 @@
import { OneToMany, PrimaryGeneratedColumn } from "../../../../src";
import {Column, OneToMany, PrimaryGeneratedColumn} from "../../../../src";
import { Entity } from "../../../../src/decorator/entity/Entity";
import { Bar } from "./Bar";
@ -6,6 +6,8 @@ import { Bar } from "./Bar";
export class Foo {
@PrimaryGeneratedColumn() id: number;
@Column({ default: "foo description" }) description: string;
@OneToMany(() => Bar, bar => bar.foo, { cascade: true, eager: true })
bars?: Bar[];
}

View File

@ -9,5 +9,8 @@ export class Dummy {
primary: true,
})
id: number;
@Column({ default: "name" })
name: string;
}

View File

@ -1,5 +1,5 @@
import {Entity} from "../../../../src/decorator/entity/Entity";
import { PrimaryColumn } from "../../../../src";
import {Column, PrimaryColumn} from "../../../../src";
@Entity()
export class Dummy2 {
@ -9,5 +9,8 @@ export class Dummy2 {
primary: true,
})
id: number;
@Column({ default: "name" })
name: string;
}

View File

@ -1,4 +1,5 @@
import {JoinTable, Entity, ManyToMany} from "../../../../src";
import {Column} from "../../../../src/decorator/columns/Column";
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {PostWithVeryLongName} from "./PostWithVeryLongName";
@ -7,6 +8,9 @@ export class CategoryWithVeryLongName {
@PrimaryGeneratedColumn()
categoryId: number;
@Column({ default: "dummy name" })
name: string;
@ManyToMany(() => PostWithVeryLongName, post => post.categories)
@JoinTable()
postsWithVeryLongName: PostWithVeryLongName[];

View File

@ -1,6 +1,6 @@
import {PrimaryGeneratedColumn} from "../../../../src/decorator/columns/PrimaryGeneratedColumn";
import {AuthorWithVeryLongName} from "./AuthorWithVeryLongName";
import {ManyToMany, Entity, ManyToOne} from "../../../../src";
import {ManyToMany, Entity, ManyToOne, Column} from "../../../../src";
import {CategoryWithVeryLongName} from "./CategoryWithVeryLongName";
@Entity()
@ -8,6 +8,9 @@ export class PostWithVeryLongName {
@PrimaryGeneratedColumn()
postId: number;
@Column({ default: "dummy name" })
name: string;
@ManyToOne(() => AuthorWithVeryLongName, author => author.postsWithVeryLongName)
authorWithVeryLongName: AuthorWithVeryLongName;

View File

@ -1,4 +1,5 @@
import "reflect-metadata";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src/connection/Connection";
import {Post} from "./entity/Post";
@ -16,6 +17,9 @@ describe("github issues > #3363 Isolation Level in transaction() from Connection
after(() => closeTestingConnections(connections));
it("should execute operations in READ UNCOMMITED isolation level", () => Promise.all(connections.map(async function(connection) {
// SAP does not support READ UNCOMMITTED isolation level
if (connection.driver instanceof SapDriver)
return;
let postId: number|undefined = undefined, categoryId: number|undefined = undefined;

View File

@ -1,4 +1,5 @@
import {MysqlDriver} from "../../../src/driver/mysql/MysqlDriver";
import {SapDriver} from "../../../src/driver/sap/SapDriver";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../utils/test-utils";
import {Connection} from "../../../src";
import {EntitySchema} from "../../../src";
@ -19,7 +20,7 @@ describe("github issues > #3803 column option unique sqlite error", () => {
await queryRunner.release();
// MySQL stores unique constraints as unique indices
if (connection.driver instanceof MysqlDriver) {
if (connection.driver instanceof MysqlDriver || connection.driver instanceof SapDriver) {
expect(table!.indices.length).to.be.equal(1);
expect(table!.indices[0].isUnique).to.be.true;
expect(table!.indices[0].columnNames[0]).to.be.equal("name");

View File

@ -1,4 +1,5 @@
import {Entity, PrimaryGeneratedColumn, ManyToMany, JoinTable} from "../../../../src";
import {Column} from "../../../../src/decorator/columns/Column";
import {Category} from "./Category";
@Entity()
@ -7,8 +8,11 @@ export class Question {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany("Category")
@JoinTable()
categories: Category[];
}
}

View File

@ -25,7 +25,7 @@ describe("github issues > #4190 Relation decorators: allow to pass string instea
profile.gender = "male";
profile.photo = "me.jpg";
await connection.manager.save(profile);
const user = new User();
user.name = "Joe Smith";
user.profile = profile;
@ -44,17 +44,17 @@ describe("github issues > #4190 Relation decorators: allow to pass string instea
}]);
})));
it("should work with many-to-one/one-to-many relations", () => Promise.all(connections.map(async connection => {
const photo1 = new Photo();
photo1.url = "me.jpg";
await connection.manager.save(photo1);
const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
await connection.manager.save(photo2);
const user = new User();
user.name = "John";
user.photos = [photo1, photo2];
@ -102,12 +102,13 @@ describe("github issues > #4190 Relation decorators: allow to pass string instea
const category1 = new Category();
category1.name = "animals";
await connection.manager.save(category1);
const category2 = new Category();
category2.name = "zoo";
await connection.manager.save(category2);
const question = new Question();
question.name = "About animals";
question.categories = [category1, category2];
await connection.manager.save(question);
@ -126,4 +127,4 @@ describe("github issues > #4190 Relation decorators: allow to pass string instea
})));
});
});

View File

@ -1,8 +1,9 @@
import {Generated} from "../../../../src";
import {Column} from "../../../../src/decorator/columns/Column";
import {PrimaryColumn} from "../../../../src/decorator/columns/PrimaryColumn";
import {Entity} from "../../../../src/decorator/entity/Entity";
import {OneToOne} from "../../../../src/decorator/relations/OneToOne";
import {User} from "./User";
import {Generated} from "../../../../src/decorator/Generated";
@Entity()
export class AccessToken {
@ -11,9 +12,12 @@ export class AccessToken {
@Generated()
primaryKey: number;
@Column()
expireTime: number;
@OneToOne(type => User, user => user.access_token, {
cascade: true
})
user: User;
}
}

View File

@ -20,4 +20,4 @@ export class User {
@JoinColumn()
access_token: AccessToken;
}
}

View File

@ -20,6 +20,7 @@ describe("github issues > #57 cascade insert not working with OneToOne relations
// create
const token = new AccessToken();
token.expireTime = 60000;
const user = new User();
user.email = "mwelnick@test.com";
user.access_token = token; // this is not necessary at all
@ -37,6 +38,7 @@ describe("github issues > #57 cascade insert not working with OneToOne relations
expect(tokens).not.to.be.undefined;
tokens.should.be.eql([{
primaryKey: 1,
expireTime: 60000,
user: {
primaryKey: 1,
email: "mwelnick@test.com",
@ -54,7 +56,8 @@ describe("github issues > #57 cascade insert not working with OneToOne relations
primaryKey: 1,
email: "mwelnick@test.com",
access_token: {
primaryKey: 1
primaryKey: 1,
expireTime: 60000,
}
}]);