Compare commits

...

24 Commits

Author SHA1 Message Date
Piotr Kuczynski
974803ce41
Merge branch 'master' into next
# Conflicts:
#	eslint.config.mjs
2025-12-08 21:27:58 +01:00
Piotr Kuczynski
14e2ae3eb9
feat(mysql)!: drop support for mysql package and default to mysql2 (#11766) 2025-12-08 21:16:50 +01:00
Piotr Kuczynski
ffd735dfdd
ci: detect if package-lock.json is up to date and generated with correct npm version (#11827) 2025-12-08 20:49:50 +01:00
Lucian Mocanu
2133c97437
chore: disable eslint errors for chai assertions (#11833) 2025-12-08 15:10:10 +01:00
Piotr Kuczynski
ef9e4b6f8e
Merge branch 'master' into next 2025-12-06 23:32:55 +01:00
Wonbin Choi
cc07c90f1d
fix: add async to the method using setFindOptions() (#10787)
Co-authored-by: Giorgio Boa <35845425+gioboa@users.noreply.github.com>
Co-authored-by: Naor Peled <me@naor.dev>
2025-12-06 21:50:43 +02:00
Piotr Kuczynski
544f640db0
chore: format next branch after merging master (#11826) 2025-12-06 16:44:05 +02:00
mjr128
a46eb0a7e1
fix: release query runner when there is no migration to revert (#11232)
Co-authored-by: Adrien PEREZ <adrien-perez@samse.fr>
2025-12-06 15:36:34 +01:00
Piotr Kuczynski
200d3df91d
Merge branch 'master' into next
# Conflicts:
#	DEVELOPER.md
#	package-lock.json
#	package.json
#	test/github-issues/3387/issue-3387.ts
#	test/github-issues/3837/issue-3387.test.ts
#	test/github-issues/3837/issue-3837.ts
2025-12-05 23:15:38 +01:00
LeviHeber
2d8c5158db
fix: prevent eager-loaded entities from overwriting manual relations (#11267)
Co-authored-by: Lucian Mocanu <alumni@users.noreply.github.com>
Co-authored-by: Giorgio Boa <35845425+gioboa@users.noreply.github.com>
2025-12-05 14:19:02 +01:00
Prakhar Chhalotre
6e34756b9d
fix: fix up aggregate methods ambiguous column (#11822) 2025-12-04 22:49:31 +01:00
Mike Guida
73fda419e4
chore: release v0.3.28 (#11816) 2025-12-03 09:29:32 +01:00
ibrahim menem
6f486e5a67
fix(redis): version detection logic (#11815)
Co-authored-by: AdolfodelSel <adolfo.selllano@gmail.com>
Co-authored-by: Giorgio Boa <35845425+gioboa@users.noreply.github.com>
Co-authored-by: Mike Guida <mike@mguida.com>
2025-12-02 11:23:26 -07:00
CHOIJEWON
38715bbd41
fix(mongodb): add missing findBy method to MongoEntityManager (#11814) 2025-12-02 16:35:42 +01:00
Mohamed Akram
ec3ea10b44
refactor: use pragma method in better-sqlite3 (#10684) 2025-12-01 22:43:06 +01:00
Lucian Mocanu
c4f5d12f3f
refactor(tests): ensure test files have the .test.ts extension (#11801) 2025-11-30 21:37:49 +01:00
Giorgio Boa
61f9e0d085
docs(mysql): add missing mysql credential options (#11813) 2025-11-30 20:35:23 +01:00
CHOIJEWON
55cd8e2b08
feat:add utc flag to date column (#11740) 2025-11-30 14:18:50 +01:00
Giorgio Boa
67f793feaa
feat(mysql): add pool size options for each connection (#11810)
Co-authored-by: 아이작_조서환 <wtae1216@sooplive.com>
2025-11-30 12:31:52 +01:00
Lucian Mocanu
835647ac92
test: use built-in wait function and fix wait times to avoid flaky tests (#11812) 2025-11-29 10:25:39 +01:00
Lucian Mocanu
546192767d
chore: update dependencies (#11811) 2025-11-29 05:54:38 +01:00
Mohammed Gomaa
d0b54544e9
fix: typesense doc sync (#11807)
Co-authored-by: Giorgio Boa <35845425+gioboa@users.noreply.github.com>
2025-11-28 15:03:18 +01:00
Lucian Mocanu
cfb3d6c015
feat(mysql): add support for vector columns on MariaDB and MySQL (#11670) 2025-11-27 15:28:49 +01:00
Piotr Kuczynski
dd55218648
fix(cli): init command reading package.json from two folders up (#11789) 2025-11-25 14:13:25 +01:00
982 changed files with 5074 additions and 3318 deletions

View File

@ -1,7 +1,7 @@
{
"all": true,
"cache": false,
"exclude": ["node_modules", "**/*.d.ts"],
"exclude": ["**/*.d.ts"],
"exclude-after-remap": true,
"extension": [".ts"],
"include": ["build/compiled/src/**", "src/**"],

View File

@ -33,8 +33,8 @@
- [ ] Code is up-to-date with the `master` branch
- [ ] This pull request links relevant issues as `Fixes #00000`
- [ ] There are new or updated unit tests validating the change
- [ ] Documentation has been updated to reflect this change
- [ ] There are new or updated tests validating the change (`tests/**.test.ts`)
- [ ] Documentation has been updated to reflect this change (`docs/docs/**.md`)
<!--
🎉 Thank you for contributing and making TypeORM even better!

View File

@ -12,7 +12,35 @@ jobs:
steps:
- uses: actions/checkout@v5
- name: Delete unaliased collections
env:
TYPESENSE_API_KEY: ${{ secrets.TYPESENSE_API_KEY }}
TYPESENSE_HOST: ${{ secrets.TYPESENSE_HOST }}
TYPESENSE_PROTOCOL: https
TYPESENSE_PORT: 443
run: |
ALIAS_COLLECTION=$(curl -s -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_PROTOCOL://$TYPESENSE_HOST:$TYPESENSE_PORT/aliases/typeorm-docs" \
| jq -r '.collection_name')
if [ "$ALIAS_COLLECTION" = "null" ] || [ -z "$ALIAS_COLLECTION" ]; then
echo "Alias does not exist; skipping collection cleanup."
exit 0
fi
echo "Alias currently points to: $ALIAS_COLLECTION"
COLLECTIONS=$(curl -s -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_PROTOCOL://$TYPESENSE_HOST:$TYPESENSE_PORT/collections" \
| jq -r '.[].name')
for col in $COLLECTIONS; do
if [ "$col" != "$ALIAS_COLLECTION" ]; then
echo "Deleting unaliased collection: $col"
curl -s -X DELETE -H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
"$TYPESENSE_PROTOCOL://$TYPESENSE_HOST:$TYPESENSE_PORT/collections/$col"
fi
done
- run: |
docker run \
-e TYPESENSE_API_KEY=${{ secrets.TYPESENSE_API_KEY }} \

View File

@ -3,7 +3,6 @@
"skip": false,
"name": "mysql",
"type": "mysql",
"connectorPackage": "mysql2",
"host": "localhost",
"port": 3306,
"username": "root",
@ -16,7 +15,6 @@
"skip": false,
"name": "mariadb",
"type": "mariadb",
"connectorPackage": "mysql2",
"host": "localhost",
"port": 3307,
"username": "root",

View File

@ -34,6 +34,7 @@ jobs:
src-or-tests: &src-or-tests
- *src
- test/**/*.ts
- .github/workflows/test/**/*
- .github/workflows/test*.yml
- .mocharc.json
@ -58,6 +59,21 @@ jobs:
- run: npm run lint
- run: npm run format:ci
lock-file:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
- run: npm install
- run: git status
- run: |
if [ -n "$(git status --porcelain)" ]; then
echo "package-lock.json is not up to date or was generated with a different npm version than the one shipped with Node.js $(cat .nvmrc)"
exit 1
fi
docs:
if: contains(needs.detect-changes.outputs.changes, 'docs')
needs: detect-changes
@ -125,6 +141,7 @@ jobs:
- coverage
- docs
- formatting
- lock-file
- tests-linux
- tests-windows
steps:

View File

@ -1,10 +1,10 @@
{
"__comment": "TODO: remove --exit flag: https://mochajs.org/#-exit",
"exit": true,
"$schema": "https://json.schemastore.org/mocharc",
"check-leaks": true,
"color": true,
"exit": true,
"file": ["./build/compiled/test/utils/test-setup.js"],
"recursive": true,
"spec": ["./build/compiled/test"],
"spec": ["./build/compiled/test/**/*.test.{js,ts}"],
"timeout": 90000
}

View File

@ -1,3 +1,31 @@
## [0.3.28](https://github.com/typeorm/typeorm/compare/0.3.27...0.3.28) (2025-12-02)
### Bug Fixes
* add multiSubnetFailover option for mssql ([#10804](https://github.com/typeorm/typeorm/issues/10804)) ([83e3a8a](https://github.com/typeorm/typeorm/commit/83e3a8a3db581a50495fa2d97c8fcd5d603cfd3c))
* circular import in SapDriver.ts ([#11750](https://github.com/typeorm/typeorm/issues/11750)) ([bed7913](https://github.com/typeorm/typeorm/commit/bed79136230d4ab26cce8cf79071134c75527857))
* **cli:** init command reading package.json from two folders up ([#11789](https://github.com/typeorm/typeorm/issues/11789)) ([dd55218](https://github.com/typeorm/typeorm/commit/dd55218648eb449937e22e1e7c88182db0048f1d))
* **deps:** upgrade glob to fix CVE-2025-64756 ([#11784](https://github.com/typeorm/typeorm/issues/11784)) ([dc74f53](https://github.com/typeorm/typeorm/commit/dc74f5374ef5ec83d53045e4bca99cb9ff7d49d4))
* **mongodb:** add missing `findBy` method to MongoEntityManager ([#11814](https://github.com/typeorm/typeorm/issues/11814)) ([38715bb](https://github.com/typeorm/typeorm/commit/38715bbd4169cae2910aac035cd2b05bddbaec5c))
* **redis:** version detection logic ([#11815](https://github.com/typeorm/typeorm/issues/11815)) ([6f486e5](https://github.com/typeorm/typeorm/commit/6f486e5a67c007287949be119f233fb2b4fb7a59))
* typesense doc sync ([#11807](https://github.com/typeorm/typeorm/issues/11807)) ([d0b5454](https://github.com/typeorm/typeorm/commit/d0b54544e9e43a5330c0485d41551128224fe4d3))
### Features
* add support for `jsonpath` column type in PostgreSQL ([#11684](https://github.com/typeorm/typeorm/issues/11684)) ([4f05718](https://github.com/typeorm/typeorm/commit/4f05718237a6ef1a3bc623e803536db23f1f327b))
* **cli/init:** pick dependencies versions from our own package.json ([#11705](https://github.com/typeorm/typeorm/issues/11705)) ([b930909](https://github.com/typeorm/typeorm/commit/b9309098bc00de047a96cba642ea1ed9e730b1fa))
* entity schema support trees ([#11606](https://github.com/typeorm/typeorm/issues/11606)) ([925dee0](https://github.com/typeorm/typeorm/commit/925dee002b92f1210456dce16c18c6b436e912f3))
* export QueryPartialEntity and QueryDeepPartialEntity types ([#11748](https://github.com/typeorm/typeorm/issues/11748)) ([ade198c](https://github.com/typeorm/typeorm/commit/ade198c77cda65e86f057f97261073f5ab2b1ed6))
* init version in postgres driver only if not set ([#11373](https://github.com/typeorm/typeorm/issues/11373)) ([cb1284c](https://github.com/typeorm/typeorm/commit/cb1284c8c0950dcb792e95b889efe1dfafc05aea))
* manage MongoDB SOCKS5 proxy settings ([#11731](https://github.com/typeorm/typeorm/issues/11731)) ([d7867eb](https://github.com/typeorm/typeorm/commit/d7867ebff173e6cae45e6ce82c9f8890811c4eba))
* **mssql:** support 'vector' type for MS SQL Server ([#11732](https://github.com/typeorm/typeorm/issues/11732)) ([2681051](https://github.com/typeorm/typeorm/commit/2681051f78c5c284b340e7978f8f337e86c7e915))
* **mysql:** add pool size options for each connection ([#11810](https://github.com/typeorm/typeorm/issues/11810)) ([67f793f](https://github.com/typeorm/typeorm/commit/67f793feaa976da717175daf152f738793b94ed2))
* **mysql:** add support for vector columns on MariaDB and MySQL ([#11670](https://github.com/typeorm/typeorm/issues/11670)) ([cfb3d6c](https://github.com/typeorm/typeorm/commit/cfb3d6c015ad648a7ffc08a7a11ce580d108ac69))
## [0.3.27](https://github.com/typeorm/typeorm/compare/0.3.26...0.3.27) (2025-09-19)

View File

@ -2,11 +2,11 @@
This document describes how to set up your development environment and run TypeORM test cases.
- [Prerequisite Software](#prerequisite-software)
- [Getting the Sources](#getting-the-sources)
- [Installing NPM Modules](#installing-npm-modules)
- [Building](#building)
- [Running Tests Locally](#running-tests-locally)
* [Prerequisite Software](#prerequisite-software)
* [Getting the Sources](#getting-the-sources)
* [Installing NPM Modules](#installing-npm-modules)
* [Building](#building)
* [Running Tests Locally](#running-tests-locally)
See the [contribution guidelines](https://github.com/typeorm/typeorm/blob/master/CONTRIBUTING.md)
if you'd like to contribute to TypeORM.
@ -16,14 +16,14 @@ if you'd like to contribute to TypeORM.
Before you can build and test TypeORM, you must install and configure the
following products on your development machine:
- [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or [Windows](http://windows.github.com));
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or [Windows](http://windows.github.com));
[GitHub's Guide to Installing Git](https://docs.github.com/get-started/git-basics/set-up-git) is a good source of information.
- [Node.js](https://nodejs.org) can be installed from the official website, the operating system's package manager, or using a Node.js version manager like [fnm](https://fnm.vercel.app) or [nvm](https://github.com/nvm-sh/nvm).
- [Mysql](https://www.mysql.com/) is required to run tests on this platform (or docker)
- [MariaDB](https://mariadb.com/) is required to run tests on this platform (or docker)
- [Postgres](https://www.postgresql.org/) is required to run tests on this platform (or docker)
- [Oracle](https://www.oracle.com/database/index.html) is required to run tests on this platform
- [Microsoft SQL Server](https://www.microsoft.com/en-us/cloud-platform/sql-server) is required to run tests on this platform
* [Node.js](https://nodejs.org) can be installed from the official website, the operating system's package manager, or using a Node.js version manager like [fnm](https://fnm.vercel.app).
* [MySQL](https://www.mysql.com/) is required to run tests on this platform (or docker)
* [MariaDB](https://mariadb.com/) is required to run tests on this platform (or docker)
* [Postgres](https://www.postgresql.org/) is required to run tests on this platform (or docker)
* [Oracle](https://www.oracle.com/database/index.html) is required to run tests on this platform
* [Microsoft SQL Server](https://www.microsoft.com/en-us/cloud-platform/sql-server) is required to run tests on this platform
For convenience, you can also use the [Docker](https://www.docker.com/) images
provided in [docker-compose.yml](https://github.com/typeorm/typeorm/blob/master/docker-compose.yml)
@ -59,9 +59,9 @@ You should have node installed in the version described in [.nvmrc](.nvmrc).
It is recommended to configure your OS to automatically switch to use this version whenever you enter project folder. This can be achieved in many ways:
* [`fnm`](https://github.com/Schniz/fnm)
* [`zsh-nvm`](https://github.com/lukechilds/zsh-nvm#auto-use)
* [`asdf`](https://asdf-vm.com) with `asdf-nodejs` plugin and [`legacy_version_file = true`](https://asdf-vm.com/manage/configuration.html#legacy-version-file) option
- [`fnm`](https://github.com/Schniz/fnm)
- [`zsh-nvm`](https://github.com/lukechilds/zsh-nvm#auto-use)
- [`asdf`](https://asdf-vm.com) with `asdf-nodejs` plugin and [`legacy_version_file = true`](https://asdf-vm.com/manage/configuration.html#legacy-version-file) option
## Installing package dependencies
@ -104,7 +104,7 @@ You can copy this tar into your project and run `npm install ./typeorm-x.x.x.tgz
It is greatly appreciated if PRs that change code come with appropriate tests.
To create a new test, check the [relevant functional tests](https://github.com/typeorm/typeorm/tree/master/test/functional). Depending on the test, you may need to create a new test file or modify an existing one.
To create a new test, check the [relevant functional tests](https://github.com/typeorm/typeorm/tree/master/test/functional). Depending on the test, you may need to create a new `.test.ts` file or modify an existing one.
If the test is for a specific regression or issue opened on GitHub, add a comment to the tests mentioning the issue number.
@ -116,11 +116,12 @@ import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
} from "../../../utils/test-utils"
import { DataSource } from "../../../../src/data-source/DataSource"
} from "../../utils/test-utils"
import { DataSource } from "../../../src/data-source/DataSource"
describe("description of the functionality you're testing", () => {
let dataSources: DataSource[]
before(
async () =>
(dataSources = await createTestingConnections({

View File

@ -12,7 +12,7 @@ services:
MYSQL_DATABASE: "test"
mysql-9:
image: "mysql:9.4.0"
image: "mysql:9.5.0"
container_name: "typeorm-mysql-9"
ports:
- "3306:3306"
@ -24,7 +24,7 @@ services:
# mariadb
mariadb-10:
image: "mariadb:10.6.22-jammy"
image: "mariadb:10.6.24-jammy"
container_name: "typeorm-mariadb-10"
ports:
- "3307:3306"
@ -35,7 +35,7 @@ services:
MYSQL_DATABASE: "test"
mariadb-12:
image: "mariadb:12.0.1-rc"
image: "mariadb:12.1.2"
container_name: "typeorm-mariadb-12"
ports:
- "3307:3306"

View File

@ -207,7 +207,7 @@ const queryEmbedding = [
const results = await dataSource.query(
`
DECLARE @question AS VECTOR (1998) = @0;
SELECT TOP (10) dc.*,
SELECT TOP (10) dc.*,
VECTOR_DISTANCE('cosine', @question, embedding) AS distance
FROM document_chunk dc
ORDER BY VECTOR_DISTANCE('cosine', @question, embedding)

View File

@ -4,14 +4,6 @@ MySQL, MariaDB and Amazon Aurora MySQL are supported as TypeORM drivers.
## Installation
Either `mysql` or `mysql2` are required to connect to a MySQL/MariaDB data source. Only `mysql2` can connect to MySQL 8.0 or later and is recommended because it is still maintained. See more about [mysql2](https://sidorares.github.io/node-mysql2/docs/history-and-why-mysq2).
```shell
npm install mysql
```
or:
```shell
npm install mysql2
```
@ -20,8 +12,6 @@ npm install mysql2
See [Data Source Options](../data-source/2-data-source-options.md) for the common data source options. You can use the data source types `mysql`, `mariadb` and `aurora-mysql` to connect to the respective databases.
- `connectorPackage` - The database client, either `mysql` or `mysql2`. If the specified client cannot be loaded, it will fall back to the alternative. (Current default: `mysql`)
- `url` - Connection url where the connection is performed. Please note that other data source options will override parameters set from url.
- `host` - Database host.
@ -34,6 +24,10 @@ See [Data Source Options](../data-source/2-data-source-options.md) for the commo
- `database` - Database name.
- `socketPath` - Database socket path.
- `poolSize` - Maximum number of clients the pool should contain for each connection.
- `charset` and `collation` - The charset/collation for the connection. If an SQL-level charset is specified (like utf8mb4) then the default collation for that charset is used.
- `timezone` - the timezone configured on the MySQL server. This is used to typecast server date/time
@ -82,7 +76,7 @@ See [Data Source Options](../data-source/2-data-source-options.md) for the commo
- `enableQueryTimeout` - If a value is specified for maxQueryExecutionTime, in addition to generating a warning log when a query exceeds this time limit, the specified maxQueryExecutionTime value is also used as the timeout for the query. For more information, check [mysql timeouts](https://github.com/mysqljs/mysql#timeouts).
Additional options can be added to the `extra` object and will be passed directly to the client library. See more in the [mysql connection options](https://github.com/mysqljs/mysql#connection-options) or the [mysql2 documentation](https://sidorares.github.io/node-mysql2/docs).
Additional options can be added to the `extra` object and will be passed directly to the client library. See more in the [mysql2 documentation](https://sidorares.github.io/node-mysql2/docs).
## Column Types
@ -139,3 +133,7 @@ export class User {
roles: UserRoleType[]
}
```
### Vector Types
MySQL supports the [VECTOR type](https://dev.mysql.com/doc/refman/en/vector.html) since version 9.0, while in MariaDB, [vectors](https://mariadb.com/docs/server/reference/sql-structure/vectors/vector-overview) are available since 11.7.

View File

@ -60,7 +60,7 @@ Additional options can be added to the `extra` object and will be passed directl
### Column types for `postgres`
`int`, `int2`, `int4`, `int8`, `smallint`, `integer`, `bigint`, `decimal`, `numeric`, `real`, `float`, `float4`, `float8`, `double precision`, `money`, `character varying`, `varchar`, `character`, `char`, `text`, `citext`, `hstore`, `bytea`, `bit`, `varbit`, `bit varying`, `timetz`, `timestamptz`, `timestamp`, `timestamp without time zone`, `timestamp with time zone`, `date`, `time`, `time without time zone`, `time with time zone`, `interval`, `bool`, `boolean`, `enum`, `point`, `line`, `lseg`, `box`, `path`, `polygon`, `circle`, `cidr`, `inet`, `macaddr`, `macaddr8`, `tsvector`, `tsquery`, `uuid`, `xml`, `json`, `jsonb`, `jsonpath`, `int4range`, `int8range`, `numrange`, `tsrange`, `tstzrange`, `daterange`, `int4multirange`, `int8multirange`, `nummultirange`, `tsmultirange`, `tstzmultirange`, `multidaterange`, `geometry`, `geography`, `cube`, `ltree`
`int`, `int2`, `int4`, `int8`, `smallint`, `integer`, `bigint`, `decimal`, `numeric`, `real`, `float`, `float4`, `float8`, `double precision`, `money`, `character varying`, `varchar`, `character`, `char`, `text`, `citext`, `hstore`, `bytea`, `bit`, `varbit`, `bit varying`, `timetz`, `timestamptz`, `timestamp`, `timestamp without time zone`, `timestamp with time zone`, `date`, `time`, `time without time zone`, `time with time zone`, `interval`, `bool`, `boolean`, `enum`, `point`, `line`, `lseg`, `box`, `path`, `polygon`, `circle`, `cidr`, `inet`, `macaddr`, `macaddr8`, `tsvector`, `tsquery`, `uuid`, `xml`, `json`, `jsonb`, `jsonpath`, `int4range`, `int8range`, `numrange`, `tsrange`, `tstzrange`, `daterange`, `int4multirange`, `int8multirange`, `nummultirange`, `tsmultirange`, `tstzmultirange`, `multidaterange`, `geometry`, `geography`, `cube`, `ltree`, `vector`, `halfvec`.
### Column types for `cockroachdb`
@ -68,6 +68,33 @@ Additional options can be added to the `extra` object and will be passed directl
Note: CockroachDB returns all numeric data types as `string`. However, if you omit the column type and define your property as `number` ORM will `parseInt` string into number.
### Vector columns
Vector columns can be used for similarity searches using PostgreSQL's vector operators:
```typescript
// L2 distance (Euclidean) - <->
const results = await dataSource.sql`
SELECT id, embedding
FROM post
ORDER BY embedding <-> ${"[1,2,3]"}
LIMIT 5`
// Cosine distance - <=>
const results = await dataSource.sql`
SELECT id, embedding
FROM post
ORDER BY embedding <=> ${"[1,2,3]"}
LIMIT 5`
// Inner product - <#>
const results = await dataSource.sql`
SELECT id, embedding
FROM post
ORDER BY embedding <#> ${"[1,2,3]"}
LIMIT 5`
```
### Spatial columns
TypeORM's PostgreSQL and CockroachDB support uses [GeoJSON](http://geojson.org/) as an interchange format, so geometry columns should be tagged either as `object` or `Geometry` (or subclasses, e.g. `Point`) after importing [`geojson` types](https://www.npmjs.com/package/@types/geojson) or using the TypeORM built-in GeoJSON types:

View File

@ -37,15 +37,16 @@ SAP HANA 2.0 and SAP HANA Cloud support slightly different data types. Check the
- [SAP HANA 2.0 Data Types](https://help.sap.com/docs/SAP_HANA_PLATFORM/4fe29514fd584807ac9f2a04f6754767/20a1569875191014b507cf392724b7eb.html?locale=en-US)
- [SAP HANA Cloud Data Types](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/data-types)
TypeORM's `SapDriver` supports `tinyint`, `smallint`, `integer`, `bigint`, `smalldecimal`, `decimal`, `real`, `double`, `date`, `time`, `seconddate`, `timestamp`, `boolean`, `char`, `nchar`, `varchar`, `nvarchar`, `text`, `alphanum`, `shorttext`, `array`, `varbinary`, `blob`, `clob`, `nclob`, `st_geometry`, `st_point`, `real_vector`, `half_vector`, `vector`, and `halfvec`. Some of these data types have been deprecated or removed in SAP HANA Cloud, and will be converted to the closest available alternative when connected to a Cloud database.
TypeORM's `SapDriver` supports `tinyint`, `smallint`, `integer`, `bigint`, `smalldecimal`, `decimal`, `real`, `double`, `date`, `time`, `seconddate`, `timestamp`, `boolean`, `char`, `nchar`, `varchar`, `nvarchar`, `text`, `alphanum`, `shorttext`, `array`, `varbinary`, `blob`, `clob`, `nclob`, `st_geometry`, `st_point`, `real_vector` and `half_vector`. Some of these data types have been deprecated or removed in SAP HANA Cloud, and will be converted to the closest available alternative when connected to a Cloud database.
### Vector Types
The `real_vector` and `half_vector` data types were introduced in SAP HANA Cloud (2024Q1 and 2025Q2 respectively), and require a supported version of `@sap/hana-client` as well.
The `real_vector` and `half_vector` data types were introduced in SAP HANA Cloud (2024Q1 and 2025Q2 respectively), and require a supported version of `@sap/hana-client` as well.
For consistency with PostgreSQL's vector support, TypeORM also provides aliases:
- `vector` (alias for `real_vector`) - stores vectors as 4-byte floats
- `halfvec` (alias for `half_vector`) - stores vectors as 2-byte floats for memory efficiency
- `vector` (alias for `real_vector`) - stores vectors as 4-byte floats
- `halfvec` (alias for `half_vector`) - stores vectors as 2-byte floats for memory efficiency
```typescript
@Entity()
@ -70,3 +71,5 @@ export class Document {
```
By default, the client will return a `Buffer` in the `fvecs`/`hvecs` format, which is more efficient. It is possible to let the driver convert the values to a `number[]` by adding `{ extra: { vectorOutputType: "Array" } }` to the connection options. Check the SAP HANA Client documentation for more information about [REAL_VECTOR](https://help.sap.com/docs/SAP_HANA_CLIENT/f1b440ded6144a54ada97ff95dac7adf/0d197e4389c64e6b9cf90f6f698f62fe.html) or [HALF_VECTOR](https://help.sap.com/docs/SAP_HANA_CLIENT/f1b440ded6144a54ada97ff95dac7adf/8bb854b4ce4a4299bed27c365b717e91.html).
Use the appropriate [vector functions](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/vector-functions) for similarity searches.

View File

@ -180,88 +180,6 @@ There are several special column types with additional functionality available:
each time you call `save` of entity manager or repository, or during `upsert` operations when an update occurs.
You don't need to set this column - it will be automatically set.
### Vector columns
Vector columns are supported on PostgreSQL (via [`pgvector`](https://github.com/pgvector/pgvector) extension), Microsoft SQL Server, and SAP HANA Cloud, enabling storing and querying vector embeddings for similarity search and machine learning applications.
TypeORM supports both `vector` and `halfvec` column types across databases:
- `vector` - stores vectors as 4-byte floats (single precision)
- PostgreSQL: native `vector` type via pgvector extension
- SQL Server: native `vector` type
- SAP HANA: alias for `real_vector` type
- `halfvec` - stores vectors as 2-byte floats (half precision) for memory efficiency
- PostgreSQL: native `halfvec` type via pgvector extension
- SAP HANA: alias for `half_vector` type
You can specify the vector dimensions using the `length` option:
```typescript
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number
// Vector without specified dimensions (works on PostgreSQL and SAP HANA; SQL Server requires explicit dimensions)
@Column("vector")
embedding: number[] | Buffer
// Vector with 3 dimensions: vector(3)
@Column("vector", { length: 3 })
embedding_3d: number[] | Buffer
// Half-precision vector with 4 dimensions: halfvec(4) (PostgreSQL and SAP HANA only)
@Column("halfvec", { length: 4 })
halfvec_embedding: number[] | Buffer
}
```
**PostgreSQL** - Vector columns can be used for similarity searches using vector operators:
```typescript
// L2 distance (Euclidean) - <->
const results = await dataSource.query(
`SELECT id, embedding FROM post ORDER BY embedding <-> $1 LIMIT 5`,
["[1,2,3]"],
)
// Cosine distance - <=>
const results = await dataSource.query(
`SELECT id, embedding FROM post ORDER BY embedding <=> $1 LIMIT 5`,
["[1,2,3]"],
)
// Inner product - <#>
const results = await dataSource.query(
`SELECT id, embedding FROM post ORDER BY embedding <#> $1 LIMIT 5`,
["[1,2,3]"],
)
```
**SQL Server** - Use the `VECTOR_DISTANCE` function for similarity searches:
```typescript
const queryEmbedding = [1, 2, 3]
// Cosine distance
const results = await dataSource.query(
`
DECLARE @question AS VECTOR(3) = @0;
SELECT TOP (5) id, embedding,
VECTOR_DISTANCE('cosine', @question, embedding) AS distance
FROM post
ORDER BY VECTOR_DISTANCE('cosine', @question, embedding)
`,
[JSON.stringify(queryEmbedding)],
)
```
> **Note**:
>
> - **PostgreSQL**: Vector columns require the `pgvector` extension to be installed. The extension provides the vector data types and similarity operators.
> - **SQL Server**: Vector type support requires a compatible SQL Server version with vector functionality enabled.
> - **SAP HANA**: Vector columns require SAP HANA Cloud (2024Q1+) and a supported version of `@sap/hana-client`. Use the appropriate [vector similarity functions](https://help.sap.com/docs/hana-cloud-database/sap-hana-cloud-sap-hana-database-sql-reference-guide/vector-functions) for similarity searches.
## Column types
TypeORM supports all of the most commonly used database-supported column types.
@ -414,6 +332,50 @@ Besides "uuid" there is also "increment", "identity" (Postgres 10+ only) and "ro
on some database platforms with this type of generation (for example some databases can only have one increment column,
or some of them require increment to be a primary key).
### Vector columns
Vector columns are supported on MariaDB/MySQL, Microsoft SQL Server, PostgreSQL (via [`pgvector`](https://github.com/pgvector/pgvector) extension) and SAP HANA Cloud, enabling storing and querying vector embeddings for similarity search and machine learning applications.
TypeORM supports both `vector` and `halfvec` column types across databases:
- `vector` - stores vectors as 4-byte floats (single precision)
- MariaDB/MySQL: native `vector` type
- Microsoft SQL Server: native `vector` type
- PostgreSQL: `vector` type, available via `pgvector` extension
- SAP HANA Cloud: alias for `real_vector` type
- `halfvec` - stores vectors as 2-byte floats (half precision) for memory efficiency
- PostgreSQL: `halfvec` type, available via `pgvector` extension
- SAP HANA Cloud: alias for `half_vector` type
You can specify the number of vector dimensions using the `length` option:
```typescript
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number
// Vector without specified dimensions
@Column("vector")
embedding: number[] | Buffer
// Vector with 3 dimensions: vector(3)
@Column("vector", { length: 3 })
embedding_3d: number[] | Buffer
// Half-precision vector with 4 dimensions: halfvec(4) (works on PostgreSQL and SAP HANA only)
@Column("halfvec", { length: 4 })
halfvec_embedding: number[] | Buffer
}
```
> **Note**:
>
> - **MariaDB/MySQL**: Vectors are supported since MariaDB 11.7 and MySQL 9
> - **Microsoft SQL Server**: Vector type support requires SQL Server 2025 (17.x) or newer.
> - **PostgreSQL**: Vector columns require the `pgvector` extension to be installed. The extension provides the vector data types and similarity operators.
> - **SAP HANA**: Vector columns require SAP HANA Cloud (2024Q1+) and a supported version of `@sap/hana-client`.
### Spatial columns
Microsoft SQLServer, MySQL/MariaDB, PostgreSQL/CockroachDB and SAP HANA all support spatial columns. TypeORM's support for each varies slightly between databases, particularly as the column names vary between databases.
@ -491,6 +453,7 @@ List of available options in `ColumnOptions`:
- `hstoreType: "object"|"string"` - Return type of `HSTORE` column. Returns value as string or as object. Used only in [Postgres](https://www.postgresql.org/docs/9.6/static/hstore.html).
- `array: boolean` - Used for postgres and cockroachdb column types which can be array (for example int[])
- `transformer: { from(value: DatabaseType): EntityType, to(value: EntityType): DatabaseType }` - Used to marshal properties of arbitrary type `EntityType` into a type `DatabaseType` supported by the database. Array of transformers are also supported and will be applied in natural order when writing, and in reverse order when reading. e.g. `[lowercase, encrypt]` will first lowercase the string then encrypt it when writing, and will decrypt then do nothing when reading.
- `utc: boolean` - Indicates if date values should be stored and retrieved in UTC timezone instead of local timezone. Only applies to `date` column type. Default value is `false` (uses local timezone for backward compatibility).
Note: most of those column options are RDBMS-specific and aren't available in `MongoDB`.

View File

@ -170,7 +170,7 @@ module.exports = {
plugins: [
//ignore the drivers you don't want. This is the complete list of all drivers -- remove the suppressions for drivers you want to use.
new FilterWarningsPlugin({
exclude: [/mongodb/, /mssql/, /mysql/, /mysql2/, /oracledb/, /pg/, /pg-native/, /pg-query-stream/, /react-native-sqlite-storage/, /redis/, /sqlite3/, /sql.js/, /typeorm-aurora-data-api-driver/]
exclude: [/mongodb/, /mssql/, /mysql2/, /oracledb/, /pg/, /pg-native/, /pg-query-stream/, /react-native-sqlite-storage/, /redis/, /sqlite3/, /sql.js/, /typeorm-aurora-data-api-driver/]
})
]
};

View File

@ -27,12 +27,7 @@
"strip_chars": " .,;:#",
"custom_settings": {
"separatorsToIndex": "_",
"attributesForFaceting": [
"language",
"version",
"type",
"docusaurus_tag"
],
"attributesForFaceting": [],
"attributesToRetrieve": [
"hierarchy",
"content",
@ -46,4 +41,4 @@
"833762294"
],
"nb_hits": 0
}
}

View File

@ -1,8 +1,8 @@
import { themes as prismThemes } from "prism-react-renderer"
import type { Config } from "@docusaurus/types"
import type * as Preset from "@docusaurus/preset-classic"
import type { Config } from "@docusaurus/types"
import { PluginOptions as LLMsTXTPluginOptions } from "@signalwire/docusaurus-plugin-llms-txt"
import { themes as prismThemes } from "prism-react-renderer"
import { redirects } from "./redirects"
import { LLMsTXTPluginOptions } from "@signalwire/docusaurus-plugin-llms-txt"
// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)
@ -23,7 +23,6 @@ const config: Config = {
projectName: "typeorm", // Usually your repo name.
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
// Even if you don't use internationalization, you can use this field to set
// useful metadata like html lang. For example, if your site is Chinese, you

2447
docs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -27,24 +27,24 @@
]
},
"dependencies": {
"@docusaurus/core": "3.8.1",
"@docusaurus/plugin-client-redirects": "^3.8.1",
"@docusaurus/preset-classic": "3.8.1",
"@docusaurus/core": "3.9.2",
"@docusaurus/plugin-client-redirects": "^3.9.2",
"@docusaurus/preset-classic": "3.9.2",
"@mdx-js/react": "^3.1.1",
"@signalwire/docusaurus-plugin-llms-txt": "^1.2.2",
"clsx": "^2.1.1",
"docusaurus-theme-search-typesense": "^0.25.0",
"docusaurus-theme-search-typesense": "^0.26.0",
"prism-react-renderer": "^2.4.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.8.1",
"@docusaurus/tsconfig": "3.8.1",
"@docusaurus/types": "3.8.1",
"typescript": "~5.9.2"
"@docusaurus/module-type-aliases": "3.9.2",
"@docusaurus/tsconfig": "3.9.2",
"@docusaurus/types": "3.9.2",
"typescript": "~5.9.3"
},
"engines": {
"node": ">=18.0"
"node": ">=20.0"
}
}

View File

@ -30,10 +30,7 @@ export default defineConfig([
js,
ts,
},
extends: [
js.configs.recommended,
...ts.configs.recommendedTypeChecked,
],
extends: [js.configs.recommended, ...ts.configs.recommendedTypeChecked],
rules: {
// exceptions from typescript-eslint/recommended
"@typescript-eslint/ban-ts-comment": "warn",
@ -48,7 +45,7 @@ export default defineConfig([
"warn",
{
argsIgnorePattern: "^_",
destructuredArrayIgnorePattern: "^_"
destructuredArrayIgnorePattern: "^_",
},
],
"@typescript-eslint/no-wrapper-object-types": "off",
@ -88,15 +85,14 @@ export default defineConfig([
"no-regex-spaces": "warn",
},
},
jsdoc({
files: ["src/**/*.ts"],
config: "flat/recommended-typescript", // change to 'flat/recommended-typescript-error' once warnings are fixed
// Temporarily enable individual rules when they are fixed, until all current warnings are gone,
// and then remove manual config in favor of `config: "flat/recommended-typescript-error"`
rules: {
"jsdoc/valid-types": "error"
}
"jsdoc/valid-types": "error",
},
}),
{

View File

@ -3,7 +3,6 @@
"skip": false,
"name": "mysql",
"type": "mysql",
"connectorPackage": "mysql2",
"host": "localhost",
"port": 3306,
"username": "root",
@ -16,7 +15,6 @@
"skip": false,
"name": "mariadb",
"type": "mariadb",
"connectorPackage": "mysql2",
"host": "localhost",
"port": 3307,
"username": "root",

3674
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"name": "typeorm",
"version": "0.3.27",
"description": "Data-Mapper ORM for TypeScript and ES2023+. Supports MySQL/MariaDB, PostgreSQL, MS SQL Server, Oracle, SAP HANA, SQLite, MongoDB databases.",
"version": "0.3.28",
"description": "Data-Mapper ORM for TypeScript and ES2021+. Supports MySQL/MariaDB, PostgreSQL, MS SQL Server, Oracle, SAP HANA, SQLite, MongoDB databases.",
"homepage": "https://typeorm.io",
"bugs": {
"url": "https://github.com/typeorm/typeorm/issues"
@ -98,11 +98,10 @@
"ansis": "^4.2.0",
"app-root-path": "^3.1.0",
"buffer": "^6.0.3",
"dayjs": "^1.11.18",
"dayjs": "^1.11.19",
"debug": "^4.4.3",
"dedent": "^1.7.0",
"dotenv": "^17.2.3",
"glob": "^10.5.0",
"reflect-metadata": "^0.2.2",
"sha.js": "^2.4.12",
"sql-highlight": "^6.1.0",
@ -113,13 +112,13 @@
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@google-cloud/spanner": "^8.2.1",
"@sap/hana-client": "^2.26.18",
"@google-cloud/spanner": "^8.3.1",
"@sap/hana-client": "^2.26.26",
"@tsconfig/node20": "^20.1.6",
"@types/chai": "^5.2.2",
"@types/chai-as-promised": "^8.0.2",
"@types/debug": "^4.1.12",
"@types/gulp-rename": "^2.0.6",
"@types/gulp-rename": "^2.0.7",
"@types/gulp-sourcemaps": "^0.0.38",
"@types/mocha": "^10.0.10",
"@types/node": "^20.19.18",
@ -127,7 +126,7 @@
"@types/sinon": "^17.0.4",
"@types/sinon-chai": "^4.0.0",
"@types/source-map-support": "^0.5.10",
"@types/yargs": "^17.0.33",
"@types/yargs": "^17.0.35",
"better-sqlite3": "^12.4.1",
"c8": "^10.1.3",
"chai": "^6.2.0",
@ -135,7 +134,7 @@
"class-transformer": "^0.5.1",
"eslint": "^9.39.1",
"eslint-plugin-chai-friendly": "^1.1.0",
"eslint-plugin-jsdoc": "^61.1.12",
"eslint-plugin-jsdoc": "^61.4.1",
"globals": "^16.5.0",
"gulp": "^4.0.2",
"gulp-rename": "^2.1.0",
@ -146,19 +145,17 @@
"gulpclass": "^0.2.0",
"husky": "^9.1.7",
"is-ci": "^4.1.0",
"lint-staged": "^16.2.6",
"mocha": "^11.7.3",
"mongodb": "^6.20.0",
"mssql": "^12.0.0",
"mysql": "^2.18.1",
"mysql2": "^3.15.1",
"oracledb": "^6.9.0",
"lint-staged": "^16.2.7",
"mocha": "^11.7.5",
"mongodb": "^6.21.0",
"mssql": "^12.1.1",
"mysql2": "^3.15.3",
"oracledb": "^6.10.0",
"pg": "^8.16.3",
"pg-query-stream": "^4.10.3",
"pkg-pr-new": "^0.0.60",
"prettier": "^3.6.2",
"redis": "^5.8.2",
"remap-istanbul": "^0.13.0",
"redis": "^5.10.0",
"sinon": "^21.0.0",
"sinon-chai": "^4.0.1",
"sort-package-json": "^3.4.0",
@ -167,8 +164,8 @@
"sqlite3": "^5.1.7",
"standard-changelog": "^7.0.1",
"ts-node": "^10.9.2",
"typescript": "^5.9.2",
"typescript-eslint": "^8.46.3"
"typescript": "^5.9.3",
"typescript-eslint": "^8.48.0"
},
"peerDependencies": {
"@google-cloud/spanner": "^8.0.0",
@ -177,7 +174,7 @@
"ioredis": "^5.0.4",
"mongodb": "^6.0.0",
"mssql": "^12.0.0",
"mysql2": "^3.0.1",
"mysql2": "^3.15.3",
"oracledb": "^6.3.0",
"pg": "^8.5.1",
"pg-native": "^3.0.0",
@ -246,13 +243,6 @@
"url": "https://opencollective.com/typeorm",
"logo": "https://opencollective.com/opencollective/logo.txt"
},
"devEngines": {
"packageManager": {
"name": "npm",
"onFail": "error"
}
},
"readmeFilename": "README.md",
"tags": [
"orm",
"typescript",

View File

@ -300,26 +300,22 @@ export class RedisQueryResultCache implements QueryResultCache {
}
/**
* Detects the Redis version based on the connected client's API characteristics
* without creating test keys in the database
* Detects the Redis package version by reading the installed package.json
* and sets the appropriate API version (3 for callback-based, 5 for Promise-based).
*/
private detectRedisVersion(): void {
if (this.clientType !== "redis") return
try {
// Detect version by examining the client's method signatures
// This avoids creating test keys in the database
const setMethod = this.client.set
if (setMethod && setMethod.length <= 3) {
// Redis 5+ set method accepts fewer parameters (key, value, options)
this.redisMajorVersion = 5
} else {
// Redis 3/4 set method requires more parameters (key, value, flag, duration, callback)
this.redisMajorVersion = 3
}
} catch {
// Default to Redis 3/4 for maximum compatibility
const version = PlatformTools.readPackageVersion("redis")
const major = parseInt(version.split(".")[0], 10)
if (isNaN(major)) {
throw new TypeORMError(`Invalid Redis version format: ${version}`)
}
if (major <= 4) {
// Redis 3/4 uses callback-based API
this.redisMajorVersion = 3
} else {
// Redis 5+ uses Promise-based API
this.redisMajorVersion = 5
}
}

View File

@ -33,24 +33,23 @@ export interface ContainerInterface {
*
* @deprecated
*/
const defaultContainer: ContainerInterface = new (class
implements ContainerInterface
{
private instances: { type: Function; object: any }[] = []
const defaultContainer: ContainerInterface =
new (class implements ContainerInterface {
private instances: { type: Function; object: any }[] = []
get<T>(someClass: ContainedType<T>): T {
let instance = this.instances.find((i) => i.type === someClass)
if (!instance) {
instance = {
type: someClass,
object: new (someClass as new () => T)(),
get<T>(someClass: ContainedType<T>): T {
let instance = this.instances.find((i) => i.type === someClass)
if (!instance) {
instance = {
type: someClass,
object: new (someClass as new () => T)(),
}
this.instances.push(instance)
}
this.instances.push(instance)
}
return instance.object
}
})()
return instance.object
}
})()
let userContainer: ContainerInterface
let userContainerOptions: UseContainerOptions | undefined

View File

@ -200,4 +200,15 @@ export interface ColumnOptions extends ColumnCommonOptions {
* @See https://typeorm.io/decorator-reference#virtualcolumn for more details.
*/
query?: (alias: string) => string
/**
* Indicates if date values should be stored and retrieved in UTC timezone
* instead of local timezone. Only applies to "date" column type.
* Default value is "false" (uses local timezone for backward compatibility).
*
* @example
* @Column({ type: "date", utc: true })
* birthDate: Date
*/
utc?: boolean
}

View File

@ -7,8 +7,7 @@ import { BaseDataSourceOptions } from "../../data-source/BaseDataSourceOptions"
* @see https://github.com/mysqljs/mysql#connection-options
*/
export interface AuroraMysqlConnectionOptions
extends BaseDataSourceOptions,
AuroraMysqlConnectionCredentialsOptions {
extends BaseDataSourceOptions, AuroraMysqlConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -533,7 +533,9 @@ export class AuroraMysqlDriver implements Driver {
if (columnMetadata.type === Boolean) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (columnMetadata.type === "json") {
@ -592,7 +594,9 @@ export class AuroraMysqlDriver implements Driver {
) {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "json") {
value = typeof value === "string" ? JSON.parse(value) : value
} else if (columnMetadata.type === "time") {

View File

@ -133,7 +133,7 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver {
nativeBinding = null,
prepareDatabase,
} = this.options
const databaseConnection = this.sqlite(database, {
const databaseConnection = new this.sqlite(database, {
readonly,
fileMustExist,
timeout,
@ -143,8 +143,8 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver {
// in the options, if encryption key for SQLCipher is setted.
// Must invoke key pragma before trying to do any other interaction with the database.
if (this.options.key) {
databaseConnection.exec(
`PRAGMA key = ${JSON.stringify(this.options.key)}`,
databaseConnection.pragma(
`key = ${JSON.stringify(this.options.key)}`,
)
}
@ -155,11 +155,11 @@ export class BetterSqlite3Driver extends AbstractSqliteDriver {
// we need to enable foreign keys in sqlite to make sure all foreign key related features
// working properly. this also makes onDelete to work with sqlite.
databaseConnection.exec(`PRAGMA foreign_keys = ON`)
databaseConnection.pragma("foreign_keys = ON")
// turn on WAL mode to enhance performance
if (this.options.enableWAL) {
databaseConnection.exec(`PRAGMA journal_mode = WAL`)
databaseConnection.pragma("journal_mode = WAL")
}
return databaseConnection

View File

@ -62,14 +62,16 @@ export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner {
* Called before migrations are run.
*/
async beforeMigration(): Promise<void> {
await this.query(`PRAGMA foreign_keys = OFF`)
const databaseConnection = await this.connect()
databaseConnection.pragma("foreign_keys = OFF")
}
/**
* Called after migrations are run.
*/
async afterMigration(): Promise<void> {
await this.query(`PRAGMA foreign_keys = ON`)
const databaseConnection = await this.connect()
databaseConnection.pragma("foreign_keys = ON")
}
/**
@ -172,10 +174,9 @@ export class BetterSqlite3QueryRunner extends AbstractSqliteQueryRunner {
}
protected async loadPragmaRecords(tablePath: string, pragma: string) {
const [database, tableName] = this.splitTablePath(tablePath)
const res = await this.query(
`PRAGMA ${
database ? `"${database}".` : ""
}${pragma}("${tableName}")`,
const databaseConnection = await this.connect()
const res = databaseConnection.pragma(
`${database ? `"${database}".` : ""}${pragma}("${tableName}")`,
)
return res
}

View File

@ -6,8 +6,7 @@ import { CockroachConnectionCredentialsOptions } from "./CockroachConnectionCred
* Cockroachdb-specific connection options.
*/
export interface CockroachConnectionOptions
extends BaseDataSourceOptions,
CockroachConnectionCredentialsOptions {
extends BaseDataSourceOptions, CockroachConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -385,7 +385,9 @@ export class CockroachDriver implements Driver {
if (columnMetadata.type === Boolean) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (
@ -445,7 +447,9 @@ export class CockroachDriver implements Driver {
) {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (columnMetadata.type === "simple-array") {

View File

@ -472,8 +472,7 @@ export declare class AggregationCursor<
/** @public */
export declare interface AggregationCursorOptions
extends AbstractCursorOptions,
AggregateOptions {}
extends AbstractCursorOptions, AggregateOptions {}
/**
* It is possible to search using alternative types in mongodb e.g.
@ -486,25 +485,24 @@ export declare type AlternativeType<T> =
/** @public */
export declare type AnyBulkWriteOperation<TSchema extends Document = Document> =
| {
insertOne: InsertOneModel<TSchema>
}
| {
replaceOne: ReplaceOneModel<TSchema>
}
| {
updateOne: UpdateOneModel<TSchema>
}
| {
updateMany: UpdateManyModel<TSchema>
}
| {
deleteOne: DeleteOneModel<TSchema>
}
| {
deleteMany: DeleteManyModel<TSchema>
}
| {
insertOne: InsertOneModel<TSchema>
}
| {
replaceOne: ReplaceOneModel<TSchema>
}
| {
updateOne: UpdateOneModel<TSchema>
}
| {
updateMany: UpdateManyModel<TSchema>
}
| {
deleteOne: DeleteOneModel<TSchema>
}
| {
deleteMany: DeleteManyModel<TSchema>
}
/** @public */
export declare type AnyError = MongoError | Error
@ -826,7 +824,8 @@ export { BSONRegExp }
* @public
*/
export declare interface BSONSerializeOptions
extends Omit<SerializeOptions, "index">,
extends
Omit<SerializeOptions, "index">,
Omit<
DeserializeOptions,
| "evalFunctions"
@ -1133,8 +1132,7 @@ export declare class ChangeStream<
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamCollModDocument
extends ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID {
extends ChangeStreamDocumentCommon, ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
operationType: "modify"
}
@ -1144,8 +1142,7 @@ export declare interface ChangeStreamCollModDocument
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamCreateDocument
extends ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID {
extends ChangeStreamDocumentCommon, ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
operationType: "create"
}
@ -1156,7 +1153,8 @@ export declare interface ChangeStreamCreateDocument
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamCreateIndexDocument
extends ChangeStreamDocumentCommon,
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID,
ChangeStreamDocumentOperationDescription {
/** Describes the type of operation represented in this change notification */
@ -1173,7 +1171,9 @@ export declare interface ChangeStreamCreateIndexDocument
*/
export declare interface ChangeStreamDeleteDocument<
TSchema extends Document = Document,
> extends ChangeStreamDocumentCommon,
>
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentKey<TSchema>,
ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
@ -1283,8 +1283,7 @@ export declare interface ChangeStreamDocumentOperationDescription {
* @public
* @see https://www.mongodb.com/docs/manual/reference/change-events/#dropdatabase-event
*/
export declare interface ChangeStreamDropDatabaseDocument
extends ChangeStreamDocumentCommon {
export declare interface ChangeStreamDropDatabaseDocument extends ChangeStreamDocumentCommon {
/** Describes the type of operation represented in this change notification */
operationType: "dropDatabase"
/** The database dropped */
@ -1298,8 +1297,7 @@ export declare interface ChangeStreamDropDatabaseDocument
* @see https://www.mongodb.com/docs/manual/reference/change-events/#drop-event
*/
export declare interface ChangeStreamDropDocument
extends ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID {
extends ChangeStreamDocumentCommon, ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
operationType: "drop"
/** Namespace the drop event occurred on */
@ -1312,7 +1310,8 @@ export declare interface ChangeStreamDropDocument
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamDropIndexDocument
extends ChangeStreamDocumentCommon,
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID,
ChangeStreamDocumentOperationDescription {
/** Describes the type of operation represented in this change notification */
@ -1339,7 +1338,9 @@ export declare type ChangeStreamEvents<
*/
export declare interface ChangeStreamInsertDocument<
TSchema extends Document = Document,
> extends ChangeStreamDocumentCommon,
>
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentKey<TSchema>,
ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
@ -1354,8 +1355,7 @@ export declare interface ChangeStreamInsertDocument<
* @public
* @see https://www.mongodb.com/docs/manual/reference/change-events/#invalidate-event
*/
export declare interface ChangeStreamInvalidateDocument
extends ChangeStreamDocumentCommon {
export declare interface ChangeStreamInvalidateDocument extends ChangeStreamDocumentCommon {
/** Describes the type of operation represented in this change notification */
operationType: "invalidate"
}
@ -1370,8 +1370,10 @@ export declare interface ChangeStreamNameSpace {
* Options that can be passed to a ChangeStream. Note that startAfter, resumeAfter, and startAtOperationTime are all mutually exclusive, and the server will error if more than one is specified.
* @public
*/
export declare interface ChangeStreamOptions
extends Omit<AggregateOptions, "writeConcern"> {
export declare interface ChangeStreamOptions extends Omit<
AggregateOptions,
"writeConcern"
> {
/**
* Allowed values: 'updateLookup', 'whenAvailable', 'required'.
*
@ -1439,7 +1441,8 @@ export declare interface ChangeStreamOptions
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamRefineCollectionShardKeyDocument
extends ChangeStreamDocumentCommon,
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID,
ChangeStreamDocumentOperationDescription {
/** Describes the type of operation represented in this change notification */
@ -1451,8 +1454,7 @@ export declare interface ChangeStreamRefineCollectionShardKeyDocument
* @see https://www.mongodb.com/docs/manual/reference/change-events/#rename-event
*/
export declare interface ChangeStreamRenameDocument
extends ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID {
extends ChangeStreamDocumentCommon, ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
operationType: "rename"
/** The new name for the `ns.coll` collection */
@ -1470,8 +1472,8 @@ export declare interface ChangeStreamRenameDocument
*/
export declare interface ChangeStreamReplaceDocument<
TSchema extends Document = Document,
> extends ChangeStreamDocumentCommon,
ChangeStreamDocumentKey<TSchema> {
>
extends ChangeStreamDocumentCommon, ChangeStreamDocumentKey<TSchema> {
/** Describes the type of operation represented in this change notification */
operationType: "replace"
/** The fullDocument of a replace event represents the document after the insert of the replacement document */
@ -1493,7 +1495,8 @@ export declare interface ChangeStreamReplaceDocument<
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamReshardCollectionDocument
extends ChangeStreamDocumentCommon,
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID,
ChangeStreamDocumentOperationDescription {
/** Describes the type of operation represented in this change notification */
@ -1505,7 +1508,8 @@ export declare interface ChangeStreamReshardCollectionDocument
* @see https://www.mongodb.com/docs/manual/reference/change-events/
*/
export declare interface ChangeStreamShardCollectionDocument
extends ChangeStreamDocumentCommon,
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentCollectionUUID,
ChangeStreamDocumentOperationDescription {
/** Describes the type of operation represented in this change notification */
@ -1518,7 +1522,9 @@ export declare interface ChangeStreamShardCollectionDocument
*/
export declare interface ChangeStreamUpdateDocument<
TSchema extends Document = Document,
> extends ChangeStreamDocumentCommon,
>
extends
ChangeStreamDocumentCommon,
ChangeStreamDocumentKey<TSchema>,
ChangeStreamDocumentCollectionUUID {
/** Describes the type of operation represented in this change notification */
@ -2297,8 +2303,7 @@ export declare interface CollectionInfo extends Document {
/** @public */
export declare interface CollectionOptions
extends BSONSerializeOptions,
WriteConcernOptions {
extends BSONSerializeOptions, WriteConcernOptions {
/** Specify a read concern for the collection. (only MongoDB 3.2 or higher supported) */
readConcern?: ReadConcernLike
/** The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). */
@ -2387,9 +2392,7 @@ export declare class CommandFailedEvent {
/** @public */
export declare interface CommandOperationOptions
extends OperationOptions,
WriteConcernOptions,
ExplainOptions {
extends OperationOptions, WriteConcernOptions, ExplainOptions {
/** Specify a read concern and level for the collection. (only MongoDB 3.2 or higher supported) */
readConcern?: ReadConcernLike
/** Collation */
@ -2553,7 +2556,8 @@ export declare type ConnectionEvents = {
/** @public */
export declare interface ConnectionOptions
extends SupportedNodeConnectionOptions,
extends
SupportedNodeConnectionOptions,
StreamDescriptionOptions,
ProxyOptions {
id: number | "<monitor>"
@ -2638,8 +2642,10 @@ export declare class ConnectionPoolMonitoringEvent {
}
/** @public */
export declare interface ConnectionPoolOptions
extends Omit<ConnectionOptions, "id" | "generation"> {
export declare interface ConnectionPoolOptions extends Omit<
ConnectionOptions,
"id" | "generation"
> {
/** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections. */
maxPoolSize: number
/** The minimum number of connections that MUST exist at any moment in a single connection pool. */
@ -2701,8 +2707,7 @@ export declare interface CountOptions extends CommandOperationOptions {
}
/** @public */
export declare interface CreateCollectionOptions
extends CommandOperationOptions {
export declare interface CreateCollectionOptions extends CommandOperationOptions {
/** Returns an error if the collection does not exist */
strict?: boolean
/** Create a capped collection */
@ -2749,8 +2754,10 @@ export declare interface CreateCollectionOptions
}
/** @public */
export declare interface CreateIndexesOptions
extends Omit<CommandOperationOptions, "writeConcern"> {
export declare interface CreateIndexesOptions extends Omit<
CommandOperationOptions,
"writeConcern"
> {
/** Creates the index in the background, yielding whenever possible. */
background?: boolean
/** Creates a unique index. */
@ -3054,8 +3061,7 @@ export declare class Db {
/** @public */
export declare interface DbOptions
extends BSONSerializeOptions,
WriteConcernOptions {
extends BSONSerializeOptions, WriteConcernOptions {
/** If the database authentication is dependent on another databaseName. */
authSource?: string
/** Force server to assign _id values instead of driver. */
@ -3103,8 +3109,7 @@ export declare interface DeleteOneModel<TSchema extends Document = Document> {
/** @public */
export declare interface DeleteOptions
extends CommandOperationOptions,
WriteConcernOptions {
extends CommandOperationOptions, WriteConcernOptions {
/** If true, when an insert fails, don't execute the remaining writes. If false, continue with remaining inserts when one fails. */
ordered?: boolean
/** Specifies the collation to use for the operation */
@ -3194,8 +3199,7 @@ export declare interface ErrorDescription extends Document {
}
/** @public */
export declare interface EstimatedDocumentCountOptions
extends CommandOperationOptions {
export declare interface EstimatedDocumentCountOptions extends CommandOperationOptions {
/**
* The maximum amount of time to allow the operation to run.
*
@ -3263,8 +3267,9 @@ export declare type FilterOperations<T> =
: FilterOperators<T>
/** @public */
export declare interface FilterOperators<TValue>
extends NonObjectIdLikeDocument {
export declare interface FilterOperators<
TValue,
> extends NonObjectIdLikeDocument {
$eq?: TValue
$gt?: TValue
$gte?: TValue
@ -3459,8 +3464,7 @@ export declare class FindCursor<TSchema = any> extends AbstractCursor<TSchema> {
}
/** @public */
export declare interface FindOneAndDeleteOptions
extends CommandOperationOptions {
export declare interface FindOneAndDeleteOptions extends CommandOperationOptions {
/** An optional hint for query optimization. See the {@link https://www.mongodb.com/docs/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/
hint?: Document
/** Limits the fields to return for all matching documents. */
@ -3472,8 +3476,7 @@ export declare interface FindOneAndDeleteOptions
}
/** @public */
export declare interface FindOneAndReplaceOptions
extends CommandOperationOptions {
export declare interface FindOneAndReplaceOptions extends CommandOperationOptions {
/** Allow driver to bypass schema validation in MongoDB 3.2 or higher. */
bypassDocumentValidation?: boolean
/** An optional hint for query optimization. See the {@link https://www.mongodb.com/docs/manual/reference/command/update/#update-command-hint|update command} reference for more information.*/
@ -3491,8 +3494,7 @@ export declare interface FindOneAndReplaceOptions
}
/** @public */
export declare interface FindOneAndUpdateOptions
extends CommandOperationOptions {
export declare interface FindOneAndUpdateOptions extends CommandOperationOptions {
/** Optional list of array filters referenced in filtered positional operators */
arrayFilters?: Document[]
/** Allow driver to bypass schema validation in MongoDB 3.2 or higher. */
@ -3544,8 +3546,9 @@ export declare class FindOperators {
* @public
* @typeParam TSchema - Unused schema definition, deprecated usage, only specify `FindOptions` with no generic
*/
export declare interface FindOptions<TSchema extends Document = Document>
extends Omit<CommandOperationOptions, "writeConcern"> {
export declare interface FindOptions<
TSchema extends Document = Document,
> extends Omit<CommandOperationOptions, "writeConcern"> {
/** Sets the limit of documents returned in the query. */
limit?: number
/** Set to sort the documents coming back from the query. Array of indexes, `[['a', 1]]` etc. */
@ -3773,8 +3776,7 @@ export declare interface GridFSBucketReadStreamOptions {
}
/** @public */
export declare interface GridFSBucketReadStreamOptionsWithRevision
extends GridFSBucketReadStreamOptions {
export declare interface GridFSBucketReadStreamOptionsWithRevision extends GridFSBucketReadStreamOptions {
/** The revision number relative to the oldest file with the given filename. 0
* gets you the oldest file, 1 gets you the 2nd oldest, -1 gets you the
* newest. */
@ -3868,8 +3870,7 @@ export declare class GridFSBucketWriteStream {
}
/** @public */
export declare interface GridFSBucketWriteStreamOptions
extends WriteConcernOptions {
export declare interface GridFSBucketWriteStreamOptions extends WriteConcernOptions {
/** Overwrite this bucket's chunkSizeBytes for this file */
chunkSizeBytes?: number
/** Custom file id for the GridFS file. */
@ -3939,28 +3940,27 @@ export declare class HostAddress {
}
/** @public */
export declare interface IndexDescription
extends Pick<
CreateIndexesOptions,
| "background"
| "unique"
| "partialFilterExpression"
| "sparse"
| "hidden"
| "expireAfterSeconds"
| "storageEngine"
| "version"
| "weights"
| "default_language"
| "language_override"
| "textIndexVersion"
| "2dsphereIndexVersion"
| "bits"
| "min"
| "max"
| "bucketSize"
| "wildcardProjection"
> {
export declare interface IndexDescription extends Pick<
CreateIndexesOptions,
| "background"
| "unique"
| "partialFilterExpression"
| "sparse"
| "hidden"
| "expireAfterSeconds"
| "storageEngine"
| "version"
| "weights"
| "default_language"
| "language_override"
| "textIndexVersion"
| "2dsphereIndexVersion"
| "bits"
| "min"
| "max"
| "bucketSize"
| "wildcardProjection"
> {
collation?: CollationOptions
name?: string
key:
@ -4254,8 +4254,10 @@ export declare class ListCollectionsCursor<
}
/** @public */
export declare interface ListCollectionsOptions
extends Omit<CommandOperationOptions, "writeConcern"> {
export declare interface ListCollectionsOptions extends Omit<
CommandOperationOptions,
"writeConcern"
> {
/** Since 4.0: If true, will only return the collection name in the response, and will omit additional info */
nameOnly?: boolean
/** Since 4.0: If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */
@ -4296,8 +4298,10 @@ export declare class ListIndexesCursor extends AbstractCursor {
}
/** @public */
export declare interface ListIndexesOptions
extends Omit<CommandOperationOptions, "writeConcern"> {
export declare interface ListIndexesOptions extends Omit<
CommandOperationOptions,
"writeConcern"
> {
/** The batchSize for the returned command cursor or if pre 2.8 the systems batch collection */
batchSize?: number
}
@ -4571,8 +4575,7 @@ export declare type MongoClientEvents = Pick<
* @see https://www.mongodb.com/docs/manual/reference/connection-string
*/
export declare interface MongoClientOptions
extends BSONSerializeOptions,
SupportedNodeConnectionOptions {
extends BSONSerializeOptions, SupportedNodeConnectionOptions {
/** Specifies the name of the replica set, if the mongod is a member of a replica set. */
replicaSet?: string
/** Enables or disables TLS/SSL for the connection. */
@ -5044,7 +5047,8 @@ export declare class MongoNotConnectedError extends MongoAPIError {
* @public
*/
export declare interface MongoOptions
extends Required<
extends
Required<
Pick<
MongoClientOptions,
| "autoEncryption"
@ -5283,8 +5287,10 @@ export declare type MonitorEvents = {
/* Excluded from this release type: MonitorIntervalOptions */
/** @public */
export declare interface MonitorOptions
extends Omit<ConnectionOptions, "id" | "generation" | "hostAddress"> {
export declare interface MonitorOptions extends Omit<
ConnectionOptions,
"id" | "generation" | "hostAddress"
> {
connectTimeoutMS: number
heartbeatFrequencyMS: number
minHeartbeatFrequencyMS: number
@ -5713,8 +5719,7 @@ export declare class ReadPreference {
}
/** @public */
export declare interface ReadPreferenceFromOptions
extends ReadPreferenceLikeOptions {
export declare interface ReadPreferenceFromOptions extends ReadPreferenceLikeOptions {
session?: ClientSession
readPreferenceTags?: TagSet[]
hedge?: HedgeOptions
@ -5724,8 +5729,7 @@ export declare interface ReadPreferenceFromOptions
export declare type ReadPreferenceLike = ReadPreference | ReadPreferenceMode
/** @public */
export declare interface ReadPreferenceLikeOptions
extends ReadPreferenceOptions {
export declare interface ReadPreferenceLikeOptions extends ReadPreferenceOptions {
readPreference?:
| ReadPreferenceLike
| {
@ -6511,8 +6515,9 @@ export declare interface TransactionOptions extends CommandOperationOptions {
* Typescript type safe event emitter
* @public
*/
export declare interface TypedEventEmitter<Events extends EventsDescription>
extends EventEmitter {
export declare interface TypedEventEmitter<
Events extends EventsDescription,
> extends EventEmitter {
addListener<EventKey extends keyof Events>(
event: EventKey,
listener: Events[EventKey],
@ -6800,8 +6805,7 @@ export declare interface UpdateStatement {
}
/** @public */
export declare interface ValidateCollectionOptions
extends CommandOperationOptions {
export declare interface ValidateCollectionOptions extends CommandOperationOptions {
/** Validates a collection in the background, without interrupting read or write traffic (only in MongoDB 4.4+) */
background?: boolean
}

View File

@ -43,4 +43,10 @@ export interface MysqlConnectionCredentialsOptions {
* Database socket path
*/
readonly socketPath?: string
/**
* Maximum number of clients the pool should contain.
* for each connection
*/
readonly poolSize?: number
}

View File

@ -8,8 +8,7 @@ import { MysqlConnectionCredentialsOptions } from "./MysqlConnectionCredentialsO
* @see https://github.com/mysqljs/mysql#connection-options
*/
export interface MysqlConnectionOptions
extends BaseDataSourceOptions,
MysqlConnectionCredentialsOptions {
extends BaseDataSourceOptions, MysqlConnectionCredentialsOptions {
/**
* Database type.
*/
@ -17,8 +16,7 @@ export interface MysqlConnectionOptions
/**
* The driver object
* This defaults to require("mysql").
* Falls back to require("mysql2")
* This defaults to require("mysql2").
*/
readonly driver?: any
@ -103,12 +101,6 @@ export interface MysqlConnectionOptions
*/
readonly flags?: string[]
/**
* TypeORM will automatically use package found in your node_modules, prioritizing mysql over mysql2,
* but you can specify it manually
*/
readonly connectorPackage?: "mysql" | "mysql2"
/**
* If a value is specified for maxQueryExecutionTime, in addition to generating a warning log when a query exceeds this time limit,
* the specified maxQueryExecutionTime value is also used as the timeout for the query.

View File

@ -57,11 +57,6 @@ export class MysqlDriver implements Driver {
*/
poolCluster: any
/**
* The actual connector package that was loaded ("mysql" or "mysql2").
*/
private loadedConnectorPackage: "mysql" | "mysql2" | undefined
// -------------------------------------------------------------------------
// Public Implemented Properties
// -------------------------------------------------------------------------
@ -157,6 +152,8 @@ export class MysqlDriver implements Driver {
"multilinestring",
"multipolygon",
"geometrycollection",
// vector data types
"vector",
// additional data types for mariadb
"uuid",
"inet4",
@ -191,6 +188,7 @@ export class MysqlDriver implements Driver {
"nvarchar",
"binary",
"varbinary",
"vector",
]
/**
@ -280,6 +278,7 @@ export class MysqlDriver implements Driver {
char: { length: 1 },
binary: { length: 1 },
varbinary: { length: 255 },
vector: { length: 2048 }, // default length MySQL uses if not provided a value
decimal: { precision: 10, scale: 0 },
dec: { precision: 10, scale: 0 },
numeric: { precision: 10, scale: 0 },
@ -589,14 +588,6 @@ export class MysqlDriver implements Driver {
}
}
/**
* Checks if the driver is using mysql2 package.
*/
protected isUsingMysql2(): boolean {
// Check which package was actually loaded during initialization
return this.loadedConnectorPackage === "mysql2"
}
/**
* Prepares given value to a value to be persisted, based on its column type and metadata.
*/
@ -612,7 +603,9 @@ export class MysqlDriver implements Driver {
if (columnMetadata.type === Boolean) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (columnMetadata.type === "json") {
@ -666,29 +659,23 @@ export class MysqlDriver implements Driver {
) {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "json") {
// mysql2 returns JSON values already parsed, but may still be a string
// if the JSON value itself is a string (e.g., "\"hello\"")
// mysql (classic) always returns JSON as strings that need parsing
if (this.isUsingMysql2()) {
// With mysql2, only parse if it's a valid JSON string representation
// but not if it's already an object or a JSON primitive
if (typeof value === "string") {
try {
// Try to parse it - if it fails, it's already a parsed string value
const parsed = JSON.parse(value)
value = parsed
} catch {
// It's a string that's not valid JSON, which means mysql2
// already parsed it and it's just a string value
// Keep value as is
}
// mysql2 only parse if it's a valid JSON string representation
// but not if it's already an object or a JSON primitive
// If it's not a string, mysql2 has already parsed it correctly
if (typeof value === "string") {
try {
// Try to parse it - if it fails, it's already a parsed string value
const parsed = JSON.parse(value)
value = parsed
} catch {
// It's a string that's not valid JSON, which means mysql2
// already parsed it and it's just a string value
// Keep value as is
}
// If it's not a string, mysql2 has already parsed it correctly
} else {
// Classic mysql always returns JSON as strings
value = typeof value === "string" ? JSON.parse(value) : value
}
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
@ -1188,64 +1175,10 @@ export class MysqlDriver implements Driver {
* Loads all driver dependencies.
*/
protected loadDependencies(): void {
// Warn if driver is provided directly but connectorPackage is not specified
if (this.options.driver && !this.options.connectorPackage) {
console.warn(
"Warning: MySQL driver instance provided directly without specifying connectorPackage. " +
"This may lead to unexpected JSON parsing behavior differences between mysql and mysql2. " +
"Consider explicitly setting connectorPackage: 'mysql' or 'mysql2' in your configuration.",
)
}
const connectorPackage = this.options.connectorPackage ?? "mysql"
const fallbackConnectorPackage =
connectorPackage === "mysql"
? ("mysql2" as const)
: ("mysql" as const)
try {
// try to load first supported package
const mysql =
this.options.driver || PlatformTools.load(connectorPackage)
this.mysql = mysql
/*
* Some frameworks (such as Jest) may mess up Node's require cache and provide garbage for the 'mysql' module
* if it was not installed. We check that the object we got actually contains something otherwise we treat
* it as if the `require` call failed.
*
* @see https://github.com/typeorm/typeorm/issues/1373
*/
if (Object.keys(this.mysql).length === 0) {
throw new TypeORMError(
`'${connectorPackage}' was found but it is empty. Falling back to '${fallbackConnectorPackage}'.`,
)
}
// Successfully loaded the requested package
// If driver was provided directly, try to detect which package it is
if (this.options.driver && !this.options.connectorPackage) {
// Try to detect if it's mysql2 based on unique properties
if (
this.mysql.version ||
(this.mysql.Connection &&
this.mysql.Connection.prototype.execute)
) {
this.loadedConnectorPackage = "mysql2"
} else {
this.loadedConnectorPackage = "mysql"
}
} else {
this.loadedConnectorPackage = connectorPackage
}
this.mysql = this.options.driver || PlatformTools.load("mysql2")
} catch (e) {
try {
this.mysql = PlatformTools.load(fallbackConnectorPackage) // try to load second supported package
// Successfully loaded the fallback package
this.loadedConnectorPackage = fallbackConnectorPackage
} catch (e) {
throw new DriverPackageNotInstalledError(
"Mysql",
connectorPackage,
)
}
throw new DriverPackageNotInstalledError("Mysql", "mysql2")
}
}
@ -1293,7 +1226,7 @@ export class MysqlDriver implements Driver {
port: credentials.port,
ssl: options.ssl,
socketPath: credentials.socketPath,
connectionLimit: options.poolSize,
connectionLimit: credentials.poolSize ?? options.poolSize,
},
options.acquireTimeout === undefined
? {}

View File

@ -2800,17 +2800,19 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
) !== -1 &&
dbColumn["CHARACTER_MAXIMUM_LENGTH"]
) {
const length =
dbColumn[
"CHARACTER_MAXIMUM_LENGTH"
].toString()
let length: number =
dbColumn["CHARACTER_MAXIMUM_LENGTH"]
if (tableColumn.type === "vector") {
// MySQL and MariaDb store the vector length in bytes, not in number of dimensions.
length = length / 4
}
tableColumn.length =
!this.isDefaultColumnLength(
table,
tableColumn,
length,
length.toString(),
)
? length
? length.toString()
: ""
}

View File

@ -13,8 +13,7 @@ export interface OracleThickModeOptions {
* Oracle-specific connection options.
*/
export interface OracleConnectionOptions
extends BaseDataSourceOptions,
OracleConnectionCredentialsOptions {
extends BaseDataSourceOptions, OracleConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -531,9 +531,9 @@ export class OracleDriver implements Driver {
} else if (columnMetadata.type === "date") {
if (typeof value === "string") value = value.replace(/[^0-9-]/g, "")
return () =>
`TO_DATE('${DateUtils.mixedDateToDateString(
value,
)}', 'YYYY-MM-DD')`
`TO_DATE('${DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})}', 'YYYY-MM-DD')`
} else if (
columnMetadata.type === Date ||
columnMetadata.type === "timestamp" ||
@ -567,7 +567,9 @@ export class OracleDriver implements Driver {
if (columnMetadata.type === Boolean) {
value = !!value
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (

View File

@ -6,8 +6,7 @@ import { PostgresConnectionCredentialsOptions } from "./PostgresConnectionCreden
* Postgres-specific connection options.
*/
export interface PostgresConnectionOptions
extends BaseDataSourceOptions,
PostgresConnectionCredentialsOptions {
extends BaseDataSourceOptions, PostgresConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -656,7 +656,9 @@ export class PostgresDriver implements Driver {
if (columnMetadata.type === Boolean) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (
@ -755,7 +757,9 @@ export class PostgresDriver implements Driver {
) {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (

View File

@ -335,7 +335,9 @@ export class ReactNativeDriver implements Driver {
) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (
@ -407,7 +409,9 @@ export class ReactNativeDriver implements Driver {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (columnMetadata.type === "simple-array") {

View File

@ -5,8 +5,7 @@ import { SapConnectionCredentialsOptions } from "./SapConnectionCredentialsOptio
* SAP Hana specific connection options.
*/
export interface SapConnectionOptions
extends BaseDataSourceOptions,
SapConnectionCredentialsOptions {
extends BaseDataSourceOptions, SapConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -542,7 +542,9 @@ export class SapDriver implements Driver {
if (value === null || value === undefined) return value
if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (
@ -584,7 +586,9 @@ export class SapDriver implements Driver {
) {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (columnMetadata.type === "simple-array") {

View File

@ -6,8 +6,7 @@ import { SpannerConnectionCredentialsOptions } from "./SpannerConnectionCredenti
* Spanner specific connection options.
*/
export interface SpannerConnectionOptions
extends BaseConnectionOptions,
SpannerConnectionCredentialsOptions {
extends BaseConnectionOptions, SpannerConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -399,7 +399,9 @@ export class SpannerDriver implements Driver {
const lib = this.options.driver || PlatformTools.load("spanner")
return lib.Spanner.numeric(value.toString())
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "json") {
return value
} else if (
@ -434,7 +436,9 @@ export class SpannerDriver implements Driver {
} else if (columnMetadata.type === "numeric") {
value = value.value
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "json") {
value = typeof value === "string" ? JSON.parse(value) : value
} else if (columnMetadata.type === Number) {

View File

@ -331,7 +331,9 @@ export abstract class AbstractSqliteDriver implements Driver {
) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDateString(value)
return DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
return DateUtils.mixedDateToTimeString(value)
} else if (
@ -406,7 +408,9 @@ export abstract class AbstractSqliteDriver implements Driver {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (

View File

@ -6,8 +6,7 @@ import { SqlServerConnectionCredentialsOptions } from "./SqlServerConnectionCred
* Microsoft Sql Server specific connection options.
*/
export interface SqlServerConnectionOptions
extends BaseDataSourceOptions,
SqlServerConnectionCredentialsOptions {
extends BaseDataSourceOptions, SqlServerConnectionCredentialsOptions {
/**
* Database type.
*/

View File

@ -532,7 +532,7 @@ export class SqlServerDriver implements Driver {
if (columnMetadata.type === Boolean) {
return value === true ? 1 : 0
} else if (columnMetadata.type === "date") {
return DateUtils.mixedDateToDate(value)
return DateUtils.mixedDateToDate(value, columnMetadata.utc)
} else if (columnMetadata.type === "time") {
return DateUtils.mixedTimeToDate(value)
} else if (
@ -586,7 +586,9 @@ export class SqlServerDriver implements Driver {
) {
value = DateUtils.normalizeHydratedDate(value)
} else if (columnMetadata.type === "date") {
value = DateUtils.mixedDateToDateString(value)
value = DateUtils.mixedDateToDateString(value, {
utc: columnMetadata.utc,
})
} else if (columnMetadata.type === "time") {
value = DateUtils.mixedTimeToString(value)
} else if (columnMetadata.type === "simple-array") {

View File

@ -75,7 +75,7 @@ export type WithLengthColumnType =
| "binary" // mssql
| "varbinary" // mssql, sap
| "string" // cockroachdb, spanner
| "vector" // postgres, mssql, sap
| "vector" // mariadb, mysql, mssql, postgres, sap
| "halfvec" // postgres, sap
| "half_vector" // sap
| "real_vector" // sap

View File

@ -971,7 +971,7 @@ export class EntityManager {
/**
* Checks whether any entity exists with the given options.
*/
exists<Entity extends ObjectLiteral>(
async exists<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
options?: FindManyOptions<Entity>,
): Promise<boolean> {
@ -1002,7 +1002,7 @@ export class EntityManager {
* Counts entities that match given options.
* Useful for pagination.
*/
count<Entity extends ObjectLiteral>(
async count<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
options?: FindManyOptions<Entity>,
): Promise<number> {
@ -1020,7 +1020,7 @@ export class EntityManager {
* Counts entities that match given conditions.
* Useful for pagination.
*/
countBy<Entity extends ObjectLiteral>(
async countBy<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
): Promise<number> {
@ -1090,12 +1090,16 @@ export class EntityManager {
)
}
const result = await this.createQueryBuilder(entityClass, metadata.name)
.setFindOptions({ where })
const qb = this.createQueryBuilder(entityClass, metadata.name)
qb.setFindOptions({ where })
const alias = qb.alias
const result = await qb
.select(
`${fnName}(${this.connection.driver.escape(
column.databaseName,
)})`,
alias,
)}.${this.connection.driver.escape(column.databaseName)})`,
fnName,
)
.getRawOne()
@ -1140,7 +1144,7 @@ export class EntityManager {
* Also counts all entities that match given conditions,
* but ignores pagination settings (from and take options).
*/
findAndCount<Entity extends ObjectLiteral>(
async findAndCount<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
options?: FindManyOptions<Entity>,
): Promise<[Entity[], number]> {
@ -1159,7 +1163,7 @@ export class EntityManager {
* Also counts all entities that match given conditions,
* but ignores pagination settings (from and take options).
*/
findAndCountBy<Entity extends ObjectLiteral>(
async findAndCountBy<Entity extends ObjectLiteral>(
entityClass: EntityTarget<Entity>,
where: FindOptionsWhere<Entity> | FindOptionsWhere<Entity>[],
): Promise<[Entity[], number]> {

View File

@ -15,46 +15,46 @@ import { DeleteResult } from "../query-builder/result/DeleteResult"
import { EntityMetadata } from "../metadata/EntityMetadata"
import {
BulkWriteResult,
AggregationCursor,
Collection,
FindCursor,
Document,
AggregateOptions,
AggregationCursor,
AnyBulkWriteOperation,
BulkWriteOptions,
Filter,
CountOptions,
IndexSpecification,
CreateIndexesOptions,
IndexDescription,
DeleteResult as DeleteResultMongoDb,
DeleteOptions,
CommandOperationOptions,
FindOneAndDeleteOptions,
FindOneAndReplaceOptions,
UpdateFilter,
FindOneAndUpdateOptions,
RenameOptions,
ReplaceOptions,
UpdateResult as UpdateResultMongoDb,
BulkWriteResult,
ChangeStream,
ChangeStreamOptions,
Collection,
CollStats,
CollStatsOptions,
ChangeStreamOptions,
ChangeStream,
UpdateOptions,
ListIndexesOptions,
ListIndexesCursor,
OptionalId,
CommandOperationOptions,
CountDocumentsOptions,
CountOptions,
CreateIndexesOptions,
DeleteOptions,
DeleteResult as DeleteResultMongoDb,
Document,
Filter,
FilterOperators,
FindCursor,
FindOneAndDeleteOptions,
FindOneAndReplaceOptions,
FindOneAndUpdateOptions,
IndexDescription,
IndexInformationOptions,
IndexSpecification,
InsertManyResult,
InsertOneOptions,
InsertOneResult,
InsertManyResult,
UnorderedBulkOperation,
OrderedBulkOperation,
IndexInformationOptions,
ListIndexesCursor,
ListIndexesOptions,
ObjectId,
FilterOperators,
CountDocumentsOptions,
OptionalId,
OrderedBulkOperation,
RenameOptions,
ReplaceOptions,
UnorderedBulkOperation,
UpdateFilter,
UpdateOptions,
UpdateResult as UpdateResultMongoDb,
} from "../driver/mongodb/typings"
import { DataSource } from "../data-source/DataSource"
import { MongoFindManyOptions } from "../find-options/mongodb/MongoFindManyOptions"
@ -161,6 +161,16 @@ export class MongoEntityManager extends EntityManager {
return this.executeFindAndCount(entityClassOrName, where)
}
/**
* Finds entities that match given WHERE conditions.
*/
async findBy<Entity>(
entityClassOrName: EntityTarget<Entity>,
where: any,
): Promise<Entity[]> {
return this.executeFind(entityClassOrName, where)
}
/**
* Finds entities by ids.
* Optionally find options can be applied.

View File

@ -3,8 +3,9 @@ import { MongoFindOneOptions } from "./MongoFindOneOptions"
/**
* Defines a special criteria to find specific entities.
*/
export interface MongoFindManyOptions<Entity = any>
extends MongoFindOneOptions<Entity> {
export interface MongoFindManyOptions<
Entity = any,
> extends MongoFindOneOptions<Entity> {
/**
* Offset (paginated) where from entities should be taken.
*/

View File

@ -123,6 +123,12 @@ export class ColumnMetadata {
*/
comment?: string
/**
* Indicates if date values use UTC timezone.
* Only applies to "date" column type.
*/
utc: boolean = false
/**
* Default database value.
*/
@ -388,6 +394,8 @@ export class ColumnMetadata {
this.isSelect = options.args.options.select
if (options.args.options.insert !== undefined)
this.isInsert = options.args.options.insert
if (options.args.options.utc !== undefined)
this.utc = options.args.options.utc
if (options.args.options.update !== undefined)
this.isUpdate = options.args.options.update
if (options.args.options.readonly !== undefined)

View File

@ -12,6 +12,7 @@ import { PropertyTypeFactory } from "./types/PropertyTypeInFunction"
import { TypeORMError } from "../error"
import { ObjectUtils } from "../util/ObjectUtils"
import { InstanceChecker } from "../util/InstanceChecker"
import { OrmUtils } from "../util/OrmUtils"
/**
* Contains all information about some entity's relation.
@ -520,7 +521,11 @@ export class RelationMetadata {
entity,
)
} else {
entity[propertyName] = value
if (ObjectUtils.isObject(entity[propertyName])) {
OrmUtils.mergeDeep(entity[propertyName], value)
} else {
entity[propertyName] = value
}
}
}

View File

@ -414,6 +414,8 @@ export class MigrationExecutor {
this.connection.logger.logSchemaBuild(
`No migrations were found in the database. Nothing to revert!`,
)
// if query runner was created by us then release it
if (!this.queryRunner) await queryRunner.release()
return
}

View File

@ -27,6 +27,20 @@ export class PlatformTools {
return global
}
/**
* Reads the version string from package.json of the given package.
* This operation is only supported in node.
*/
static readPackageVersion(name: string): string {
try {
return require(`${name}/package.json`).version
} catch (err) {
throw new TypeError(
`Failed to read package.json for "${name}": ${err.message}`,
)
}
}
/**
* Loads ("require"-s) given file or package.
* This operation only supports on node platform
@ -63,9 +77,6 @@ export class PlatformTools {
/**
* mysql
*/
case "mysql":
return require("mysql")
case "mysql2":
return require("mysql2")

View File

@ -25,8 +25,21 @@ export class DateUtils {
/**
* Converts given value into date string in a "YYYY-MM-DD" format.
*/
static mixedDateToDateString(value: string | Date): string {
static mixedDateToDateString(
value: string | Date,
options?: { utc?: boolean },
): string {
const utc = options?.utc ?? false
if (value instanceof Date) {
if (utc) {
return (
this.formatZerolessValue(value.getUTCFullYear(), 4) +
"-" +
this.formatZerolessValue(value.getUTCMonth() + 1) +
"-" +
this.formatZerolessValue(value.getUTCDate())
)
}
return (
this.formatZerolessValue(value.getFullYear(), 4) +
"-" +

View File

@ -12,6 +12,7 @@ describe("benchmark > bulk-sql-build", () => {
before(async () => {
dataSources = await createTestingConnections({
__dirname,
enabledDrivers: ["postgres"],
})
})
beforeEach(() => reloadTestingDatabases(dataSources))

View File

@ -1,11 +1,11 @@
import { expect } from "chai"
import "reflect-metadata"
import { scheduler } from "timers/promises"
import { DataSource } from "../../../../src"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
sleep,
} from "../../../utils/test-utils"
import { Post } from "./entity/Post"
@ -81,7 +81,7 @@ describe("column kinds > create date column", () => {
})
// wait a second
await sleep(1000)
await scheduler.wait(1010)
// create post once again
post.title = "Updated Title"

View File

@ -1,11 +1,11 @@
import { expect } from "chai"
import "reflect-metadata"
import { scheduler } from "timers/promises"
import { DataSource } from "../../../../src"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
sleep,
} from "../../../utils/test-utils"
import { Post } from "./entity/Post"
@ -109,7 +109,7 @@ describe("column kinds > update date column", () => {
})
// wait a second
await sleep(2000)
await scheduler.wait(1010)
// update post once again
post.title = "Updated Title"
@ -120,9 +120,9 @@ describe("column kinds > update date column", () => {
await postRepository.findOneByOrFail({
id: post.id,
})
expect(loadedPostAfterUpdate.updatedAt.getTime()).to.be.not.eql(
loadedPostBeforeUpdate.updatedAt.getTime(),
)
expect(
loadedPostAfterUpdate.updatedAt.getTime(),
).to.be.greaterThan(loadedPostBeforeUpdate.updatedAt.getTime())
}),
))

View File

@ -5,7 +5,6 @@ import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
sleep,
} from "../../../utils/test-utils"
import { Post } from "./entity/Post"
@ -98,9 +97,6 @@ describe("column kinds > version column", () => {
post.title = "Post"
await postRepository.save(post)
// wait a second
await sleep(1000)
// update post once again
post.title = "Updated Title"
await postRepository.save(post)

View File

@ -1,15 +1,15 @@
import "reflect-metadata"
import { expect } from "chai"
import "reflect-metadata"
import { scheduler } from "timers/promises"
import { DataSource } from "../../../src/data-source/DataSource"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
sleep,
} from "../../utils/test-utils"
import { DataSource } from "../../../src/data-source/DataSource"
import { Address } from "./entity/Address"
import { User } from "./entity/User"
import { MockQueryResultCache } from "./provider/MockQueryResultCache"
import { Address } from "./entity/Address"
describe("custom cache provider", () => {
let connections: DataSource[]
@ -101,7 +101,7 @@ describe("custom cache provider", () => {
expect(users3.length).to.be.equal(1)
// give some time for cache to expire
await sleep(1000)
await scheduler.wait(1010)
// now, when our cache has expired we check if we have new user inserted even with cache enabled
const users4 = await connection
@ -179,7 +179,7 @@ describe("custom cache provider", () => {
expect(users3.length).to.be.equal(1)
// give some time for cache to expire
await sleep(1000)
await scheduler.wait(1010)
// now, when our cache has expired we check if we have new user inserted even with cache enabled
const users4 = await connection
@ -249,7 +249,7 @@ describe("custom cache provider", () => {
expect(users2.length).to.be.equal(2)
// give some time for cache to expire
await sleep(1000)
await scheduler.wait(1010)
// but with cache enabled it must not return newly inserted entity since cache is not expired yet
const users3 = await connection
@ -263,7 +263,7 @@ describe("custom cache provider", () => {
expect(users3.length).to.be.equal(1)
// give some time for cache to expire
await sleep(1000)
await scheduler.wait(1010)
// now, when our cache has expired we check if we have new user inserted even with cache enabled
const users4 = await connection
@ -389,7 +389,7 @@ describe("custom cache provider", () => {
expect(users3).to.be.equal(1)
// give some time for cache to expire
await sleep(1000)
await scheduler.wait(1010)
// now, when our cache has expired we check if we have new user inserted even with cache enabled
const users4 = await connection

View File

@ -0,0 +1,50 @@
import "reflect-metadata"
import { expect } from "chai"
import {
closeTestingConnections,
createTestingConnections,
reloadTestingDatabases,
} from "../../../utils/test-utils"
import { Event } from "./entity/Event"
import { DataSource } from "../../../../src"
describe("columns > date utc flag", () => {
let originalTZ: string | undefined
let connections: DataSource[]
before(async () => {
originalTZ = process.env.TZ
process.env.TZ = "America/New_York"
connections = await createTestingConnections({
entities: [Event],
})
})
after(async () => {
process.env.TZ = originalTZ
await closeTestingConnections(connections)
})
beforeEach(() => reloadTestingDatabases(connections))
it("should save date columns in UTC when utc flag is true and in local timezone when false", () =>
Promise.all(
connections.map(async (connection) => {
const event = new Event()
const testDate = new Date(Date.UTC(2025, 5, 1)) // 2025-06-01 in UTC
event.localDate = testDate
event.utcDate = testDate
const savedEvent = await connection.manager.save(event)
const result = await connection.manager.findOneBy(Event, {
id: savedEvent.id,
})
// UTC flag true: should save as 2025-06-01 (UTC date)
expect(result!.utcDate).to.equal("2025-06-01")
// UTC flag false (default): should save as 2025-05-31 (local timezone)
expect(result!.localDate).to.equal("2025-05-31")
}),
))
})

View File

@ -0,0 +1,17 @@
import { Entity } from "../../../../../src/decorator/entity/Entity"
import { PrimaryGeneratedColumn } from "../../../../../src/decorator/columns/PrimaryGeneratedColumn"
import { Column } from "../../../../../src/decorator/columns/Column"
@Entity({
name: "event",
})
export class Event {
@PrimaryGeneratedColumn()
id: number
@Column({ type: "date" })
localDate: Date
@Column({ type: "date", utc: true })
utcDate: Date
}

Some files were not shown because too many files have changed in this diff Show More